Hey guys, I have projectile weapons mostly figured out in my space sim game, so I moved onto "beam weapons" (think Star Trek phasers). I use Ogre as my rendering engine and Bullet for physics (collision only)
Here is a video of the graphical component: http://www.youtube.com/watch?v=O4Jjaf1caVQ to give you an idea of what I'm talking about.
What I want to accomplish:
I want a beam weapon to originate from the firing ship and upon contact with the nearest ship not continue further (not go through nearest ship and potentially damage next ship in line).
I want it to be fairly efficient since I'm hoping for quite a lot of these occurances, plus lots of projectiles, missles, other ships at the same time.
Here are some potential methods of doing this that I've been thinking of:
Method 1: Using Bullet to test for collisions create a physical representation of the full beam (rectangle with the beam's dimensions) if more than one object is hit, find the nearest object then shorten the graphical component of the beam and only do damage to the nearest hit ship.
Performance issues: This would mean that I'm storing what the beam hit then going through the list, which to me seems like a fairly short list).
Method 2: while displaying a graphical representation of a "beam" - physics engine wise shoot a projectile to test for nearest hit (as I do with other projectiles except making these "beam" projectiles move much much faster and re-fire much much faster than current weapons, game wise they would have to be near instananeous in speed).
Performance issues: This would mean that I'm constantly adding and removing bodies from the physics engine.
Method 3: Create a physical representation of the beam, start it off small then scale it if it isn't colliding with another object or until it reaches its full range, if it collides do damage and stop the scaling until it is not colliding. (although I haven't tried this yet, it looks like Bullet has this: boxShape->setLocalScaling(Vector3) which could accomplish this)
Performance issues: This would mean I'm scaling the boxShape potentially often.
Method 4: either use Bullet ray queries or Ogre ray scene queries to find the nearest object, do the appropriate damage, then scale the graphical representation of the beam based on the distance returned.
Performance issues: this would mean i'm sending ray scene queries often, if I use Ogre ray scene query I would hit the AAB unless I use the method MOC (collision to the triangle level) which would mean lowered performance.
Hopefuly I can get someideas or pointers to a good method from the list above or from stuff you can come up with.
thanks
"Beam" weapons - methods of detecting hits - advice sought
-
chaosavy
- Posts: 29
- Joined: Wed Nov 11, 2009 9:09 pm
-
dphil
- Posts: 237
- Joined: Tue Jun 29, 2010 10:27 pm
Re: "Beam" weapons - methods of detecting hits - advice soug
I haven't ever done the sort of thing you are trying, nor have I worked with raycasting at all (though I am familiar with how it works). That said, my 2 cents...
Methods 1 and 4 seem preferable to me. 2 and 3 feel a bit awkward, and seem like they would basically do what raycasting does, but less efficiently. Personally, I'd try out method 4. Do a ray cast and use a callback to grab the nearest hit (sample code I came across here). This may be sufficient enough for your needs, but I know what you mean about constant raycasts (though you could optimize in some way, such as only re-casting only every i simulation steps). Which is why I also included method 1. Using a persistent collision object (long rectangle or cylinder) for the beam might(?) be more efficient than constant raycasting, since I believe bullet does some optimizations so it doesn't even need to recheck all collisions at every frame anyway, and in a space sim, you're right, you'd likely have very few collisions along any given beam path anyway (especially if the beam has a reasonably limited range). And having all objects on the beam path stored could be handy for some purposes too, for example if you wanted the beam to be able to punch through an object and continue to the next one along its path (though raycasting could accomplish this too).
On a side note, Star Trek-style ship-based beam weapons tend to be targeted (get within range, get signal lock, fire) to specific enemy vessels/objects (rather than straight, dumb-fire), which of course would simplify things too
.
Methods 1 and 4 seem preferable to me. 2 and 3 feel a bit awkward, and seem like they would basically do what raycasting does, but less efficiently. Personally, I'd try out method 4. Do a ray cast and use a callback to grab the nearest hit (sample code I came across here). This may be sufficient enough for your needs, but I know what you mean about constant raycasts (though you could optimize in some way, such as only re-casting only every i simulation steps). Which is why I also included method 1. Using a persistent collision object (long rectangle or cylinder) for the beam might(?) be more efficient than constant raycasting, since I believe bullet does some optimizations so it doesn't even need to recheck all collisions at every frame anyway, and in a space sim, you're right, you'd likely have very few collisions along any given beam path anyway (especially if the beam has a reasonably limited range). And having all objects on the beam path stored could be handy for some purposes too, for example if you wanted the beam to be able to punch through an object and continue to the next one along its path (though raycasting could accomplish this too).
On a side note, Star Trek-style ship-based beam weapons tend to be targeted (get within range, get signal lock, fire) to specific enemy vessels/objects (rather than straight, dumb-fire), which of course would simplify things too
-
sparkprime
- Posts: 508
- Joined: Fri May 30, 2008 2:51 am
- Location: Ossining, New York
Re: "Beam" weapons - methods of detecting hits - advice soug
Casting rays in bullet would fit this need perfectly. You can easily filter out the nearest one or use the library function that does it for you. Ogre's ray casting only works for bounding box, unless you iterate through the triangles which is slow (bullet uses the bvh for that), and may involve duplicating triangle data on host and gpu.
-
chaosavy
- Posts: 29
- Joined: Wed Nov 11, 2009 9:09 pm
Re: "Beam" weapons - methods of detecting hits - advice soug
Thank you for the suggestions, I indeed went with Bullet rays and so far so good. Because I'd rather not send the ray every frame I put it into the timer that's already in place to "ossilate" the beam (scale it up and down).
Here is the code if anyone is interested (has Ogre code in it there):
Here is the code if anyone is interested (has Ogre code in it there):
Code: Select all
float beamRange=range;
Ogre::Vector3 fromPos = beamNode->_getDerivedPosition();
Ogre::Vector3 toPos = parentSceneNode->_getDerivedOrientation()*Ogre::Vector3(0,0,-beamRange);
toPos = toPos + fromPos;
btVector3 btFromPos = BtOgre::Convert::toBullet(fromPos);
btVector3 btToPos = BtOgre::Convert::toBullet(toPos);
btCollisionWorld::ClosestRayResultCallback ray(btFromPos, btToPos);
worldFactory->mPhysics->collisionWorld->rayTest(btFromPos, btToPos, ray);
if(ray.hasHit())
{
btCollisionObject* pColObject=ray.m_collisionObject;
Ogre::Entity *entityHit=static_cast<Ogre::Entity*>(pColObject->getUserPointer());
int hitType = Common::getType(worldFactory->mSceneMgr, entityHit->getName());
Station* stationHit=NULL;
Ship* shipHit=NULL;
float distance=0;
switch(hitType)
{
case 0: //Sun
//Future???
break;
case 1: //Planet
//Future???
break;
case 2: //Station
determineBeamDistance(&beamRange, fromPos, BtOgre::Convert::toOgre(ray.m_hitPointWorld));
break;
case 5: //Ship
determineBeamDistance(&beamRange, fromPos, BtOgre::Convert::toOgre(ray.m_hitPointWorld));
shipHit =Common::getShipPtr(worldFactory->mSceneMgr, entityHit->getName());
shipHit->beamDamage(this, damage*(mTimeSinceLastFrame+scaleTimer));
break;
case 10: //Projectile
//Future???
break;
}
}