Game Development Community

Crouch Logic Problem

by Marcus L · in Torque 3D Professional · 07/21/2010 (1:16 pm) · 19 replies

lame title, i know
Hello torquers,

There are two crouch logic problems the torque moderators should fix for the next final release (1.1 final):

Problem 1:
I've thought about this some times when planing and making my levels, so I've comed to ask you (the forum) for advice.

Warning: Unnecessarily long explenation ahead
Now let me explain the dilema, For example: You're suposed to move through some air ducts, but you're too high to get in. *pling* You got the idea to bend your legs to fit in the air duct in other words, crouching. So the player presses the crouch button to be able to move through the air ducts. Then when the player gets in to the air ducts, he expects he can release the button and still be crouching through the ducts. *releases button*, dun-dun-dun, and he's head is sticking out of the air ducts looking at inverted geometry...

If you still don't see the problem after my Unnecessarily long explenation here are some pics:

img20.imageshack.us/img20/1039/screenshot00500002.png
*releases button*
img687.imageshack.us/img687/9648/screenshot00500004.png
I think you see the problem now. I have not tried to solve this problem yet, and I think if I would try to, i would've done many mistakes. I believe the most logical solution would be to do a rayCast uppwards that somehow interacts with the players boundingBox. (This is where you come in) Help me find the solution for this one, and please post it here.

Problem 2:
This one is not hard to fix at all, it is just me that think this sould be fixed in future releases of T3D.

Standard crouchBoundingBox:
img33.imageshack.us/img33/9568/screenshot00500000.png

MXG's crouchBoundingBox:
img20.imageshack.us/img20/1253/screenshot00500001.png
To fix, add:
boundingBox = "1 1 2";
swimBoundingBox = "1 2 2";
crouchBoundingBox = "1 1 1.45"; // Add
to defaultPlayerData in art/datablocks/player.cs.

Thanks,
Marcus L.

#1
07/21/2010 (5:28 pm)
nice catch.

From what I know of the crouch, ray casting might be the solution when you release the crouch button.

2nd issue. I'm not familiar with those parameter, what the goal of those value? are they to modify the current bounds box in the model?
1 = 100% means no changes?

On crouch animation, you export a bound box that is used for the animation speed & to match key frame. Do you know if it is used also for bounding collision? So depending of your move, the bounds box is updated.
#2
07/21/2010 (5:44 pm)
Just a quick and dirty for the crouching problem. Change the code for the doCrouch function in scripts/client/default.bind.cs so that the x key becomes a toggle.

function doCrouch(%val)
{
   if(!$isCrouching)
   {
      $isCrouching=true;
      $mvTriggerCount3++;
   }
   else
   {
      $isCrouching=false;
      $mvTriggerCount3++;
   }
}

also add at the top of this file
$isCrouching=false;
#3
07/21/2010 (5:53 pm)
@ elvince
If you where expecting an answer from me, sorry, im not 100% sure about the answer to your questions but i can give them my best guess. Someone else please correct me if I'm wrong!

Quote:1 = 100% means no changes?
I think so. I guess it modulates the original bounds.

Quote:Do you know if it is used also for bounding collision?
Yup, guess it is.

Quote:On crouch animation, you export a bound box that is used for the animation speed & to match key frame.
Not sure, someone else plz?

@ Richard
Umm.. Couldn't you do this instead:
function doCrouch(%val)
{
   if(%val)
      $mvTriggerCount3++;
}
And it doesn't exactly fix the problem, it just prevent it form happen more often. You can still rise up and get stuck in the geometry.
#4
07/21/2010 (6:00 pm)
@Marcus:

You're right, it doesn't fix the problem, but in the part where you rise up again you can perform a upward raycast to see if there is enough space to get up. I said it was quick and dirty;P
#5
07/21/2010 (6:07 pm)
Switching the keybind to a toggle is a good step. I agree that there should be a check for overhead height before untoggling to prevent the "head is sticking out of the air ducts looking at inverted geometry..." problem.

Quote:
2nd issue. I'm not familiar with those parameter, what the goal of those value? are they to modify the current bounds box in the model?
Those are X Y Z (width, depth, height) values that denote the size of the bounding box of the player. These technically should be different for each pose (normal, crouch, prone, and swimming), and model dependent, in order to force the bounding box to conform to the relevant player action and shape. You can see the bounding box while in the editor: toggle to free cam mode and select the player. This will make a frame appear around it indicating the bounds box. Adjust the datablock properties to make the bounding box smaller/larger.
#6
07/21/2010 (6:11 pm)
[Edit]

I found in Player cpp:
case CrouchPose:
boxSize = mDataBlock->crouchBoxSize;
break;

So I think that's it, you need to setup your box size accuratly and this will work.
From a quick reading of the source code, it seems that this box value are "torque unit" and not "scale value of the current model box".
Stupid question:So what the use of putting a bound box in the Player model, if the datablock redefine it.

Another way to do this, could be to use the bounds box of the DSQ? this might need more C++ coding, but at this end, depanding of the current animation on your player, your bounds will fit what you design!
[Edit]
Might be difficult... as if you have different thread 1 for legs and 1 for arms running at the same time, you will have to register both in collision list...
#7
07/21/2010 (6:29 pm)
If i know the gideon model correctly, it uses the bounds as collision, which therefore makes changing the bounds size logical.

Quote:You need to review the crouch animation so the bounds is matching the height of your model when crouching and this will work perfectly. Don't you think?
ahhh, almost forgot, you cannot animate the bounds. That is why that is not a good idea. But if your player uses collision meshes, then you can animate the collision to fit your crouching player.

EDIT: you editied your post, this post might not make sence anymore
#8
07/21/2010 (6:29 pm)
Stupid question:So what the use of putting a bound box in the Player model, if the datablock overrides it from scratch?
#9
07/21/2010 (6:36 pm)
Quote:
Quote:You need to review the crouch animation so the bounds is matching the height of your model when crouching and this will work perfectly. Don't you think?

ahhh, almost forgot, you cannot animate the bounds. That is why that is not a good idea. But if your player uses collision meshes, then you can animate the collision to fit your crouching player.
I didn't know that. In this case, you can only select 1 bounds size per animation, but that could be more customizable than just the 3/4 datablock properties.
#10
07/21/2010 (6:50 pm)
Quote:Stupid question:So what the use of putting a bound box in the Player model, if the datablock overrides it from scratch?
Try changing the boundingBox to "0 0 0", it will only affect the collision, not the bounds itself. So in theory, the boundingBox value is useless if you have a defined collision anyone plz correct me if I'm worng.

Quote:In this case, you can only select 1 bounds size per animation
FYI it is also a bad idea to change bounds during animation change.
#11
07/21/2010 (8:31 pm)
Collision meshes are not used with a player object, instead a bounding box is used for collision and determination of damage location*. The player's bounding box is handled through code. The datablock properties determine the size of this box, which varies depending upon pose.

*damage location is wrong when in crouch/prone pose (unfinished code)
#12
07/21/2010 (8:36 pm)
Thanks for the clarification on that, i just checked the player code and realized this, but i have one question then: How does the engine deal with the damage locations? Is it like; from top to ~7% down is estimated to be head, and form ~7% down to ~33% down is considert to be the body.

This is getting of topic =/.
#13
07/21/2010 (8:56 pm)
@Marcus:
Yeah, that's pretty much how the damage locations are calculated. I believe it actually calculates percentage from the bottom up though - anything greater than boxNormalHeadPercentage would be the head, anything less than boxNormalTorsoPercentage would be the legs, and everything in between those values would be the torso. This box percentage calculation is also why the damage locations are wrong when in other than the normal standing pose.
#14
07/21/2010 (9:06 pm)
Looks like Player::canStand() would be a good place to do a overhead check, where it says
Quote:
// Do standard Torque physics test here!


#15
07/27/2010 (7:53 pm)
*Bump Time*
Well, as I said in my post, I could integrate overhead check myself, but it might take unnecessary time and effort to get it done (mostly since I don't know wth I'm doing at times).

So when this thread ends up at page 2, I'll take that as i sign that I'll have to integrate this myself.
#16
07/28/2010 (1:25 am)
I'll take a shot at this later this evening or tomorrow morning. I use crouch and prone fairly heavily and somehow never bothered to test for this case, which honestly needs to be fixed less for the "you got stuck" factor and more for the (minor) "I'm uncrouching to look through solid geometry" exploit factor.

Fairly simple logically... If a Player is crouched but the crouch trigger is no longer down, do upward raycast from (x, y, z + crouchBounds->topExtent) to (x, y, z + standBounds->topExtent) and don't allow a return to stand state if we hit something. This gets repeated every tick until A) User resumes active crouch trigger state (holding or toggle), B) raycast doesn't hit anything.

I remember seeing the canStand function, but I don't have the code on my laptop here so I can't determine whether that's just a disembodied empty function or is actually called by the whole crouch/prone/stand system. If it's actually being called, I'll put my code in there.

Now, for 100% accuracy as far as getting stuck we should actually be doing 4 raycasts, 1 from each corner of the crouched bounding box up to the 4 corners of the standing box, but that's probably overkill. If you can find a tiny hole in the ceiling to pop your head up into and get it stuck in, more power to you -- in other words you just found a spot you can uncrouch into and need to crouch again to get out of it.

Anyway I'll post back as soon as I get home and have a chance to throw together a solution. :P
#17
08/07/2010 (6:11 pm)
Sorry for the bump/double post, but I figured some people might like to know that this was available.

In T3Dplayer.cpp, go to the function
Player::CanStand()

and replace it with this:

bool Player::canStand()
{   
   if ( mState != MoveState || 
        mDamageState != Enabled || 
        isMounted() || 
        mSwimming )
      return false;

   // Do standard Torque physics test here!
   if ( !mPhysicsRep )
   // [HNT] raycast from top of crouch or prone box to top of standbox
   {
      Point3F boxSize(1,1,1);

      // check current pose
      switch (mPose) 
      {
         case StandPose:
            return true; // bail, already standing
            break;
         case CrouchPose:
            boxSize = mDataBlock->crouchBoxSize;         
            break;
         case PronePose:
            boxSize = mDataBlock->proneBoxSize;         
            break;
         case SwimPose:
            return true; // always allow stand from swim
            break;
      }

      disableCollision(); // don't collide w/ self
      Point3F start = getPosition();
      start.z += boxSize.z;
      Point3F end = getPosition();
      end.z += mDataBlock->boxSize.z;

      RayInfo rinfo;
      bool rayHit = false;
      rayHit = gServerContainer.castRay(start, end, sCollisionMoveMask, &rinfo);
      enableCollision(); // done, turn collision back on

      if (rayHit)
         return false;
      else
         return true;
   }
   // [/HNT]

	// We are already in this pose, so don't test it again...
	if ( mPose == StandPose )
		return true;

   return mPhysicsRep->testSpacials( getPosition(), mDataBlock->boxSize );
}

Code changes between the [HNT] and [/HNT] tags. Suggest replacing those tags with whatever you use to ID your code edits, unless you somehow actually have the same initials as me. ;D

I left the now semi-redundant "if (mPose == StandPose)" (the switch/case pose statement already handles this now) because the added code will still be skipped if the Player is using mPhysicsRep, ie if it's using a physics plugin. Could've moved this above my new code and removed the standPose case from the switch, but I wanted to maintain the structure of the original code as best I could for easy porting.

Tested with a StaticShape cube, crouched under it and released crouch, player won't stand back up until you walk out from under it.

Remember to set your bounding boxes in the PlayerData DB. These are in meters, ie they're explicit units, not multipliers on the models bounding box. Try to make them fit the size and animations of your Player object as best you can. If you don't set them, the engine will use some "default" values I assume are calibrated for Gideon.

Default values for reference:
boundingBox = "1.0 1.0 2.3";
crouchBoundingBox = "1.0 1.0 2.0";
proneBoundingBox = "1.0 2.3 1.0";
swimBoundingBox = "1.0 2.3 1.0";

As you can see the default crouch box is just 0.3m shorter than the stand box, which is why it's hard to crouch under stuff in the stock setup. You can play with these values until you find what works without letting your player's head pop up through ceilings.
#18
08/07/2010 (6:44 pm)
Awesome Henry, thanks for figuring this out. Unfortunately I'm unable to test now because when i ported to 1.1b2 i included PhysX which makes me unable to crouch, but I'm working on it.

Thanks again Henry for the Awesome effort :D
#19
08/07/2010 (6:53 pm)
When it's using a physics plugin, the work of checking to see if the Player can crouch/uncrouch seems to go to mPhysicsRep->testSpacials ... I'm not sure how much of this plugin/PhysicsPlayer stuff is totally finished, though. At least, it wasn't finished in some earlier versions I've tried. Not using PhysX at the moment so I'm not sure I can be much help on this one. :P

You might try going to Player::canCrouch() and using Con::printf to see what testSpacials is returning. I don't honestly see the need to run a physics check to go to crouch, unless your crouch box is somewhat wider and might overlap into an object in front of/beside you, but it does appear to run the box check.

Hope I got that about right... on my laptop now and not looking at the code. :P