Adding Collision to a projectile
by Dumbledore · in Torque Game Engine · 05/21/2008 (6:10 am) · 6 replies
Hello, I'm new but maybe you can help me!
Background:
My goal is to make projectiles selectable. The way a mouse click event is generated is a ray is cast where the mouse click occurs and if it hits an object it passes the object it hit along with the coordinates to script.
The problem I have is that because Projectiles use ray cast collision detection they do not generate a hit when a ray is cast through them.
To solve this I hope to implement collision detection that will generate a hit when a ray cast hits it.
My question:
Must I go through the trouble of creating a working collision set that gets updated in every Projectile::processTick? (Remember I just need a raycast to generate a hit when it collides with the projectile, therefore I do not need anything fancy)
If yes than: do I basically have to copy the Player collision code? What foreseeable shortcuts (if any) can I take? I'd like to circumvent doing more work than I have to while maintaining maximum efficiency.
Thanks in advance.
Background:
My goal is to make projectiles selectable. The way a mouse click event is generated is a ray is cast where the mouse click occurs and if it hits an object it passes the object it hit along with the coordinates to script.
The problem I have is that because Projectiles use ray cast collision detection they do not generate a hit when a ray is cast through them.
To solve this I hope to implement collision detection that will generate a hit when a ray cast hits it.
My question:
Must I go through the trouble of creating a working collision set that gets updated in every Projectile::processTick? (Remember I just need a raycast to generate a hit when it collides with the projectile, therefore I do not need anything fancy)
If yes than: do I basically have to copy the Player collision code? What foreseeable shortcuts (if any) can I take? I'd like to circumvent doing more work than I have to while maintaining maximum efficiency.
Thanks in advance.
#2
Thanks in advance.
05/21/2008 (7:49 am)
Thanks Scott. So you're saying all that I must do is add Projectile::castRay() and from then on when I do Container::castRay() and it hits the projectile it will register as a hit? I don't see how this will work. Could you perhaps tell me what code I should be looking at? Like where Projectile::castRay() gets called? Thanks in advance.
#3
SceneObject.cc
SceneObject.h
SceneObject.cc
#1. We are getting the next SceneObject in the current bin.
#2. We are calling castRay on this object.
#3. Because castRay is declared virtual in SceneObject, it will call Projectile::castRay() if Projectile::castRay() was defined.
#4. If it returns true than it will register a hit. (Basically, although there is more stuff going on here that I don't fully understand)
So I will test this and report back as soon as possible! Thanks again Scott.
05/21/2008 (8:25 am)
Okay it turns out you might be right Scott. I can't test it yet but it looks like what you say will work. I left comments at the relevant parts. SceneObject.cc
bool Container::castRay(const Point3F &start, const Point3F &end, U32 mask, RayInfo* info)
{
PROFILE_START(ContainerCastRay);
F32 currentT = 2.0;
smCurrSeqKey++;
SceneObjectRef* chain = mOverflowBin.nextInBin;
static RayInfo ri;
ri.material = 0;
while (chain)
{
SceneObject* ptr = chain->object; // #1
if (ptr->getContainerSeqKey() != smCurrSeqKey)
{
ptr->setContainerSeqKey(smCurrSeqKey);
// In the overflow bin, the world box is always going to intersect the line,
// so we can omit that test...
if ((ptr->getType() & mask) != 0 &&
ptr->isCollisionEnabled() == true)
{
Point3F xformedStart, xformedEnd;
ptr->mWorldToObj.mulP(start, &xformedStart);
ptr->mWorldToObj.mulP(end, &xformedEnd);
xformedStart.convolveInverse(ptr->mObjScale);
xformedEnd.convolveInverse(ptr->mObjScale);
if (ptr->castRay(xformedStart, xformedEnd, &ri)) // #2
{
if(ri.t < currentT)
{
*info = ri;
info->point.interpolate(start, end, info->t);
currentT = ri.t;
}
}
}
}
chain = chain->nextInBin;
}SceneObject.h
/// Casts a ray and obtain collision information, returns true if RayInfo is modified. /// /// @param start Start point of ray /// @param end End point of ray /// @param info Collision information obtained (out) virtual bool castRay(const Point3F &start, const Point3F &end, RayInfo* info); // #3
SceneObject.cc
if(currentT != 2) // #4
{
PlaneF fakePlane;
fakePlane.x = info->normal.x;
fakePlane.y = info->normal.y;
fakePlane.z = info->normal.z;
fakePlane.d = 0;
PlaneF result;
mTransformPlane(info->object->getTransform(), info->object->getScale(), fakePlane, &result);
info->normal = result;
PROFILE_END();
return true;
}#1. We are getting the next SceneObject in the current bin.
#2. We are calling castRay on this object.
#3. Because castRay is declared virtual in SceneObject, it will call Projectile::castRay() if Projectile::castRay() was defined.
#4. If it returns true than it will register a hit. (Basically, although there is more stuff going on here that I don't fully understand)
So I will test this and report back as soon as possible! Thanks again Scott.
#4
05/21/2008 (9:15 am)
I confirmed that this works. Thanks again to Scott Richards who saved me a lot of hassle!
#5
SceneObject.cc
SceneObject.h
SceneObject.cc
#1. We are getting the next SceneObject in the current bin.
#2. We are calling castRay on this object.
#3. Because castRay is declared virtual in SceneObject, it will call Projectile::castRay() if Projectile::castRay() was defined.
#4. If it returns true than it will register a hit. (Basically, although there is more stuff going on here that I don't fully understand)
So I will test this and report back as soon as possible! Thanks again Scott.
05/22/2008 (5:54 am)
Okay it turns out you might be right Scott. I can't test it yet but it looks like what you say will work. I left comments at the relevant parts. SceneObject.cc
bool Container::castRay(const Point3F &start, const Point3F &end, U32 mask, RayInfo* info)
{
PROFILE_START(ContainerCastRay);
F32 currentT = 2.0;
smCurrSeqKey++;
SceneObjectRef* chain = mOverflowBin.nextInBin;
static RayInfo ri;
ri.material = 0;
while (chain)
{
SceneObject* ptr = chain->object; // #1
if (ptr->getContainerSeqKey() != smCurrSeqKey)
{
ptr->setContainerSeqKey(smCurrSeqKey);
// In the overflow bin, the world box is always going to intersect the line,
// so we can omit that test...
if ((ptr->getType() & mask) != 0 &&
ptr->isCollisionEnabled() == true)
{
Point3F xformedStart, xformedEnd;
ptr->mWorldToObj.mulP(start, &xformedStart);
ptr->mWorldToObj.mulP(end, &xformedEnd);
xformedStart.convolveInverse(ptr->mObjScale);
xformedEnd.convolveInverse(ptr->mObjScale);
if (ptr->castRay(xformedStart, xformedEnd, &ri)) // #2
{
if(ri.t < currentT)
{
*info = ri;
info->point.interpolate(start, end, info->t);
currentT = ri.t;
}
}
}
}
chain = chain->nextInBin;
}SceneObject.h
/// Casts a ray and obtain collision information, returns true if RayInfo is modified. /// /// @param start Start point of ray /// @param end End point of ray /// @param info Collision information obtained (out) virtual bool castRay(const Point3F &start, const Point3F &end, RayInfo* info); // #3
SceneObject.cc
if(currentT != 2) // #4
{
PlaneF fakePlane;
fakePlane.x = info->normal.x;
fakePlane.y = info->normal.y;
fakePlane.z = info->normal.z;
fakePlane.d = 0;
PlaneF result;
mTransformPlane(info->object->getTransform(), info->object->getScale(), fakePlane, &result);
info->normal = result;
PROFILE_END();
return true;
}#1. We are getting the next SceneObject in the current bin.
#2. We are calling castRay on this object.
#3. Because castRay is declared virtual in SceneObject, it will call Projectile::castRay() if Projectile::castRay() was defined.
#4. If it returns true than it will register a hit. (Basically, although there is more stuff going on here that I don't fully understand)
So I will test this and report back as soon as possible! Thanks again Scott.
#6
SceneObject.cc
SceneObject.h
SceneObject.cc
#1. We are getting the next SceneObject in the current bin.
#2. We are calling castRay on this object.
#3. Because castRay is declared virtual in SceneObject, it will call Projectile::castRay() if Projectile::castRay() was defined.
#4. If it returns true than it will register a hit. (Basically, although there is more stuff going on here that I don't fully understand)
So I will test this and report back as soon as possible! Thanks again Scott.
05/22/2008 (5:56 am)
Okay it turns out you might be right Scott. I can't test it yet but it looks like what you say will work. I left comments at the relevant parts. SceneObject.cc
bool Container::castRay(const Point3F &start, const Point3F &end, U32 mask, RayInfo* info)
{
PROFILE_START(ContainerCastRay);
F32 currentT = 2.0;
smCurrSeqKey++;
SceneObjectRef* chain = mOverflowBin.nextInBin;
static RayInfo ri;
ri.material = 0;
while (chain)
{
SceneObject* ptr = chain->object; // #1
if (ptr->getContainerSeqKey() != smCurrSeqKey)
{
ptr->setContainerSeqKey(smCurrSeqKey);
// In the overflow bin, the world box is always going to intersect the line,
// so we can omit that test...
if ((ptr->getType() & mask) != 0 &&
ptr->isCollisionEnabled() == true)
{
Point3F xformedStart, xformedEnd;
ptr->mWorldToObj.mulP(start, &xformedStart);
ptr->mWorldToObj.mulP(end, &xformedEnd);
xformedStart.convolveInverse(ptr->mObjScale);
xformedEnd.convolveInverse(ptr->mObjScale);
if (ptr->castRay(xformedStart, xformedEnd, &ri)) // #2
{
if(ri.t < currentT)
{
*info = ri;
info->point.interpolate(start, end, info->t);
currentT = ri.t;
}
}
}
}
chain = chain->nextInBin;
}SceneObject.h
/// Casts a ray and obtain collision information, returns true if RayInfo is modified. /// /// @param start Start point of ray /// @param end End point of ray /// @param info Collision information obtained (out) virtual bool castRay(const Point3F &start, const Point3F &end, RayInfo* info); // #3
SceneObject.cc
if(currentT != 2) // #4
{
PlaneF fakePlane;
fakePlane.x = info->normal.x;
fakePlane.y = info->normal.y;
fakePlane.z = info->normal.z;
fakePlane.d = 0;
PlaneF result;
mTransformPlane(info->object->getTransform(), info->object->getScale(), fakePlane, &result);
info->normal = result;
PROFILE_END();
return true;
}#1. We are getting the next SceneObject in the current bin.
#2. We are calling castRay on this object.
#3. Because castRay is declared virtual in SceneObject, it will call Projectile::castRay() if Projectile::castRay() was defined.
#4. If it returns true than it will register a hit. (Basically, although there is more stuff going on here that I don't fully understand)
So I will test this and report back as soon as possible! Thanks again Scott.
Torque 3D Owner Scott Richards