Problem with platformer wall collision when jumping
by Adam McDonald · in Torque Game Builder · 02/25/2012 (12:36 pm) · 5 replies
I have been building a platformer using the TDN Platformer Tutorial as a foundation. I have found that it is solid overall, but I have had a couple of problems with the the way it handles collision with walls when jumping.
1. If I am holding left or right against a wall, my character will frequently stop short when jumping. I thought maybe this was a physic-based problem, so I turned off all physics on both objects and it still happens.
2. If issue 1 does not happen, and the character clears the height of the wall, the character will not continue in the direction being held down. This can be avoided by simply jumping straight up and then pressing the direction in mid-air once the wall has been cleared, but forcing players to do this is not very intuitive. As a player, I would find it unacceptable.
If anyone has any ideas on how to fix these issues please let me know. I have made a lot of changes to the platformer tutorial scripts, but I have left the onUpdateVertical function essentially untouched.
1. If I am holding left or right against a wall, my character will frequently stop short when jumping. I thought maybe this was a physic-based problem, so I turned off all physics on both objects and it still happens.
2. If issue 1 does not happen, and the character clears the height of the wall, the character will not continue in the direction being held down. This can be avoided by simply jumping straight up and then pressing the direction in mid-air once the wall has been cleared, but forcing players to do this is not very intuitive. As a player, I would find it unacceptable.
If anyone has any ideas on how to fix these issues please let me know. I have made a lot of changes to the platformer tutorial scripts, but I have left the onUpdateVertical function essentially untouched.
function playerClass::updateVertical(%this)
{
%yVelocity = %this.getLinearVelocityY();
%this.setLinearVelocityY(5);
%collision = %this.castCollision(0.005);
%normalX = getWord(%collision, 4);
%normalY = getWord(%collision, 5);
// no collision
if (%collision $= "")
{
%this.airborne = true;
%this.setConstantForceY(100);
%this.setLinearVelocityY(%yVelocity);
return;
}
// collides with wall to the left
if (%normalX == 1 && %normalY == 0)
{
%this.againstLeftWall = true;
%this.setLinearVelocityX(0);
%this.setLinearVelocityY(%yVelocity);
return;
}
// collides with wall to the right
if (%normalX == -1 && %normalY == 0)
{
%this.againstRightWall = true;
%this.setLinearVelocityX(0);
%this.setLinearVelocityY(%yVelocity);
return;
}
// on ground with no wall collisions
if (%normalX == 0 && %normalY == -1)
{
%this.airborne = false;
%this.againstLeftWall = false;
%this.againstRightWall = false;
%this.setConstantForceY(0);
%this.setLinearVelocityY(%yVelocity);
return;
}
// in air and hits platform with head
if (%normalY == 1)
{
%this.airborne = true;
%this.setLinearVelocityX(0);
%this.setConstantForceY(100);
%this.setLinearVelocityY(%yVelocity);
return;
}
// in case another type of collision normal was detected
error("another collison type" SPC %normalX SPC %normalY);
%this.airborne = false;
%this.againstLeftWall = false;
%this.againstRightWall = false;
%this.setLinearVelocityY(%yVelocity);
}About the author
#2
My code for my character is fairly complex and convoluted based on my game design (character can change to 6 different colours and either sticks to, is repelled by, passes through or collides normally with objects of different colours depending on what colour the character is). I put the basic tutorial code in my original post to avoid having too many variables nobody would have any frame of reference for. Anyway, here's the updates horizontal and vertical with some other stuff to make it make sense.
The control function is used to take control from the player for a moment when they repel off an object, to prevent the user from just mashing up against it.
03/18/2012 (9:51 pm)
Thanks for the reply. I hadn't touched my code since you posted, but I tried what you did for no collision and it seems to have worked. Thinking back, I didn't always have the first problem (since I recall distinctly trying to solve the second problem independent of it). My code for my character is fairly complex and convoluted based on my game design (character can change to 6 different colours and either sticks to, is repelled by, passes through or collides normally with objects of different colours depending on what colour the character is). I put the basic tutorial code in my original post to avoid having too many variables nobody would have any frame of reference for. Anyway, here's the updates horizontal and vertical with some other stuff to make it make sense.
function playerClass::updateHorizontal(%this)
{
if($player.getLinearVelocityX() < 2)
{
if($player.getLinearVelocityX() > -2)
{
$player.setLinearVelocityX(0);
}
}
if(!%this.airborne)
{
if(%this.moveLeft == %this.moveRight)
{
$player.setLinearVelocityX(0);
}
}
if (%this.moveLeft)
{
if (!%this.moveRight)
{
if (!%this.againstLeftWall)
{
%this.againstRightWall = true;
if(%this.control)
{
%this.setLinearVelocityX(%this.xMoveLeft);
}
}
}
}
if (%this.moveRight)
{
if (!%this.moveLeft)
{
if (!%this.againstRightWall)
{
%this.againstLeftWall = true;
if(%this.control)
{
%this.setLinearVelocityX(%this.xMoveRight);
}
}
}
}
if (%this.moveUp)
{
if (!%this.airborne)
{
%this.setLinearVelocityY(-20);
}
}
if (%this.moveDown)
{
if (!%this.airborne)
{
%this.setLinearVelocityY(20);
}
}
if(!%this.airborne)
{
if($inStick)
{
if(!%this.airborne)
{
if(%this.moveUp == %this.moveDown)
{
$player.setLinearVelocityY(0);
}
}
}
}
}
function playerClass::updateVertical(%this)
{
%xVelocity = %this.getLinearVelocityX();
%yVelocity = %this.getLinearVelocityY();
%this.setLinearVelocityY(5);
%collision = %this.castCollision(0.004);
%normalX = getWord(%collision, 4);
%normalY = getWord(%collision, 5);
//no collision
if (%normalX == 0 && %normalY == 0)
{
%this.airborne = %this.noColAir;
%this.againstLeftWall = false;
%this.againstRightWall = false;
%this.setConstantForceY(%this.noColConY);
%this.setLinearVelocityY(%yVelocity);
%this.setLinearVelocityX(%xVelocity);
return;
}
// collides with wall to the left
if (%normalX == 1 && %normalY == 0)
{
%this.againstLeftWall = true;
%this.setLinearVelocityX(%this.xLeft);
%this.setLinearVelocityY(%this.leftY);
return;
}
// collides with wall to the right
if (%normalX == -1 && %normalY == 0)
{
%this.againstRightWall = true;
%this.setLinearVelocityX(%this.xRight);
%this.setLinearVelocityY(%this.rightY);
return;
}
// on ground with no wall collisions
if (%normalX == 0 && %normalY == -1)
{
%this.airborne = %this.bottomAir;
%this.againstLeftWall = false;
%this.againstRightWall = false;
%this.setConstantForceY(%this.bottomConY);
%this.setLinearVelocityY(%this.bottomY);
return;
}
// in air and hits platform with head
if (%normalX == 0 && %normalY == 1)
{
%this.airborne = %this.topAir;
%this.setLinearVelocityX(0);
%this.setConstantForceY(%this.topConY);
%this.setLinearVelocityY(%this.topY);
return;
}
}
function playerClass::onUpdate(%this)
{
%this.updateHorizontal();
%this.updateVertical();
%this.onCollision();
%this.setCurrentAnimation();
%this.controlTimer();
%this.resetThings();
}
function playerClass::controlTimer(%this)
{
if(!$player.control)
{
%this.schedule(250, "returnControl");
}
}
function playerClass::returnControl(%this)
{
%this.control = true;
}
function playerClass::resetThings(%this)
{
if(%this.control)
{
%this.xLeft = 0;
%this.xRight = 0;
}
}The control function is used to take control from the player for a moment when they repel off an object, to prevent the user from just mashing up against it.
#3
I've been messing with this a lot, and turning off my moveRight/moveLeft functions in my onUpdateVertical when the character is touching the respective walls provides me with a slightly better result than where I started (no rubbing/hugging on walls, but once the character makes it above the wall it won't keep moving in that direction unless I release the directional key and press it again). I'm trying to wrap my head around other possible solutions, since this one feels hacky and doesn't quite work. For some reason using againstRightWall/againstLeftWall being false as a condition for moving in the respective direction doesn't help at all.
03/21/2012 (1:07 am)
Ok, so I commented out my slightly more convoluted onUpdateHorizontal and replaced it with the one you posted and I still see the same issue. Since fixing the second issue it now occurs 100% of the time... the best way I can describe it is that the character seems to "hug" walls if you press against them. Basically stops if you're moving up or slows down if you're moving down. I want it to ignore the wall completely until it clears it.I've been messing with this a lot, and turning off my moveRight/moveLeft functions in my onUpdateVertical when the character is touching the respective walls provides me with a slightly better result than where I started (no rubbing/hugging on walls, but once the character makes it above the wall it won't keep moving in that direction unless I release the directional key and press it again). I'm trying to wrap my head around other possible solutions, since this one feels hacky and doesn't quite work. For some reason using againstRightWall/againstLeftWall being false as a condition for moving in the respective direction doesn't help at all.
#4
Basically, the variables being called in the collision functions were being set when the character actually touched the object, not when the cast collision detected the object. That was screwing things up. If I replace the variables with static numbers that fixes this issue, but causes others. What I'm going to do now is use triggers to set the variables appropriately before the character detects the object.
I really doubt this will come up for anyone else unless you have conditional collision variables like me, but you never know...
04/01/2012 (12:11 am)
Ok, doesn't seem like anyone is following this thread but just in case someone runs into the same problem one day...Basically, the variables being called in the collision functions were being set when the character actually touched the object, not when the cast collision detected the object. That was screwing things up. If I replace the variables with static numbers that fixes this issue, but causes others. What I'm going to do now is use triggers to set the variables appropriately before the character detects the object.
I really doubt this will come up for anyone else unless you have conditional collision variables like me, but you never know...
#5
Basically, when you hold left or right against a wall and press jump, the player jumps higher than normal/expected. This happens specifically whn adding in the code:
If I leave out:
Any ideas?
-Drew
[]I own TGB on another account, which can be verified.[]
07/21/2012 (10:58 am)
Adam, I'm having a similar problem, and I'm interested to see how you've perfected your platforming movement. Basically, when you hold left or right against a wall and press jump, the player jumps higher than normal/expected. This happens specifically whn adding in the code:
// no collision
if(%collision $= "")
{
%this.againstleftWall = false;
%this.againstRightWall = false;
%this.inAir = true;
%this.setConstantForceY($gravity);
%this.setLinearVelocityY(%tempY);
return;
}If I leave out:
%this.againstleftWall = false; %this.againstRightWall = false;it will stop at the correct jump height but will not continue moving in the direction being held down.
Any ideas?
-Drew
[]I own TGB on another account, which can be verified.[]
Torque Owner Bryce Fosheim
Caffeinated Hearts
Anyway, the only change I did to the updateVertical function is in the "no collision" block.
You have the following:
// no collision if (%collision $= "") { %this.airborne = true; %this.setConstantForceY(100); %this.setLinearVelocityY(%yVelocity); return; }Mine is this:
// no collision if (%collision $= "") { %this.againstLeftWall = false; %this.againstRightWall = false; %this.airborne = true; %this.setConstantForceY(100); %this.setLinearVelocityY(%yVelocity); return; }I compared our functions and that was the only change in that function. I'm not sure if I have something different in my updateHorizontal function. I'll post it here for you though.
function Player::updateHorizontal(%this) { if(%this.moveLeft == %this.moveRight) { %this.setLinearVelocityX(0); return; } if(%this.moveLeft) { if(!%this.againstLeftWall) { %this.againstRightWall = false; %this.setLinearVelocityX(-90); } } if(%this.moveRight) { if(!%this.againstRightWall) { %this.againstLeftWall = false; %this.setLinearVelocityX(90); } } }If you see anything different between yours and mine let me know, cause my curiosity is piqued.