Example Bullet Code, needs 1 last issue figured out
Posted: Fri Jul 20, 2007 3:34 pm
I thought I would share my projectile code with people and hopefully somebody will also have an idea why about 10-20% of the time bullets seem to be able to go through an enemy without a collision detected.
You will have to modify this depending on your model domain, as this uses all my game classes.
Just to sum up the logic:
Every frame the following happens for a bullet in the air:
First frame: calculate the distance to wall we will hit so we don't have to calculate collisions with the world scene node
All other frames:
take current position and create a line from there to next position given amount of time passed and flight speed
Do a ray cast check with custom ray cast code along that line(custom ray cast will be at the bottom)
If any collisions along the line, stop there and perform a hit
else move to the end of the line.
And here is the code (If you know how to make it preserve indentation please let me know)
Also every node has this happen once at the beginning
ITriangleSelector* selector=myGameSceneManager->createTriangleSelectorFromBoundingBox(sceneNode);
sceneNode->setTriangleSelector(selector);
You will have to modify this depending on your model domain, as this uses all my game classes.
Just to sum up the logic:
Every frame the following happens for a bullet in the air:
First frame: calculate the distance to wall we will hit so we don't have to calculate collisions with the world scene node
All other frames:
take current position and create a line from there to next position given amount of time passed and flight speed
Do a ray cast check with custom ray cast code along that line(custom ray cast will be at the bottom)
If any collisions along the line, stop there and perform a hit
else move to the end of the line.
And here is the code (If you know how to make it preserve indentation please let me know)
Code: Select all
void Projectile::passTime(f32 amount)
{
Object::passTime(amount);
if(firstTick)
{
firstTick=false;
line3df totalTravelLine;
totalTravelLine.start=getSceneNode()->getPosition();
totalTravelLine.end=direction*50000.0f;
wallDecal=myGameSceneManager->getSceneCollisionManager()->getCollisionPoint(totalTravelLine,game->world->getSceneNode()->getTriangleSelector(),expirePoint,expireTriangle);
if(wallDecal)
{
expireDistanceRemaining=expirePoint.getDistanceFrom(totalTravelLine.start);
}
else
{
printf("No wall hit.\n");// This should not happen
expireDistanceRemaining=2500000000.0f;
}
}
line3d<f32> line;
line.start=getSceneNode()->getPosition();
line.end = line.start + direction*speed*amount;
lines.push_back(line);//i track these just so i can draw the incramental trajectories for debugging only(this is how i see that the line passes right through a scene node)
expireDistanceRemaining-=line.getLength();
ISceneNode* selectedSceneNode=NULL;
f32 distanceSquared;
vector3df collisionPoint;
triangle3df collisionTriangle;
collisionCheck(myGameSceneManager->getRootSceneNode(),line,ProjectileSceneNodeFilter(thisProjectilePtr()),selectedSceneNode,collisionPoint,collisionTriangle,distanceSquared);
bool hit=false;
if(selectedSceneNode)
{
handleImpact(selectedSceneNode,collisionPoint,collisionTriangle,line);
destroy();
}
else if(expireDistanceRemaining<=0.0f)
{
if(wallDecal&&hasBulletHole)
{
shared_ptr<Decal> temp(new Decal());
temp->init(game->world->getSceneNode(),expireTriangle,expirePoint,bulletHoleTexture,2);
game->zone->addDecal(temp);
}
destroy();
}
else
{
getSceneNode()->setPosition(line.end);
}
}
and the collision function(this is a modifcation to the one in irrlicht
//! recursive method for going through all scene nodes and looking for the best triangle collision
void collisionCheck(ISceneNode* root,
const line3df& ray,SceneNodeFilter &filter,ISceneNode*& outBestNode,vector3df &outPoint,triangle3df &outTriangle,f32 &outDistanceSQ)
{
core::vector3df edges[8];
const core::list<ISceneNode*>& children = root->getChildren();
core::list<ISceneNode*>::Iterator it = children.begin();
for (; it != children.end(); ++it)
{
ISceneNode* current = *it;
if (filter.allowNode(current))
{
// get world to object space transform
core::matrix4 mat;
if (!current->getAbsoluteTransformation().getInverse(mat))
{
continue;
}
// transform vector from world space to object space
core::line3df line(ray);
mat.transformVect(line.start);
mat.transformVect(line.end);
const core::aabbox3df& box = current->getBoundingBox();
// do triangle intersection test in object space
if (box.intersectsWithLine(line))
{
vector3df point;
triangle3df triangle;
bool hit=myGameSceneManager->getSceneCollisionManager()->getCollisionPoint(ray,current->getTriangleSelector(),point,triangle);
if(hit)
{
float newDistance=point.getDistanceFromSQ(line.end);
if(!outBestNode||newDistance<outDistanceSQ)
{
outBestNode = current;
outDistanceSQ=newDistance;
outPoint=point;
outTriangle=triangle;
}
}
}
}
collisionCheck(current, ray, filter,outBestNode,outPoint,outTriangle,outDistanceSQ);
}
}
ITriangleSelector* selector=myGameSceneManager->createTriangleSelectorFromBoundingBox(sceneNode);
sceneNode->setTriangleSelector(selector);