Game Development Community

Hit position on target

by Arkadiusz Dymek · in Torque Game Engine · 04/10/2005 (3:14 pm) · 19 replies

Hi,

I'd like to know exact hit position on target. For this question let's assume it's a flat wall with several painted squares (it's a bit more complicated in reality, but squares will make it easier to explain). Of course I can use %position of hit point and %position of the target and after some transformations I should get relative hit position which should allow me to tell where has the target been hit. Knowing hit position and square corner positions I should be able to tell which square has been hit. Now the question is - how to get square corner coordinates? I can shoot at them and write down the coords, but it seems like a bit troublesome and not too accurate method. There has to be some easier and quicker way - could I use ie ShowTool to read coords? I've been playing with it for while but I don't see such possibility. Any other ideas? Or maybe there's even simpler way than just calculating hit position already provided by the engine?

cheers,
Arkadesh

#1
04/10/2005 (4:06 pm)
Arkadesh,

You should look at Player::getDamageLocation in the engine and where it is called in the script. Of course it is only for the player, you will have to figure out how to apply it to other objects, but it will get you started.

Thanks.
#2
04/10/2005 (6:41 pm)
Thanks for help, but I'm not sure if that's what I look for. Basically what I need is a quick and easy way to map points on texture to torque coordinates. Above resource seems to deal with the part what to do after I know where the zones are and what's the hit point. And I don't know how to get areas coords :( I just have them painted on the texture and that's all.

cheers,
Arkadesh
#3
04/10/2005 (7:07 pm)
Why do you need per pixel collision (which is basically what it sounds like you are saying)--is this on a 3-D model, or gui's? Especially if its a .dts model, that's some pretty hefty transformation stuff...
#4
04/10/2005 (7:42 pm)
I don't know if this will help your situation, but this is what I'm doing for a board game:

I have a board placed flat in my world at a known location (for example, at <0,0,0>). If the user clicks his/her mouse and it intersects this object, I can get the position in the world where the mouse click hit the board. I then use my knowledge of the board's geometry to calculate where the hit was. (For example, I may know that the board goes from <0,0,0> to <5,5,0> and is gridded into 8x8 squares. I can then do some simple math to determine which square was hit.

Of course, this doesn't help at all if you need to know where on a specific texture you hit. If you need this, it sounds like some incredibly painful work will be needed.
#5
04/10/2005 (11:43 pm)
Yes, your approach is what I'm doing now. I'm just looking now for quick way to lookup my geometry points. Ie some way to tell in ShowTool what are coords of clicked point. Now I'm shooting at those points (square corners in my example) and writing down their coords, but that is painful and slow...

cheers,
Arkadesh
#6
04/11/2005 (5:07 am)
I'm not sure if you realize this, but once the model makes it into the engine (you are currently only mentioning ShowTool), all bets are off--the model may be translated, rotated, or otherwise transformed, and you'll need to handle the mathematical modifications to handle that transform change in your mapping of the point that was clicked.

This is why most use the stock getDamageLocation() technique, because it handles all the transform manipulations in 3-Space for you.
#7
04/11/2005 (5:17 am)
Yeah.. I know about the transforms required. I keepi telling about ShowTool (or some equivalent) cause I need to get untransformed coords first somehow.
Btw what do you mean by getDamageLocation technique? How should the dts model be prepared so I can use it. Named boxes for each zone? Any resource for the modeller? I'd like to know what should I request from the artist :)

cheers,
Arkadesh
#8
04/11/2005 (5:34 am)
Long story short, the Damage Location functionality lets the code determine which -part- of a model is hit, and returns the appropriate identifier for that portion of the model.

Honestly, I've not used the code much (or even looked at it), but my first guess is that it allows you to identify certain portions of the model by name, and returns that name to the code--in other words, pretty much exactly what you want to do (as Derk originally suggested).

My suggestion would be to take a good look at that portion of the code, find out exactly how it works, and then adapt it to what you need. It's probably pretty close!
#9
04/11/2005 (5:43 am)
I am guessing it returns the name of the collision mesh that it collided with. I think you can only have 10 collision meshes on any one model. So you can make your model with one collision mesh for it's head, one for the chest, two for each arm and leg.... Then when you call getDamageLocation(...) it returns that name and you can do what you like with the info.
#10
04/11/2005 (6:04 am)
Chris,

Actually, it allows you to define areas on a single collision mesh. I have broken the player box into 16 different areas.

Thanks.
#11
04/11/2005 (6:53 am)
Defining areas on collision mesh? Fits my needs then. Can you tell how this defining should be done on the artwork side? Ie should the artist write down some stuff from max or is it done some other way?

cheers,
Arkadesh
#12
04/11/2005 (6:54 am)
Well, if you can model 10 different collision meshes to a single dts and 16 areas to a collision mesh... then you should be able to make 160 areas? Or were your 16 including the 10 different collision meshes?
#13
04/11/2005 (7:15 am)
Dymek,

I have heavily modified the existing code, but the basics are in your system. Do not use this code as is, it won't work. It is for example only of how you can expand what is already in the engine.

Scripting /server/scripts/player.cs
datablock PlayerData(Mech)
{
...
   boundingBox = "2.4 2.9 4";

   boxTorsoBottom      = 2.75;  // Bottom of Torso box
   boxArmBottom        = 3.125; // Bottom of Arm box
   boxArmTop           = 4.0;   // Top of Arm box
   boxArmWidth         = 0.4;   // Width of Arm box
   boxTorsoWidth       = 0.6;   // Width of Side Torso
   boxHeadBottom       = 3.0;   // Bottom of Head box
   boxHeadTop          = 3.25;  // Top of Head box
   boxHeadLeft         = 0.4;   // Left Side of Head box
   boxHeadRight        = -0.4;  // Right Side of Head box
   boxRear             = -0.5;  // Rear of entire box
...
}
...
function Armor::damage(%this, %obj, %sourceObject, %position, %damage, %damageType)
{
...
   // Find hit location
   %location = %obj.getDamageLocation(%position);
...
}
Engine /engine/game/player.cc
void Player::getDamageLocation(const Point3F& in_rPos, const char *&out_loc)
{
   Point3F newPoint;
   mWorldToObj.mulP(in_rPos, &newPoint);

   F32 boxX = mDataBlock->boxSize.x / 2;

   if (mDataBlock->sidestep) {
     if (newPoint.z <= mDataBlock->boxTorsoBottom) {
       // Hit Legs
       if (newPoint.x <= 0.0f) 
	     if (newPoint.y <= mDataBlock->boxRear)
		   out_loc = "LLF";
	     else
		   out_loc = "LAF";
       else 
	     if (newPoint.y <= mDataBlock->boxRear)
		   out_loc = "RLF";
	     else
		   out_loc = "RAF";
	 } else {
	   // Torso Hit
       // Torso twisting coversion
       if (mDataBlock->twist) {
	     // Get hit angle
         F32 angle = mAtan( newPoint.x, newPoint.y );
	     // Get current rotation
	     Point3F headRotation = getHeadRotation();
	     // Subtract twist from angle (to move in opposite direction)
	     angle -= headRotation.z;
	     // Convert angle to -PI to PI
	     if(angle > M_PI )
           angle -= M_2PI;
         else if(angle < -M_PI )
           angle += M_2PI;
	     // Get distance ratio
	     F32 ratio = mTan(angle);
         // Calculate new location based on quadrant
	     if ((angle >= -M_PI/4) && (angle <= M_PI/4)) {
		   newPoint.y = mDataBlock->boxSize.y / 2;
		   newPoint.x = newPoint.y * ratio;
		 }
	     if ((angle > M_PI/4) && (angle < M_PI*0.75)) {
		   newPoint.x = mDataBlock->boxSize.x / 2;
		   newPoint.y = newPoint.x / ratio;
		 }
	     if ((angle <= -M_PI*0.75) || (angle >= M_PI*0.75)) {
		   newPoint.y = -mDataBlock->boxSize.y / 2;
		   newPoint.x = newPoint.y * ratio;
		 }
	     if ((angle > -M_PI*0.75) && (angle < -M_PI/4)) {
		   newPoint.x = -mDataBlock->boxSize.x / 2;
		   newPoint.y = newPoint.x / ratio;
		 }
	   }
	   if (newPoint.x <= (mDataBlock->boxTorsoWidth - boxX)) {
	     out_loc = "LTF";
	   } else if (newPoint.x >= (boxX - mDataBlock->boxTorsoWidth)) {
		 out_loc = "RTF";
	   } else {
		 out_loc = "CTF";
	   }
	   // Check Head
	   if ((newPoint.z >= mDataBlock->boxHeadBottom) && (newPoint.z <= mDataBlock->boxHeadTop)) {
	     if ((newPoint.x <= mDataBlock->boxHeadLeft) && (newPoint.x >= mDataBlock->boxHeadRight)) {
		   out_loc = "HF";
		 }
	   }
	 }
#14
04/11/2005 (7:15 am)
} else {
     if (newPoint.z <= mDataBlock->boxTorsoBottom) {
       // Hit Legs
       if (newPoint.x <= 0.0f) 
	     if (newPoint.y <= mDataBlock->boxRear)
		   out_loc = "LLR";
	     else
		   out_loc = "LLF";
       else 
	     if (newPoint.y <= mDataBlock->boxRear)
		   out_loc = "RLR";
	     else
		   out_loc = "RLF";
	 } else {
	   // Torso Hit
       // Torso twisting coversion
       if (mDataBlock->twist) {
	     // Get hit angle
         F32 angle = mAtan( newPoint.x, newPoint.y );
	     // Get current rotation
	     Point3F headRotation = getHeadRotation();
	     // Subtract twist from angle (to move in opposite direction)
	     angle -= headRotation.z;
	     // Convert angle to -PI to PI
	     if(angle > M_PI )
           angle -= M_2PI;
         else if(angle < -M_PI )
           angle += M_2PI;
	     // Get distance ratio
	     F32 ratio = mTan(angle);
         // Calculate new location based on quadrant
	     if ((angle >= -M_PI/4) && (angle <= M_PI/4)) {
		   newPoint.y = mDataBlock->boxSize.y / 2;
		   newPoint.x = newPoint.y * ratio;
		 }
	     if ((angle > M_PI/4) && (angle < M_PI*0.75)) {
		   newPoint.x = mDataBlock->boxSize.x / 2;
		   newPoint.y = newPoint.x / ratio;
		 }
	     if ((angle <= -M_PI*0.75) || (angle >= M_PI*0.75)) {
		   newPoint.y = -mDataBlock->boxSize.y / 2;
		   newPoint.x = newPoint.y * ratio;
		 }
	     if ((angle > -M_PI*0.75) && (angle < -M_PI/4)) {
		   newPoint.x = -mDataBlock->boxSize.x / 2;
		   newPoint.y = newPoint.x / ratio;
		 }
	   }
	   if (newPoint.x <= (mDataBlock->boxTorsoWidth - boxX)) {
	     if (newPoint.y <= mDataBlock->boxRear)
		   out_loc = "LTR";
	     else
		   out_loc = "LTF";
	   } else if (newPoint.x >= (boxX - mDataBlock->boxTorsoWidth)) {
	     if (newPoint.y <= mDataBlock->boxRear)
		   out_loc = "RTR";
	     else
		   out_loc = "RTF";
	   } else {
	     if (newPoint.y <= mDataBlock->boxRear)
		   out_loc = "CTR";
	     else
		   out_loc = "CTF";
	   }
	   // Check Arms
	   if ((newPoint.z >= mDataBlock->boxArmBottom) && (newPoint.z <= mDataBlock->boxArmTop)) {
	     if (newPoint.x <= (mDataBlock->boxArmWidth - boxX))
	       if (newPoint.y <= mDataBlock->boxRear)
		     out_loc = "LAR";
	       else
		     out_loc = "LAF";
	     if (newPoint.x >= (boxX - mDataBlock->boxArmWidth))
	       if (newPoint.y <= mDataBlock->boxRear)
		     out_loc = "RAR";
	       else
		     out_loc = "RAF";
	   }
	   // Check Head
	   if ((newPoint.z >= mDataBlock->boxHeadBottom) && (newPoint.z <= mDataBlock->boxHeadTop)) {
	     if ((newPoint.x <= mDataBlock->boxHeadLeft) && (newPoint.x >= mDataBlock->boxHeadRight)) {
		   if (mDataBlock->boxHeadTop == mDataBlock->boxSize.z)
	         if (newPoint.y <= mDataBlock->boxRear)
		       out_loc = "HR";
	         else
		       out_loc = "HF";
		   else
		     if (newPoint.y >= mDataBlock->boxRear)
	           out_loc = "HF";
		 }
	   }
	 }
   }
}

Realize that some of the values are absolute (like boxTorsoBottom) while some are percentages (0 to 1 like boxRear). The original code in your system will probably be easier to understand as mine covers two kind of players and is rather convoluted.

HIH
#15
04/11/2005 (7:18 am)
Can anyone say "resource" ? Hint hint...
#16
04/11/2005 (7:31 am)
Tx again. On the code side it's pretty clear to me, but how do you get the values - like ie
boxTorsoBottom = 2.75; // Bottom of Tors
How do you get them of the model on the artist side. Ie if I have 3 circles on the box face - how do I get their centerpoints?

cheers,
Arkadesh
#17
04/11/2005 (8:23 am)
Arkadesh,

I have the models in MilkShape and I can measure the bounding box (which is the first line in my example code [x,y,z size]), then I measure (approximate) the various areas. I take by your question that ShowTool doesn't give you measurement info so you will need an art package to get it. If you don't have access to the original model, it's going to be difficult.

HIH
#18
04/12/2005 (12:25 pm)
While there's some interest in the topic I'll try another approach - what part of engine should I take a closer look if artist creates several collision boxes and puts them into the dts model. Is there any ready function returning name of collision box hit?

cheers,
Arkadesh
#19
04/12/2005 (1:07 pm)
Ah, for that you will need to look at Hitboxes for players.