Game Development Community

PlatformJumping: CastCollision Vs. Pick[Line/Rect] Vs. Triggers

by Eric Robinson · in Torque Game Builder · 10/03/2006 (11:35 pm) · 69 replies

Okay, I've looked around through the forums, looked into the script functions, [in some cases] skimmed the source, and spent considerable time pondering the issue of jumping/falling for platformer style games.

Here's what I understand as drawbacks for the three different jumping styles:

1) The CastCollision route. This is the route taken in the TGB MiniPlatformerTutorial. The issue I have with this algorithm [at least as implemented in the tutorial] is that it requires you to call "onUpdateScene()" for movement resulting in at least two calls to castCollision() per frame update (the second call was to fix the bug described and fixed here). I feel like this is very inefficient. I believe that movement should not necessarily require a call to "onUpdateScene()".

2) The Pick[Line/Rect] route. I will admit that I don't fully understand this method. From what I understand, however, it would require the same constant updating as the castCollision route.

3) The Triggers route. I don't remember where I saw it (can't find the forum link) but I read a while back about someone using some triggers to determine how physics works when someone jumps. Essentially you map triggers to all the platforms (or walkable surfaces) somewhat akin to the way OneWayCollision platforms work. When the player is in the trigger (onEnter) you set the constantForceY to zero and walk along the platform. Then, when you leave the trigger (onLeave) by walking off the platform or jumping, then you set the constantForceY to something non-zero. The catch here? You have to have triggers everywhere watching for the player (or anything else in their collision groups). Big levels = lots and lots of triggers requiring collision detection. Is this type of collision worse than the tileLayer collision stuff? If not then one could potentially just shut off collision on the tileLayer-level platforms and then use the collision with the triggers to run on...

So I guess it boils down to this: which is more efficient? The castCollision/pickSomething route or the triggers route? The prior requires constant extraneous collision detection while the latter adds a huge amount of objects to the collision system (though you could cut out a whole lot by turning off collision on the tileLayer).

Thoughts?
#21
10/09/2006 (2:09 pm)
There is a quirk with the getLinearVelocity function (if that's what you're using). It will return the linear velocity that the object would have if it wasn't colliding (or something like that - don't quote me). There's a thread about it somewhere, but I couldn't find it in under a minute.
#22
10/09/2006 (2:13 pm)
@Tom,

yeah I read the thread but I don't really know... the force pulls down the object even though it is colliding. The velocity is 0 nevertheless if the character stands flat on the ground, but if one foot(so to say) is in mid-air I _sometimes_ get values not equal zero. Maybe this is due to some fixes that didn't make it into 112 as mentioned by Melv and Justin?

@Thomas,

did you have similar problems? And if so, mind sharing how you solved them? :)
#23
10/09/2006 (4:52 pm)
@Firas: I commented out the entire first block of quoted code. Everything. From "%collision = ..." to the closing brace after "$pGuy.setConstantForceY(0);". All of it. That block of code is in the miniPlatformerTutorial in the updateMovement() function definition.

@Oliver: I'm not sure what you're saying in the following:
Quote:the animation switches between stand and fall if I collide with both ground and side and the animation changes to side when one edge of my player is in midair and one i still on the ground.
How do you have one edge of your player in midair and one on the ground? Are you doing something special with rotations or...?

As for some of the oddities, I'm sorry that I didn't mention them. I find that when I run into a wall, the animations get jittery because I'm no longer telling it to stop the velocity along the x-axis (as was happening with some of the code that gets commented out)... (at least I'm pretty sure that's what I was experiencing... I've had a loooong weekend). You could try leaving the checks along the x-axis in... I took them out because I find that changing the linearVelocityX component while falling used to cause the character to get well and truly stuck. Maybe with the removal of linearVelocityY getting/setting, though, things will work properly? If push comes to shove, however, you can always substitute in a pickLine call to see if you're running into a wall or something. Then you sidestep the entire linearVelocity checking altogether.

In response to the following:
Quote:For some reason, when I am standing on an edge with my character I get values greater than zero which causes the character to change to the jumpDown animation.
I had a similar oddity on edges: whenever I couldn't jump (but could run), running to an edge would once again enable my ability to jump (using the unmodified/uncommented code from the miniPlatformerTutorial, of course). It seems that calculations for collision differ at these end-points(?). I'll have to do some testing to see what I can make of everything.

Could you also link the thread Tom mentioned? Thanks!
#24
10/09/2006 (5:35 pm)
Anyone experiencing the issues with the miniPlatformerTutorial (getting stuck, not being able to jump, etc.), take a look at this thread. Seems to be related to the collision polygons...
#25
10/09/2006 (6:12 pm)
I have yet to try leaving physics enabled for this but the MiniPlatformerTutorial works a TON better when you define your custom polygons using exactly horizontal lines for the 'head' and 'feet'. I documented how to do this here.

As for the gravity... we'll have to see if leaving it on with the above fix will result in something positive.
#26
10/09/2006 (8:01 pm)
@Oliver: I just removed the physics shut-off code again and re-tested. I think I see what you're talking about. The player's animation flips between falling and standing when just left alone. Absolutely agreed that this shouldn't be happening.

My fear is that this is related to the way getLinearVelocityY() works. I hear that it works by returning what the current linear velocity is set to, not what the current velocity actually is.

We have two opposing things in this situation: CLAMP mode trying to stop the player from breaking through the collision box and the physics system attempting to keep it moving through gravity. My assumption is that the physics system sets the linear velocity, even though it can't go anywhere. When we poll we occasionally intercept that value, resulting in the flickering we see.

Hmm... changing the response mode to STICKY results in a similar issue. Upon collision the player flickers between falling and standing (though, thanks to the STICKY mode, movement left or right is not possible... jumping works though!).
#27
10/09/2006 (9:10 pm)
Okay, I found the problem. It's all stemming from the wall climbing fix. Read about what's going on with the 'getting stuck in the level' issue here.

Removing the wall fix removes the issue. However, there are several side effects:

1) While running, your character movement will stop but the animation continues.
2) You can once again reach high places through the ever-sweet wall-riding technique!
3) If you have slanted surfaces, watch out for fun! If you run UP a slope and let go before reaching the top, chances are really good that you'll be bouncin' upwards a bit (because of the linearVelocityY component associated with moving, well, UP.

On the other hand, your character can move around again...
#28
10/10/2006 (12:16 am)
I made some screenshots to clarify what I mean:

www.expressupload.de/index.php?file=gf7aKdIUS6w.png
www.expressupload.de/index.php?file=dfIC2fTT2Me.png


I will do some further testing later this evening(German time).
#29
10/10/2006 (2:21 am)
Okay, as Eric said, straightening out the collision polygon solves this problem. I still think this is a bug and should be fixed... you shouldn't be forced to use a box to get proper physics.

I also straightened out the sides and I didn't experience any ride up the wall bugs. The only problems left are the animation flickering when walking against a wall and being unable to jump from time to time.
#30
10/10/2006 (5:50 pm)
@Oliver: It's not actually a bug with the physics engine, just the movement algorithm that the miniPlatformerTutorial uses. The wall-climbing bug is really awkward but it, too, is due to ignorant use of function calls. The hack that fixes the wall climbing in the tutorial, while seemingly simple and elegant, makes impossible the vast majority of scenarios that one would consider standard for a platformer.

The miniPlatformerTutorial is not useful as an archetype for platformer games. It is useful as a learning device and a simple way to introduce you to some of the systems in TGB. I, for one, have learned a butt-load from working through the tutorial. And, subsequently, debugging the issues.

As for the wall-climbing bug, my feeling is that what is happening is the following:
1) You bump into the wall and stop moving horizontally. The CLAMP physics response does this automatically by nullifying the horizontal component of the velocity.
2) You change the velocity of the object again (simply by holding down the arrow key), forcing the player towards the wall again.
3) We still have a vertical (Y) component to the velocity and that gets translated as usual (resulting in vertical movement up or down). However, we suddenly changed the velocity and rammed into the wall again, with the horizontal velocity being nullified once again by CLAMP physics response.
5) Repeat this as long as there's a wall... we keep putting a constant force to the object and thus the speed of the climbing is constant (if you've played with it then you'll notice that the you retain the vertical speed you initially ran into it with - or at least something very close to it... and this includes climbing down.

Perhaps the "constantForce" doesn't get a chance to affect the vertical velocity because of this looping?

I'm more than likely wrong on some point but I feel that something very similar to the above is occurring, giving us all irritating headaches...

[EDIT: Changing the gravitic flag has no effect on wall climbing. Removed that from the 'explanation'.]
[EDIT2: More plausible explanation thanks to new information regarding CLAMP from Thomas B.
#31
11/06/2006 (3:33 pm)
Hey guys, i'm having a problem with this line in Thomas Buscaglia's isOnGround() function:

if( %currObj.typeMask & $Game::ObjectType::Platform )

My if never returns true.

I'm using this code in the miniPlatform Tutorial.

Thanks in Advance
#32
11/06/2006 (3:45 pm)
@Gustavo: You need to specify your platforms as such. I'm not sure how to do this off the top of my head. I seem to remember seeing it in one of the old tutorials from the Torque2D section of TDN...

Or... Thomas?
#33
11/06/2006 (6:16 pm)
Thanks for the help Eric, but i couldn't find any information about that.

I really don't have idea where i should specify that.
#34
11/06/2006 (7:09 pm)
My guess is that Thomas specified a global variable namespace or something (I'm not familiar with a $Game::ObjectType:: variable string at all) elsewhere in his code. You should feel free to change that. I found the area in the tutorials that I was referencing above. The specific section is here. Do not use this tutorial to start a platformer in TGB. It is out of date. Do read through the tutorial to see how different scripting tricks are implemented because most will carry over into the TGB world (possibly with some necessary modifications). TypeMasks (equivalent to graph-group/layer specifications(?)) are one of the things that carry over well. Particularly, look at the following:
Quote:Click on your player and go to "Edit" tab. In "Scene Object" you will find a "Group" field.
Select number "1" for your player, and "2" for the platforms (click on your Tile Map, and modify it's group field).
Update your "onLevelLoaded" function with this two lines:

$platformGroup = 2; //I'm doing this because i don't know how to get a Tile Map GraphGroup :-.
   $playerGroup = $player.getGraphGroup();
In this case, you tell the editor to set the tileMap's graph group to 2. Then you hand code in a global variable that says the same thing. If you use this setup then you could change the code from Thomas' stuff above to:
if(%currObj.getGraphGroup() == $platformGroup)
(The & is used for bitMasks and you aren't using bitMasks in the example above.)
#35
11/07/2006 (1:18 pm)
Thank you very much Eric. It's working now.
#36
11/07/2006 (7:43 pm)
Glad to hear you got it working!
#37
11/08/2006 (12:49 pm)
The object types were just global variables that we use as to set a type mask for certain things to check exactly what the objects involved with the action are. In the datablocks for those objects there is a typeMask field where the type bits are specified. You can then do a bitwise and on the type you want to check for and the typeMask of the object to see if the type you want is part of what the object is. We also store graph groups in sets of globals.

Definitions (at the top of game.cs):
$Game::ObjectType::Platform = 0x1;
$Game::ObjectType::OneWayPlatform = 0x2;
$Game::ObjectType::TilePlatform = 0x4;
$Game::ObjectType::Actor = 0x8;
$Game::ObjectType::Player = 0x10;
// etc...

An example datablock:
new t2dSceneObjectDatablock( OneWayPlatformConfig : PlatformConfig )
{
   // ObjectType = t2dStaticSprite.
   class = "OneWayPlatform";
   typeMask = $Game::ObjectType::Platform | $Game::ObjectType::OneWayPlatform;
   graphGroup = $Game::CollisionGroup::OneWayPlatform;
};

An example check:
if( %object & $Game::ObjectType::Platform )
   echo( "This is object is some type of platform." );
#38
11/08/2006 (7:16 pm)
@Thomas: Does this mean you get to define 32 types in this way? Of course you can combine these things (as you do in the OneWayPlatform config). But... isn't this redundant? Unless you have something that requires three or more bit-flags to specify it's 'type' properly you could just get away with the 'class' and 'superclass' misnomers, couldn't you? Of course every game is different and some will require fewer flags than others but... I'm trying to get a feel for how your implementation differs (pros/cons etc.).
#39
11/09/2006 (2:44 pm)
It might seem redundant at first, but it's really not. For the purposes of being on the ground, the actor only cares if the object is *any* sort of platform. When the actor wants to pass through a one-way platform, it becomes important to have the distinction.

The reason we use this typemask thing rather than the class/superclass fields is that two objects of different base C++ classes can't be linked to the same namespace because of how namespaces inherently work. This caused a huge pain when checking for object types cause we would have to check for four different platform classes (solid and one-way have two classes each - one for tile layers and one for static sprites). It was just an easy quick way to get it to work, and it seemed logical. After all, the class fields weren't designed to be used as object type indicators.

You can combine bits to get more than 32 so long as you are absolutely positive that the two bits you use for a certain type are never otherwise combined in any masks. For example, it would most likely be safe, depending on your game, to define a type that was made up of the player bit and the platform bit, since those are highly unlikely in most games to ever appear on the same object. Combining one-way platform and platform, on the other hand, would be a disaster because all one-way platforms would also test positive for that third type.
#40
11/09/2006 (5:38 pm)
That makes perfect sense. The whole C++ class interaction explanation really makes the point solid. Is there any way you could write this up in a kind of "TGB Programming Gems" section of the Wiki (TDN) or something? It's little things like this that I really love coming across and can really help. Having a well-organized place to find this kind of thing would be truly appreciated.

I mean, who's going to think to look at a thread called "PlatformJumping" to find that kind of thing? (And my experience with both the forum's and the TDN's search mechanism has been less than spectacular...)

And yes, I ripped that 'title' from the "Game Programming Gems" book series ;D