Jump to content
  • entries
    10
  • comments
    21
  • views
    22,188

Accurate placement of gun in NPCs hand


Chris Paulson

1,741 views

 Share

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

 Share

0 Comments


Recommended Comments

There are no comments to display.

Guest
Add a comment...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...