Absolute beginners guide to setattachment

Discuss programming in the QuakeC language.
Post Reply
OneManClan
Posts: 247
Joined: Sat Feb 28, 2009 2:38 pm
Contact:

Absolute beginners guide to setattachment

Post by OneManClan »

Absolute beginners guide to setattachment

NOTE: Afaik, setattachment is only compatible with FTE and DP

PREFACE
There's already a very helpful page on the Quake Wiki, which pretty much covers all you need to know about setattachment, but for those who need more, here's my unapologetically handholding guide, for absolute beginners, and of course, for a future me who doesn't remember exactly how I got this working.

INTRODUCTION
Setattachment is a (ssqc) way to connect multiple models together so that they can appear as 'one model' but each body part can be controlled seperately. For this 'step by step' walkthrough we will make a model consisting of 3 parts: 'RobotLegs', 'RobotTorso', and 'Robothead'. Each body part will have its own thinks, but 'RobotTorso' and 'Robothead' will be 'child' entities, permanently connected to 'RobotLegs', the 'parent' entity.


PREPARING THE MODEL
1. In Blender, make a (crappy boxy test) model with 3 bodyparts, RobotLegs, RobotTorso, and Robothead. Keep the three as seperate objects (ie don't join them).

2. Make an armature, 3 bones "legs", "torso", and "head", and connect each bone to its respective mesh. [TIP: If it's a robot, check the weights (weight paint) to make sure that rotating one part has 0 influece on the adjoining part.]

3. Save the Blender file.

4. Export each body part with it's bone as a seperate iqm (using Salzmans iqm exporter). Note: This example doesn't need animations (leave the 'animations' field blank) TIP: Remember to scale the model up on Export (I've been using 8 with great results), otherwise you might have trouble seeing it in-game.

THE QUAKE C

Code: Select all

// declare the body parts
#define ROBOT_LEGS "progs/robot_legs.iqm"
#define ROBOT_TORSO "progs/robot_torso.iqm"
#define ROBOT_HEAD "progs/robot_head.iqm"

Code: Select all

// precache them
precache_model(ROBOT_LEGS);
precache_model(ROBOT_TORSO);
precache_model(ROBOT_HEAD );
Note: I'm not sure if we should attach each part to 'the part it directly connects to' (ie other children), or to the parent?

Code: Select all

// The spawning
//spawn the parent entity (the one the others will attach to)
entity robot_legs= spawn();
		setmodel (robot_legs, ROBOT_LEGS);
		setorigin(robot_legs, where_you_want_it_to_spawn); 
		robot_legs.think = robot_legs_think;
		robot_legs.nextthink = time + 1;
		
		
		
// spawn child entity 1: robot_torso
entity robot_torso= spawn();
setmodel (robot_torso, ROBOT_TORSO);
// attach entity 'robot_torso' to entity 'robot_legs', using the robot_torso bone/tag called 'torso'
		setattachment (robot_torso, robot_legs, "torso");
		robot_torso.think = robot_torso_think;
		robot_torso.nextthink = time + 1;
		
// spawn the child entity 2: robot_head
		entity robot_head = spawn();
		setmodel (robot_head, ROBOT_HEAD);
// attach entity 'robot_head' to entity 'robot_torso', using the bone/tag called 'head'
		setattachment (robot_head, robot_torso, "head"); // Q: should it attach to Robotlegs/the parent??
		robot_head.think = robot_head_think;
robot_head.nextthink = time + 1;
		
6. Each bodypart now has its' own ai (robot_legs_think, robot_torso_think, and robot_head_think).

7. When a child becomes 'setattached', it's origin becomes '0 0 0', and the parent becomes the childs .tag_entity. To get the parents origin, you can go:

Code: Select all

vector parent_origin = child.tag_entity.origin;
However we need the *childs* origin, and the way to do that is to use gettaginfo, as described below:

Code: Select all

// the parent
void() robot_legs_think=
{
// code for the Robotlegs
// origin is self.origin

}

// child
void() robot_torso_think=
{
// code for the robot_torso
// Note: self.origin is '0 0 0'

// To get robot_torso's origin:
float robot_torso_bone_number = gettagindex(self, "torso");
vector robot_torso_origin = gettaginfo(self, robot_torso_bone_number);
	
}
Last edited by OneManClan on Thu Sep 05, 2019 3:05 am, edited 13 times in total.
OneManClan
Posts: 247
Joined: Sat Feb 28, 2009 2:38 pm
Contact:

Re: Help: Absolute beginners guide to setattachment (draft!)

Post by OneManClan »

Ok I found the solution to how to get the childs origin here, so I edited my original post(got rid of the 'draft' disclaimer, and think this (early and basic) version is ready to go!

One thing .. (from the link above)
jjsullivan5196 wrote:Remember, setattachment(); will set origin, size, and angles in relation to the bone the entity was attached to. So where that bone goes, the attached entity goes. So setting origin isn't absolute in world space when we're talking about the attached entity. If torso.origin is '0 0 12' that means the torso will be moved 12 units up from the bone that attaches it to the legs. So if you use gettaginfo(); to find the origin of the attachment point, say ' 22 5 50' then the torso will be at '22 5 62' ('0 0 12' + '22 5 50').
In my tests, (seem to) get the child's origin without needing to add it to the parents origin, ie this worked:

Code: Select all

// self is the child
float child_bone_number = gettagindex(self, "child_bone_name");
	vector child_location = gettaginfo(self, child_bone_number );
In fact, when I did add the parents origin ie:

Code: Select all

vector child_location = self.tag_entity.origin + gettaginfo(self, child_bone_number );
The offset way 'way out'.
Post Reply