Game Development Community

Advice for debugging player-vs-DIF collision issues ?

by Orion Elenzil · in Torque Game Engine · 10/10/2007 (1:02 pm) · 9 replies

Hey folks -
we're encountering some problems with avatars getting stuck on portions of DIF geometry where it seems like they shouldn't.
is there any advice for going about debugging something like this ?
ideal would be a visualization of the current points of collision,
but also useful would be any sort of diagnostics like "the player is blocked in front", "the player is blocked on top", etc.

specifically i've got a situation where a player is trying to walk into a room which has a very slightly raised floor,
and there's an overhang above the player. similar room without the overhang can be entered no problem, but this one the player just stops dead as if there were an invisible wall in the door. - the funky part tho is that if the player jumps a little bit, he can go right in. so it's not a simple case of the overhang being too low.

also i've tried reducing the player's height, and the behaviour is unchanged.

our engine has some modifications in these areas,
so it's quite possible that this is something we've introduced,
so what i'm really after are tips on how to approach solving the problem.

tia!

orion

#1
10/11/2007 (12:22 am)
This might sound silly, but if your player is unable to go up a small slope, could it be that the runSurfaceAngle is set too low? It's a property of the player datablock and it indicates the maximum slope your player can walk on...
#2
10/11/2007 (12:32 am)
Does this help?

On edit I see you had already posted in that resource's thread.
#3
10/11/2007 (6:35 am)
Hey Orion,

Taking a look at collisionTest in the code base might help you. Here is a quick cut & paste from my own personal documentation.

DISCLAIMER: I think the description is right but it is based off my own research by looking at the code base (and reading GG), so I could be wrong. :)

ExtrudedPolyList returns a set of collision points and normals. They are gathered by taking a box (bounding box) and extruding it along a vector path (movement path). Typically used for player collisions. The extruded box is axially aligned. So, when the player is moving in a direction not aligned with the world axis, the extruded box is slightly wider then the player's object space bounds.

Since the only things returned and stored in an extrudedPolyList are collision points and normals, we can't get vertex information of collided polys. To test it in TGE 1.4.2, do this in the console:
$Collision::testExtrudedPolyList = 1;
$Collision::boxSize = 4;
Now run around and you will see the shape of the extruded box on the screen, as well as little yellow lines representing the collision point and normal.
#4
10/11/2007 (6:41 am)
Some more of my personal notes on the collisionTest object, which give an example of debug collision rendering.


The collisionTest object is setup seperately from the rest of the game world and TGE structure. So it doesn't operate under or is called from any existing Torque game object. Instead, a extra call is placed at each of the major places where Torque updates the game world and renders the game world, so the collisionTest object can also be updated and rendered.

Game.cc
// --dp A global collistTest object is created at the top of the file.
CollisionTest collisionTest;


Game.cc
void GameInit()
{
...

// --dp The scripting things are inited, probably just for the script vars to toggle rendering on and off.
   // Initialize the collision testing script stuff.
   collisionTest.consoleInit();
}


Game.cc
bool clientProcess(U32 timeDelta)
{
   ShowTSShape::advanceTime(timeDelta);
   ITickable::advanceTime(timeDelta);

	// --dp Torque game world is advanced on the client.
   bool ret = gClientProcessList.advanceClientTime(timeDelta);

   // Run the collision test and update the Audio system
   // by checking the controlObject
   MatrixF mat;
   Point3F velocity;

   if (GameGetCameraTransform(&mat, &velocity))
   {
      alxListenerMatrixF(&mat);
//      alxListener3f(AL_VELOCITY, velocity.x, velocity.y, velocity.z);

// --dp The transform for the current game camera is passed in to the collisionTest object to use as it's position to start collision tests with.
      collisionTest.collide(mat);
   }


Game.cc
void GameRenderWorld()
{
...
   dglSetCanonicalState();
	// --dp Torque game world is rendered on the client.
   gClientSceneGraph->renderScene();
   glDisable(GL_DEPTH_TEST);

	// --dp collisionTest does its rendering after the main game world is rendered.
   collisionTest.render();
#5
10/11/2007 (7:09 am)
How I setup visual debugging for collision

This may not work for what you need, but hopefully it will help. I actually setup something for the clippedPolyList, but the same approach should work for an extrudedPolyList.

What I did was to setup a global polyList pointer that is rendered in the game loop. This way, if it is null it does nothing, and if it points to something it will render to the screen. That way I can more easily render collision information from different objects.

WARNING: Lots of the player collision objects are constructed and deconstructed during their update loop (I think in updatePos()). So the render that out to the screen later, you are going to have to take one of those vars and make it a member of the player class or global so you don't lose that data. Otherwise you won't be able to render it to the screen.

Ok, so here we go:

First create a global poly list pointer.
\engine\game\game.cpp
// --dp put this at the top of the file, after the includes
ExtrudedPolyList * gDebugCollisionPolyList = NULL;  // --dp

Next, we need to make the polylist pointed to by the pointer render.

\engine\game\game.cpp
void GameRenderWorld()
{
//...
   gClientSceneGraph->renderScene();
   GFX->setZEnable( false ); //glDisable(GL_DEPTH_TEST);
   collisionTest.render();

	// --dp Render the debug polylist
	if (gDebugCollisionPolyList)
	{
		gDebugCollisionPolyList->render();
	}
//...
}

Make the list accessible to the class/file you want to use it with (like Player):

\engine\game\player.cpp
extern ExtrudedPolyList * gDebugCollisionPolyList;

Make the global polylist pointer point to the polylist you want to debug. You can put this code pretty much anywhere. I put it in one of the player update loops.
The variable mCollisionPolyList is a new class variable which would replace the temporary polylist used in the player collisions, such as sExtrudedPolyList used in Player::updatePos(). This is so when the main loop goes to render out the collision info, there is actually something there.

Note how the collisions are set to the client object. Since the client object and server object are 2 different things, you are going to want to single out which one you want to render.

\engine\game\player.cpp
if (isClientObject())
	{
		bool renderMe = false;
		if (renderMe)
			gDebugCollisionPolyList= &mCollisionPolyList;
		else
			gDebugCollisionPolyList= NULL;
	}


Finally, in ExtrudedPolyList::render(), you can add some custom rendering via gl calls (I'm assumming you are using TGE). There is already a basic rendering routine which renders out collision points and normals. Note I did this in TGEA, so my file names end with .cpp instead of .cc. In TGE the files will be .cc.

\engine\collision\extrudedPolyList.cpp
void ExtrudedPolyList::render()
{
// --dp This is the stock TGE rendering routine.
if (!mCollisionList)
      return;

   glBegin(GL_LINES);
   glColor3f(1,1,0);

   for (U32 d = 0; d < mCollisionList->count; d++) {
      Collision& face = mCollisionList->collision[d];
      Point3F ep = face.point;
      ep += face.normal;
      glVertex3fv(face.point);
      glVertex3fv(ep);
   }

   glEnd();
}


Good luck!
#6
10/11/2007 (7:27 am)
Lastly, even when seeing stuff on the screen, it can be hard to know what is going on in the code at that time. Therefore I recommend implementing a small system where you set a codeline "breakpoint", and have the engine stop there on a key press.

This way, the minute you see a problem happening on the screen, you can hit your debug-break key and jump right to the problem spot, as opposed to trying to step there through the code. For me, often switching over to the IDE to toggle the breakpoint will cause me to lose my test condition.

For example, place you custom breakpoint line called "breakHere();" at the top of the extrudedPolyList::Render() function or in player::updatePos(). Compile, run, turn on visual debugging. Get your problem on the screen. Right as it comes up, hit your break key, which will trigger a breakpoint inside of "breakHere()". Now you can easily (hopefully!) see what code was causing what you were seeing on the screen.

It might take a day to setup, but it is so worth it. I use my system all the time and don't know what I would do without it. I have something where I can place multiple breaklines in the engine, and toggle them from an in-game GUI. In the code I put something like:

breakHere ("updatePos-collisionTest");
breakHere ("input-LeftMouseButtonDown");
breakHere ("player-jump");

Then with the in-game GUI I toggle each one as I need it. When I want to test the condition, I hit shift-F4 and the IDE breaks right at related code section. It makes debugging much easier.

Sorry for the long posting. You may know a lot of this already, but since I know what it is like as I've struggled through similar things I thought posting more may help as opposed to less.
#7
10/11/2007 (9:34 am)
Wow, what a great response !
thanks to everyone who replied.

Yves - thanks for the advice on runSurfaceAngle, but i think this situation is a little different. all the surfaces involved are either walls or flat floors.

Eric - we actually did imlement Ben's collision fix at one point, and i even thought that might *be* the problem, so i went to see if i could easily un-implement it, and then remembered that for some reason we already did (unimplement it). .. yes, according to our SVN log, we rolled back Ben's fix because it actually introduced a few problems very much like the one we're now encountering. hmm, hmm.
which PS, SVN is a wonderful thing, and should make it relatively easy to *reapply* ben's change, since that was already done once.

Drew Parker !
Wow, that is exactly what i was after.
Rendering the collision info based on the player rather than the camera should help.

breakHere() is a cool idea.

thanks again all !
#8
10/11/2007 (9:53 am)
Ftr,
i re-implemented Ben's changes to extrudedPolyList.cc,
and it indeed added problems around stepping onto shallow steps,
and did not fix the issue we're currently having.
#9
10/12/2007 (7:22 am)
Hey Orion,

Great, glad I could be of some help!

Something else I do when having to debug things in motion is slow the time scale. Tom Spillman brought it to my attention and it's a real easy trick, it's done like this in the console:
$timeScale = 0.2;

As lowering the time scale causes all objects to move slower, it makes it easier to sort out bugs that only pop up when an object is in motion, or only pop up for a brief moment.

I wouldn't go any lower then a value of 0.2 - I've found things in the sim break down somewhat and Tom found this as well.