Accurate placement of gun in NPCs hand
Placing a rifle to sit in the hands of an NPC can be a bit of a fiddle so I thought I'd post the code.
The code relies on bones for accurate placement:-
Trigger bone
Gun Butt/Rest bone
Trigger hand
Butt hand
I place config stuff like this in an XML file for easy editting, to read the XML I use a nice library tinyXML.
Ignore the bullet code as this is a temp hack I will tidy later.
Hope this helps.
PS
Thanks to Pixel Perfect for supplying gun model etc for my testing, without him I'd be "assetless".
#include "gun/include/gun.h"
#include "gun/include/bullet.h"
#include "gamelib.h"
//#define DEBUG_GUN_POS
ActorGun::ActorGun( TScene *pScene, string pFile, TEntity par, TEntity spine, TEntity pTrig, TEntity pRest ):
m_fireRate(300), m_range(50)
{
m_lastFireTime = AppTime();
m_scene = pScene;
m_scene->framewerk.GetMain().SetWorld();
m_entity = LoadModel( (char *)pFile.c_str() );
m_spine = spine;
m_parent = par;
EntityType(m_entity, 5,1);
EntityParent( m_entity, m_parent);
m_handTrigger = pTrig;
m_handRest = pRest;
HookUpdateEvent(m_scene->updateEvent);
#ifdef DEBUG_GUN_POS
HookRenderEvent(m_scene->renderEvent);
#endif
}
bool ActorGun::withinRange( float pDist )
{
return (pDist <= m_range);
}
void ActorGun::Render( float gameLoopTime)
{
#ifdef DEBUG_GUN_POS
TVec3 trigPos = EntityPosition( m_handTrigger, 1);
TVec3 restPos = EntityPosition( m_handRest, 1);
TVec3 trigBonePos = EntityPosition( m_triggerBone, 1);
TVec3 restBonePos = EntityPosition( m_restBone, 1);
SetColor( Vec4(1,0,0,1) ); // red
tdDraw( m_scene->cam, trigPos, Vec3( trigPos.X, trigPos.Y + 0.1, trigPos.Z) );
SetColor( Vec4(0,0,1,1) ); // blue
tdDraw( m_scene->cam, restPos, Vec3( restPos.X, restPos.Y + 0.1, restPos.Z) );
SetColor( Vec4(0,1,0,1) ); // green
tdDraw( m_scene->cam, trigBonePos, Vec3( trigBonePos.X, trigBonePos.Y - 0.1, trigBonePos.Z) );
SetColor( Vec4(1,1,1,1) ); // white
tdDraw( m_scene->cam, restBonePos, Vec3( restBonePos.X, restBonePos.Y - 0.1, restBonePos.Z) );
TVec3 pos = EntityPosition(m_muzzelBone,1);
TVec3 pos1 = TFormVector( Vec3(0,0,-1), m_spine, NULL);
pos1.X += pos.X;
pos1.Y += pos.Y;
pos1.Z += pos.Z;
tdDraw( m_scene->cam, pos, pos1 );
#endif
}
// Position the gun in the actors hand
void ActorGun::Update(float gameLoopTime)
{
TVec3 trigPos;
TVec3 restPos = EntityPosition( m_handRest, 1);
TVec3 handPos = EntityPosition( m_handTrigger, 1);
float diffx = handPos.X - restPos.X;
float diffy = handPos.Y - restPos.Y;
float diffz = handPos.Z - restPos.Z;
AlignToVector( m_entity, Vec3(diffx,diffy,diffz),3 );
TVec3 pos = EntityPosition(m_entity,1);
trigPos = EntityPosition(m_triggerBone,1);
diffx = pos.X - trigPos.X;
diffy = pos.Y - trigPos.Y;
diffz = pos.Z - trigPos.Z;
trigPos = EntityPosition( m_handTrigger, 1);
trigPos.X += diffx;
trigPos.Y += diffy;
trigPos.Z += diffz;
PositionEntity(m_entity, trigPos, 1);
list<Bullet*>::iterator bulletList;
for(bulletList = m_bullets.begin(); bulletList != m_bullets.end(); )
{
	if ((*bulletList)->m_life == 0)
	{
		delete *bulletList;
		m_bullets.erase( bulletList++ );
	}
	else
		++bulletList;
}
}
bool ActorGun::fireGun()
{
if (AppTime() < m_lastFireTime ) return false;
m_lastFireTime = AppTime() + m_fireRate;
Bullet *bullet;
TVec3 pos;
pos = EntityPosition(m_muzzelBone,1);
//bullet = new Bullet( pos, TFormVector( Vec3(0,0,-1), m_muzzelBone, NULL), m_scene );
bullet = new Bullet( pos, TFormVector( Vec3(0,0,-1), m_spine, NULL), m_scene );
m_bullets.push_back( bullet );
return true;
}
TEntity gunPickSource;
int _stdcall gunFilter( TEntity entity ) 
{
if ( isParent(gunPickSource, entity) ) return 0;
return 1;
}
bool ActorGun::canHit( TEntity target, TVec3 tagetPos)
{
gunPickSource = m_entity;
TVec3 pos = EntityPosition(m_muzzelBone,1);
TPick pick;
if (LinePick( &pick, pos, tagetPos, 0, 0, (BP)gunFilter))
{
	if (isParent(target, pick.entity ))
		return true;
}
else
	return true;
return false;
}
// Read in gun information from an XML file
bool ActorGun::readGunFile( string pFile )
{
string filename;
string typeName;
string bone;
filename = AbstractPath( (str)pFile.c_str());
TiXmlDocument doc( filename.c_str() );
TiXmlElement* child = 0;
TiXmlElement *bones = 0;
doc.LoadFile( filename.c_str() );
bones = doc.FirstChildElement("bones");
if(bones)
{
	child = bones->FirstChildElement();
	while(child)
	{
		typeName = child->Attribute("type");
		if(typeName == "trigger")
		{
			m_triggerBone = FindChild( m_entity, (str)child->Attribute("name") );
			m_triggerPos = EntityPosition( m_triggerBone );
		}
		typeName = child->Attribute("type");
		if(typeName == "rest")
		{
			m_restBone = FindChild( m_entity, (str)child->Attribute("name") );
			m_restPos = EntityPosition( m_restBone );
		}
		if(typeName == "muzzel")
		{
			m_muzzelBone = FindChild( m_entity, (str)child->Attribute("name") );
		}
		child = child->NextSiblingElement();
	}
}
return true;
}
Include: -
#ifndef GUN_H
#define GUN_H
#include "tinyxml.h"
#include "gamelib/include/scene.h"
#include "event/include/gameEvent.h"
#include "gun/include/bullet.h"
#include <list>
class ActorGun : public GameObject
{
protected:
TScene *m_scene;
public:
TEntity m_parent;
TEntity m_entity;
TEntity m_actor;
TEntity m_handTrigger;
TEntity m_handRest;
TEntity m_triggerBone;
TEntity m_restBone;
TEntity m_muzzelBone;
TEntity m_spine;
TVec3 m_triggerPos;
TVec3 m_restPos;
list<Bullet*> m_bullets;
float m_fireRate;
float m_lastFireTime;
float m_range;
ActorGun( TScene *pScene,  std::string pFile, TEntity par, TEntity spine, TEntity pTrig, TEntity pRest  );
virtual void Update( float gameLoopTime);
virtual void Render( float gameLoopTime);
bool fireGun();
bool withinRange( float pDist );
bool canHit( TEntity target, TVec3 tagetPos);
bool readGunFile( std::string pFile );
};
#endif
 
		 
	
0 Comments
Recommended Comments
There are no comments to display.