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);