Raycast
by Tim Heldna · in Torque Game Engine · 02/02/2007 (5:03 pm) · 12 replies
Hi all,
Anyone know if there's a debug mode which will display any rays that you are casting?
Also, I'm trying to implement a flash grenade and would like it if the player was only affected by the explosion if they were facing it. I thought I could do this with rays but am having some trouble.
Is there a cmd / function that will tell you if a given object (item) is on screen?
Thanks for any help.
Anyone know if there's a debug mode which will display any rays that you are casting?
Also, I'm trying to implement a flash grenade and would like it if the player was only affected by the explosion if they were facing it. I thought I could do this with rays but am having some trouble.
Is there a cmd / function that will tell you if a given object (item) is on screen?
Thanks for any help.
#2
02/02/2007 (5:16 pm)
Ahh perfect, thank you very much Orion!
#3
*When casting a ray from point A to point B the first object the array collided with on its way to point B will be returned. So if anything is obstructing a players view from the flash bang, that will be returned from the ray cast.
darn you Orion Elenzil you beat me to the post!
02/02/2007 (5:17 pm)
I do not know if you can display rays you are casting, but I have worked with them and can share my experience with you. Here is how I would handle the situation. I have tested similiar things in working with some AI.//How far the flash gernade can effect players.
%flashRange = 100;
//Find all players in a given radius.
%type = $TypeMasks::PlayerObjectType;
%playerObj = ContainerFindFirst(%type, %this.getTransform(), %flashRange ,
%this.viewDist, %this.viewDist);
//Now we loop through all the player objects found in the radius.
while(%playerObj)
{
//These are all of the things that can obstruct the view of the Player.
%type = $TypeMasks::PlayerObjectType | $TypeMasks::InteriorObjectType |
$TypeMasks::TerrainObjectType | $TypeMasks::StaticShapeObjectType |
$TypeMasks::VehicleObjectType;
%rayedObject = ContainerRayCast(%this.getEyeTransform(),
%playerObj.getEyeTransform(), %type, %this);
if(%rayedObject == %playerObj)
{
//Perform an effect on the player to simulate flash
%playerObj.doFlashEffect();
}
}*When casting a ray from point A to point B the first object the array collided with on its way to point B will be returned. So if anything is obstructing a players view from the flash bang, that will be returned from the ray cast.
darn you Orion Elenzil you beat me to the post!
#4
02/02/2007 (6:33 pm)
Your code will come in handy to me, too, Joshua. Thanks for posting it. :)
#5
you might want to combine Joshua's code with the dot-product thing:
Joshua's gets you whether or not there was an obstruction between the player and the explosion,
and the dot-product gets you whether or not they were facing it.
seems like it'd be nice if you didn't get blown to smithereens by a grenade that goes off on the other side of a big steel wall..
02/02/2007 (6:53 pm)
In thinking about it,you might want to combine Joshua's code with the dot-product thing:
Joshua's gets you whether or not there was an obstruction between the player and the explosion,
and the dot-product gets you whether or not they were facing it.
seems like it'd be nice if you didn't get blown to smithereens by a grenade that goes off on the other side of a big steel wall..
#6
Thanks. I haven't tried your code yet though I'm sure it will come in handy.
@ Orion
I've tried putting your code into practice with no luck. Can anyone help a mathematically challenged guy?
Here's what I did (my code is at the bottom of the function):
Back to the drawing board, any help always appreciated.
02/02/2007 (8:01 pm)
@ JoshThanks. I haven't tried your code yet though I'm sure it will come in handy.
@ Orion
I've tried putting your code into practice with no luck. Can anyone help a mathematically challenged guy?
Here's what I did (my code is at the bottom of the function):
function radiusDamage(%sourceObject, %position, %radius, %damage, %damageType, %impulse)
{
// Use the container system to iterate through all the objects
// within our explosion radius. We'll apply damage to all ShapeBase
// objects.
InitContainerRadiusSearch(%position, %radius, $TypeMasks::ShapeBaseObjectType);
%halfRadius = %radius / 2;
while ((%targetObject = containerSearchNext()) != 0)
{
// Calculate how much exposure the current object has to
// the explosive force. The object types listed are objects
// that will block an explosion. If the object is totally blocked,
// then no damage is applied.
%coverage = calcExplosionCoverage(%position, %targetObject,
$TypeMasks::InteriorObjectType | $TypeMasks::TerrainObjectType |
$TypeMasks::ForceFieldObjectType | $TypeMasks::VehicleObjectType);
if (%coverage == 0)
continue;
// Radius distance subtracts out the length of smallest bounding
// box axis to return an appriximate distance to the edge of the
// object's bounds, as opposed to the distance to it's center.
%dist = containerSearchCurrRadiusDist();
// Calculate a distance scale for the damage and the impulse.
// Full damage is applied to anything less than half the radius away,
// linear scale from there.
%distScale = (%dist < %halfRadius)? 1.0:
1.0 - ((%dist - %halfRadius) / %halfRadius);
// Apply the damage
%targetObject.damage(%sourceObject, %position,
%damage * %coverage * %distScale, %damageType);
// Apply the impulse
if (%impulse)
{
%impulseVec = VectorSub(%targetObject.getWorldBoxCenter(), %position);
%impulseVec = VectorNormalize(%impulseVec);
%impulseVec = VectorScale(%impulseVec, %impulse * %distScale);
%targetObject.applyImpulse(%position, %impulseVec);
}
// Apply a flash effect to player if item doing damage is a flash grenade
if (%damageType $= "flash grenade")
{
if (%targetObject.getClassname() $= "player")
{
%posPlayer = %targetObject.getPosition();
%posBoom = %position;
%vecPlayer = getWord(%targetObject.getTransform(), 2);
%vecPlayerBoom = VectorSub(%posBoom, %posPlayer); // vector from the player to the explosion
%dist = VectorLen(%vecPlayerBoom); // you don't really need this, but it's a handy artifact
%vecPlayerBoomN = VectorNormalize(%vecPlayerBoom); // normalize!
%dot = VectorDot(%vecPlayer, %vecPlayerBoomN);
echo("dot = " @ %dot);
// Do flash effect here pending upon value of %dot
}
}
}
} Back to the drawing board, any help always appreciated.
#7
the problem is this line:
and unfortunately i'm not sure of a good solution.
the difficulty is getting the direction the player is facing.
in the engine code, this is relatively easy - it's getTransform().getColumn(1, &vec),
but the thing is that in the engine, getTransform() returns a full matrix - 16 values -
while in script it's just position and a quaternion - 3 + 4 values.
what you could do is write a console function on um ShapeBase along these lines:
.. with that in, your code would then use:
%vecPlayer = %targetObject.getYAxis();
- also i realized a mistake i made in my original post -
the local Y axis is getColumn(1, &vec), not getColumn(2).
i hope that helps.
these things often take a bit of debugging;
i recommend printing the value of all the vectors etc involved at each step to make sure they're what you expect.
good luck!
ooo
02/02/2007 (8:14 pm)
Hey Tim -the problem is this line:
%vecPlayer = getWord(%targetObject.getTransform(), 2);
and unfortunately i'm not sure of a good solution.
the difficulty is getting the direction the player is facing.
in the engine code, this is relatively easy - it's getTransform().getColumn(1, &vec),
but the thing is that in the engine, getTransform() returns a full matrix - 16 values -
while in script it's just position and a quaternion - 3 + 4 values.
what you could do is write a console function on um ShapeBase along these lines:
ConsoleMethod( ShapeBase, getYAxis, const char*, 2, 2, "")
{
VectorF axis;
object->getTransform().getColumn(1, &axis);
char* ret = Con::getReturnBuffer(3 * 16); // enough room for 3 floats as characters
dSprintf(ret, 3 * 16, "%g %g %g", axis.x, axis.y, axis.z);
return ret;
}.. with that in, your code would then use:
%vecPlayer = %targetObject.getYAxis();
- also i realized a mistake i made in my original post -
the local Y axis is getColumn(1, &vec), not getColumn(2).
i hope that helps.
these things often take a bit of debugging;
i recommend printing the value of all the vectors etc involved at each step to make sure they're what you expect.
good luck!
ooo
#8
I have something that works now.
Still needs some tweaking but god damn it at least it works!
For any lurkers, here's how I get the player direction (still a work in progress)
02/02/2007 (8:49 pm)
Thanks Orion,I have something that works now.
Still needs some tweaking but god damn it at least it works!
For any lurkers, here's how I get the player direction (still a work in progress)
%vecPlayer = MatrixMulVector("0 0 0 " @ getWords(%targetObject.getTransform(), 3, 6), "0 1 0");
%vecPlayer = VectorNormalize(%vecPlayer);
#10
The flash effect is only applied if you are facing the explosion and the explosion is blocked by the usual objects (interiors, static shapes, vehicles etc).
Coupled with my flash screen effect & an appropraite sound it all comes together nicely.
I couldn't be happier with the results & couldn't have done it without your help, thank you very much.
02/02/2007 (9:12 pm)
Yep, just spent the past few minutes testing it and it works very well. The flash effect is only applied if you are facing the explosion and the explosion is blocked by the usual objects (interiors, static shapes, vehicles etc).
Coupled with my flash screen effect & an appropraite sound it all comes together nicely.
I couldn't be happier with the results & couldn't have done it without your help, thank you very much.
#11
Here is some of the modified code I used to determine whether a Player is in an AIPlayer's FOV:
Now you can use the angle to determine if the grenade is in the players FOV. The default FOV is 90 degrees. However, you need the angle returned from the above code to be half that (45 degrees on each side of the eye vector). The angle returned from my code will be in radians: 3.14/4 radians are 45 degrees.
02/03/2007 (5:54 am)
I know it is a bit late, again, but to get the direction the player is facing all you have to do is call this method:%eyeVector = %player.getEyeVector();
Here is some of the modified code I used to determine whether a Player is in an AIPlayer's FOV:
//Get the vector from a Player to the grenade and normalize it. %playerVec = VectorSub(%gernade.getTransform(), %player.getEyeTransform()); %playerVec = VectorNormalize(%playerVec); //Obtain the angle between the 2 vectors. angle = acos(v1*v2) %angle = mAcos(VectorDot(%this.getEyeVector(), %playerVec));
Now you can use the angle to determine if the grenade is in the players FOV. The default FOV is 90 degrees. However, you need the angle returned from the above code to be half that (45 degrees on each side of the eye vector). The angle returned from my code will be in radians: 3.14/4 radians are 45 degrees.
#12
It's never too late to post useful information.
RE my original problem with obtaining the player direction, the answer was in front of me the whole time.
My function is a little more graceful now and looks something like this:
RE the code you posted earlier, I actually use something similar for proximity mines & a warning HUD that pops up when certain items are in range, as well as a few other things.
Anyhow, thanks for all the help... hopefully this thread will also help others who may stumble across it.
02/04/2007 (2:21 am)
Hi Josh,It's never too late to post useful information.
RE my original problem with obtaining the player direction, the answer was in front of me the whole time.
%player.getForwardVector();
My function is a little more graceful now and looks something like this:
%posPlayer = %player.getPosition(); // player position %posExplosion = %position; // explosion position %vecPlayer = %player.getForwardVector(); // direction player is facing %vecExplosion = VectorSub(%posExplosion, %posPlayer); // vector from the player to the explosion %vecExplosion = VectorNormalize(%vecExplosion); // normalize! %dot = VectorDot(%vecPlayer, %vecExplosion); // dot will be: // 1.0 if the player is exactly facing the explosion, // 0.0 if the player is at ninety degrees to the explosion, //-1.0 if the player is exactly facing away from the explosion // ... and corresponding values in between.
RE the code you posted earlier, I actually use something similar for proximity mines & a warning HUD that pops up when certain items are in range, as well as a few other things.
Anyhow, thanks for all the help... hopefully this thread will also help others who may stumble across it.
Associate Orion Elenzil
Real Life Plus
in pseudo-code:
posPlayer = the position of the player; posBoom = the position of the explosion; vecPlayer = the direction the player is facing. aka their local Y axis; (in engine, that would be player.getTransform().getColumn(1, &vecPlayer);) vecPlayerBoom = posBoom - posPlayer; // vector from the player to the explosion dist = vecPlayerBoom.length(); // you don't really need this, but it's a handy artifact vecPlayerBoomN = vecPlayerBoom * (1.0 / dist); // normalize! dot = vecPlayer.DOT(vecPlayerBoomN); ta da, dot will be: 1.0 if the player is exactly facing the explosion, 0.0 if the player is at ninety degreed to the explosion, -1.0 if the player is exactly facing away from the explosion .. and corresponding values in between.edit: original getColumn() call was wrong.