One way platforms solved
by Tom Ogburn · in Torque Game Builder · 06/23/2006 (7:47 am) · 20 replies
This does require Core code changes to 2 files: t2dSceneObject.h and t2dSceneObject.cc.
t2dSceneObject.h changes
around line 403
around line 534
around line 630
t2dSceneObject.cc changes
around line 495
around line 2487 after setCollisionSuppress
around line 7132 in t2dSceneObject::processCollisionStatus
Sample script code for a one way platform - highly modified from the old platformer tutorial
t2dSceneObject.h changes
around line 403
bool mCollisionCallback;
bool mCollisionSuppress;
[b] bool mCollisionCancel;[/b]around line 534
void setCollisionCircleScale( const F32 scale );
void setCollisionSuppress( const bool status );
[b] void setCollisionCancel( const bool status );[/b]around line 630
inline bool getCollisionCallback(void) const { return mCollisionCallback; };
inline bool getCollisionSuppress(void) const { return mCollisionSuppress; };
[b] inline bool getCollisionCancel(void) const { return mCollisionCancel; };[/b]t2dSceneObject.cc changes
around line 495
mCollisionCallback(false),
mCollisionSuppress(false),
[b] mCollisionCancel(false),[/b]around line 2487 after setCollisionSuppress
[b]//-----------------------------------------------------------------------------
// Set Collision Cancel.
//-----------------------------------------------------------------------------
ConsoleMethod(t2dSceneObject, setCollisionCancel, void, 3, 3, "(status?) - Sets the collision cancel status.")
{
// Set Collision Cancel.
object->setCollisionCancel( dAtob(argv[2]) );
}
// Set Collision Cancel.
void t2dSceneObject::setCollisionCancel( const bool status )
{
// Collision Cancel.
mCollisionCancel = status;
}[/b]around line 7132 in t2dSceneObject::processCollisionStatus
// Check for Script Collision-Callbacks for both Source/Destination.
// Source...
if ( pSrcObject->getCollisionCallback() )
{
pSrcObject->onScriptCollision( pCollisionStatus );
}
[b] if (pSrcObject->getCollisionCancel())
{
//Reset Collision Cancel
pSrcObject->setCollisionCancel(false);
//Exit the function and do not process this collision
return;
}[/b]Sample script code for a one way platform - highly modified from the old platformer tutorial
function t2dSceneObject::onCollision( %srcObj, %dstObj, %srcRef, %dstRef, %time, %normal, %contactCount, %contacts )
{
switch (%srcObj.getGraphGroup())
{
case $playerGroup:
switch (%dstObj.getGraphGroup())
{
case $backgroundGroup:
collidePlayerPlatform(%normal);
case $platformGroup:
if (getWord(%normal,1) <= 0)
{
//We are falling or resting on a platform, so collide
collidePlayerPlatform(%normal);
}
else if (getWord(%normal,1) > 0)
{
//We are going up, so don't collide if we are jumping and it is a platform
[b]%srcObj.setCollisionCancel(true);[/b]
}
else
{
// echo("uncaptured collision normal: " @ %normal);
}
}
}
}About the author
Owner of Starlit Sky Games, Senior Developer / Architect at Migration.Mobi
#2
But could you derive a new object and then contain the changes to their own source files? It would be much preferable to not have to make changes to files that would later require updating every time TGB is updated. It might also avoid conflicts if other, less considerate resources make changes to the core objects.
I'm going to try and do it all in script somehow, if possible. That makes porting to Mac a snap because there is no recompile necessary.
06/23/2006 (8:02 am)
Cool! Nice work.But could you derive a new object and then contain the changes to their own source files? It would be much preferable to not have to make changes to files that would later require updating every time TGB is updated. It might also avoid conflicts if other, less considerate resources make changes to the core objects.
I'm going to try and do it all in script somehow, if possible. That makes porting to Mac a snap because there is no recompile necessary.
#3
This was the simplest way I knew how. I wasn't sure how to read a return value from a call out to script. :)
@Josh
I spent a lot of time trying to figure out how to do it in script. The only way I could figure to do it was to disable collisions on the objects in the onCollision and set a callback to re-enable them at some small time in the future. That's actually what I was using, but it is very buggy. There's no good way to know how far in the future to re-enable collisions. Too short and they'll still be moving through the platform, too long and they'll have already passed back through it. I do wish you luck in finding a solution and please share if you do.
As for requiring adding every time TGB is updated, now that it is fully released there shouldn't be as many updates as we've been getting. Also, this is such requested functionality that I'm hoping GG will either add this or another solution.
06/23/2006 (8:25 am)
@ManuelThis was the simplest way I knew how. I wasn't sure how to read a return value from a call out to script. :)
@Josh
I spent a lot of time trying to figure out how to do it in script. The only way I could figure to do it was to disable collisions on the objects in the onCollision and set a callback to re-enable them at some small time in the future. That's actually what I was using, but it is very buggy. There's no good way to know how far in the future to re-enable collisions. Too short and they'll still be moving through the platform, too long and they'll have already passed back through it. I do wish you luck in finding a solution and please share if you do.
As for requiring adding every time TGB is updated, now that it is fully released there shouldn't be as many updates as we've been getting. Also, this is such requested functionality that I'm hoping GG will either add this or another solution.
#4
06/26/2006 (7:23 am)
Thanks , your a life saver !
#5
06/26/2006 (9:00 am)
@Tom: Now that I've been able to compile TGB and try this out I've found a problem with your sample script code. When the player jumps under a platform and surpases it, lands perfectly. But if the player starts falling (the jump force ends) when he's colliding with the platform, weird things happen. Most of the times the player gets teleported over the platform he's colliding with, but ocassionally the program just crashes. Have you thought about how to solve this problem? I guess you have it too, am I wrong?.
#6
06/26/2006 (5:06 pm)
Quote:ditto.
I spent a lot of time trying to figure out how to do it in script. The only way I could figure to do it was to disable collisions on the objects in the onCollision and set a callback to re-enable them at some small time in the future. That's actually what I was using, but it is very buggy. There's no good way to know how far in the future to re-enable collisions. Too short and they'll still be moving through the platform, too long and they'll have already passed back through it. I do wish you luck in finding a solution and please share if you do.
#7
06/26/2006 (6:15 pm)
Use triggers. Put a trigger around the platform. In onEnter, check if the player is below the trigger. If it is, disable collisions. In onLeave, enable collisions.
#8
06/27/2006 (12:28 am)
AFAIK triggers are limited to rectangular areas, aren't they? Because I'm using this 'one way platforms' for mostly the whole level, which is a tile map, and has also non-rectangular tiles like slopes and the like. It'll be a pain in the ass to cover each tile with a trigger, too, and probably produce a significant performance hit.
#9
*pseudo code*
OnCollision
If collideWithPlattform
if y-speed > 0
ignore collision // he is moving upward so can't fall on anything at all
else
land on plattform
06/27/2006 (12:39 am)
Actually I don't see the problem. If you want him to jump through a plattform but correctly fall onto it, there is a quite easy way to do this:*pseudo code*
OnCollision
If collideWithPlattform
if y-speed > 0
ignore collision // he is moving upward so can't fall on anything at all
else
land on plattform
#10
06/27/2006 (12:46 am)
When falling down you also have to ignore platforms you were already colliding with on the peak of your jump path.. otherwise you get strange collision behaviour. :)
#11
I assumed that for something like a plattformer, you would keep a stack or something similar to take care of potential plattforms below you.
06/27/2006 (10:07 am)
Yeah ok, thats not clearly pointed out.I assumed that for something like a plattformer, you would keep a stack or something similar to take care of potential plattforms below you.
#12
And to solve this I would just do a collision cast over a small amount of time when starting to fall down. :)
06/27/2006 (10:10 am)
Sorry if you got that wrong... I didnt want to critize your post, I wanted to add a piece of information to it that doesn't seem very obvious if you first think about it. I just remember that from experience when I tried to tackle with that problem. :)And to solve this I would just do a collision cast over a small amount of time when starting to fall down. :)
#13
There will be a performance hit because there is more objects in the collision system, but it will not be "significant." TGB does a good job of quickly culling objects that won't be involved in particular collisions. Also, triggers completely skip the collision resolution step.
06/27/2006 (10:21 am)
Quote:Nope. Triggers are scene objects just like anything else in a TGB scene. Thus, they can define a custom collision poly.
AFAIK triggers are limited to rectangular areas, aren't they?
Quote:Not really. If you do it procedurally instead of in the level builder it would actually be pretty easy. In the onLevelLoaded method for your tile layer, iterate over the tiles and create a trigger over each one that has collision enabled. You could get fancy with a little extra work and contain connected tiles with collision in one trigger.
It'll be a pain in the ass to cover each tile with a trigger...
There will be a performance hit because there is more objects in the collision system, but it will not be "significant." TGB does a good job of quickly culling objects that won't be involved in particular collisions. Also, triggers completely skip the collision resolution step.
#14
Thanks
Le Roi
06/27/2006 (1:21 pm)
Hi thanks for clearing that up , could you prob. post some sample code or send us in the right direction with regards to documentation on triggers ?Thanks
Le Roi
#15
06/27/2006 (1:31 pm)
I second Le Roi. I'd love to see this working in code not only in ideas...
#16
On a Player::update() method called by t2dSceneGraph::onUpdateScene, I do:
if (!%this.collidingOld)
%this.colliding = false;
%this.collidingOld = false;
Then, in Player::onCollide(...) I do:
function Player::onCollide(..)
{
// prerequisite: anything the player collides with, is a "platform", part of the level
%this.collidingOld = true;
if (getWord(%collisionNormal, 1) >= 0 || %this.colliding)
{
%this.colliding = true;
%this.setCollisionCancel(true);
return;
}
... rest if the code ...
}
06/28/2006 (12:23 am)
Ok, I've resolved the falling-when-still-colliding-with-platform thing, pretty easily. Adding a couple of boolean members to my player object, "colliding" and "collidingOld". I know, pretty bad names.On a Player::update() method called by t2dSceneGraph::onUpdateScene, I do:
if (!%this.collidingOld)
%this.colliding = false;
%this.collidingOld = false;
Then, in Player::onCollide(...) I do:
function Player::onCollide(..)
{
// prerequisite: anything the player collides with, is a "platform", part of the level
%this.collidingOld = true;
if (getWord(%collisionNormal, 1) >= 0 || %this.colliding)
{
%this.colliding = true;
%this.setCollisionCancel(true);
return;
}
... rest if the code ...
}
#17
Quick Question - When the player is jumping and he collides with the left or right side of the platform , how can I check and disable collisions for that as well ?
Thanks
Le Roi
06/28/2006 (2:49 am)
THANKS !!! - IT WORKS LIKE A BOMB !!! , I'll try the triggers out as well , but for now this works !!!Quick Question - When the player is jumping and he collides with the left or right side of the platform , how can I check and disable collisions for that as well ?
Thanks
Le Roi
#18
I should add, I am not suggesting that this is a better solution than Tom's. His is obviously much more elegant. But it is the best script only implementation I can think of.
I don't have time at the moment to write up a decent trigger doc, but take a look at the code in this resource, and you'll see, they're pretty simple to use.
06/28/2006 (9:10 pm)
Alright, resource posted on TDN on how to use triggers as a script only solution to this problem. Link here.I should add, I am not suggesting that this is a better solution than Tom's. His is obviously much more elegant. But it is the best script only implementation I can think of.
I don't have time at the moment to write up a decent trigger doc, but take a look at the code in this resource, and you'll see, they're pretty simple to use.
#19
06/29/2006 (12:18 am)
Thanks Adam , checking it out now
#20
getWord(%normal,0) <0 works but then I fall through the base layer ?
Thanks
Le Roi
06/29/2006 (2:12 pm)
I can't seem to get the triggers to work on my tilelayer that I extract from a tilemap proceduraly , anyways , has anyone figured out how to get it to work if I jump and collide with the platform from the right , getWord(%normal,0) <0 works but then I fall through the base layer ?
Thanks
Le Roi
Torque Owner Manuel F. Lara