Game Development Community

Platformer physics and triggers

by baylor wetzel · in Torque Game Builder · 05/31/2007 (2:43 pm) · 3 replies

One of my students is using the mini-platformer tutorial as the base for his own platformer. In that tutorial, castCollision is used to detect when the player is on the ground. If he is not, he is airborne. The airborne flag controls animations, whether the object is falling and whether it can jump

He added a trigger. Moving through it starts the monster spawner. What i hadn't realized is that triggers send collisions (even when you uncheck send/receive collisions). So while he is in the trigger, castCollision returns that he is colliding, which affects his animation and ability to jump. Currently, he is always seen as standing so he can stand in midair. i "fixed" this by ignoring collisions with the trigger but, since castCollision only returns the first object and the first object is always the trigger, he can no longer tell if he's colliding with the ground and so he always looks like he's free falling. It's funny to see but not very helpful

i imagine there is another way to do this but i'm not sure what that way would be. i'd appreciate any pointers to other techniques of functions i should learn about that might help here

btw, this is in version 1.1.3

#1
05/31/2007 (2:49 pm)
I think I read your post backwards ...

So I looked over the code and I would do the following ..

Change (in playerClass::updateVertical):

if(%collision $= "")
{
          %this.airborne = true;
          %this.setConstantForceY(100);
}

To:

if(%collision $= "" || %collision $= "NAMEOFTRIGGEROBJECT")
{
          %this.airborne = true;
          %this.setConstantForceY(100);

}

This change should allow you to fall through trigger and not get stuck in the air.

Although this might cause a problem where you fall through the ground if your in the trigger ... might need a little testing and tweaking.

*EDIT*

I don't know if this it the way you "fixed" it or not, so I posted it anyway.
#2
05/31/2007 (3:30 pm)
Well my idea there didn't work.

It gave me a totally unexpected result.

When I hit the trigger I get stuck, if I'm moving or jumping into it, but If I'm falling and go through it then it works fine.

So maybe it's not a total crap idea, but it will need a little more work.
#3
06/09/2007 (12:49 am)
You can set the group mask when you cast collisions so it doesn't include the group that the trigger is in (assuming you put the triggers and platforms in different groups).

I'm not sure which version you're using, but here's a pruned version of the same game with added support to fix your problem. Just leave everything you want the player to check against in group 0 and put triggers in group 1 or higher ("Group" in the Scene Object rollout on the Edit tab). Note the get and set collision mask calls in the physics update method.

function playerClass::onLevelLoaded( %this, %scenegraph )
{
   %scenegraph.player = %this;
   
   moveMap.bindCmd( keyboard, "left", %this @ ".moveLeft( 1 );", %this @ ".moveLeft( 0 );" );
   moveMap.bindCmd( keyboard, "right", %this @ ".moveRight( 1 );", %this @ ".moveRight( 0 );" );
   moveMap.bindCmd( keyboard, "space", %this @ ".jump();", "" );
   
   %this.moveSpeed = 60;
   %this.setCollisionMaxIterations( 2 );
   SceneWindow2d.mount( %this, "0 0", 20, true );
}

function playerClass::moveLeft( %this, %value )
{
   %this.left = %value;
}

function playerClass::moveRight( %this, %value )
{
   %this.right = %value;
}

function playerClass::jump( %this, %value )
{
   if( !%this.airborne )
      %this.setLinearVelocityY( -225 );
}

function playerClass::updateMovement( %this )
{
   %move = %this.right - %this.left;
   %move *= %this.moveSpeed;
   
   %this.setLinearVelocityX( %move );

   %yVelocity = %this.getLinearVelocityY();
   
   %originalPoly = %this.getCollisionPoly();
   %originalMasks = %this.getCollisionMasks();
   %this.setCollisionPolyCustom( 2, "-0.5 1 0.5 1" );
   %this.setCollisionMasks(BIT(%myPlatformGraphGroup));
   %this.setLinearVelocityY( 100 );
   %collision = %this.castCollision( 0.005 );
   %this.setCollisionPolyCustom( getWordCount( %originalPoly ) / 2,  %originalPoly );
   %this.setCollisionMasks(getWord(%originalMasks, 0));

   %this.setLinearVelocityY( %yVelocity );

   if( %collision !$= "" )
      %this.airborne = false;
   else
      %this.airborne = true;
   
   if( %move < 0 )
      %this.setFlipX( true );
   else if( %move > 0 )
      %this.setFlipX( false );
   
   if( !%this.airborne )
   {
      if( %move != 0 )
      {
         if( %this.getAnimationName() !$= PlayerRun )
            %this.playAnimation( PlayerRun );
      }
      else
         %this.playAnimation( PlayerStand );
   }
   else
   {
      if( %yVelocity < 0 )
         %this.playAnimation( PlayerJumpUp );
      else
         %this.playAnimation( PlayerJumpDown );
   }
}

function PlatformerScene::onUpdateScene( %this )
{
   if( isObject( %this.player) )
      %this.player.updateMovement();
}