Trouble with Jump Physics
by Daniel Balmert · in Torque Game Builder · 08/08/2006 (7:42 pm) · 12 replies
Quick overview of my project: 2d sidescrolling with enemies and, of course, jumping. Needs to have some way for all the objects to make its way to the ground while still being able to move
I realize that you can't just set the constant Y force to 10 and be done with jumping physics. You need to have it turn off when you're on the ground, but also have it turn ON when you leave the ground in ways other than jumping (running off ledges, ledges changing position etc.)
My question is, how do you solve this problem? Objects have no way to know if they're "in the air" or not. I've heard you can use castcollision() to some degree, but I have problems that need to be worked around:
* The player will collide with many things other than the ground. This includes enemies, their projectiles, moving walls and lots of other things.
* If I CastCollision() and I don't grab the right collision (it might grab a projectile or somethign else), I'll have suspended gravity until you jump agian.
* If I CastCollisionList(), I'm not at all sure how to parse it to see if it's colliding with ground and not, say, a bullet.
Could I change the "::onCollision()" callback in the engine (working with C++) to make it so I COULD leave the constant force on?
I'm sorry to ask so many questions, but the documentation seems vague to me. I've read all the collision methods for scene objects and I can't wrap my brain around a way to give my objects a way to know for absolute sure that they are in the air.
It would be easy if there were an "::onNoCollision" callback.... or is there? I haven't quite figured out if the collision mode "CUSTOM" will hold the answer to my problem.
The way I see it, if I add a million calls to "castCollision()" every tick, I'm severely hindering processor speeds.
Any help on this subject would be helpful.
I realize that you can't just set the constant Y force to 10 and be done with jumping physics. You need to have it turn off when you're on the ground, but also have it turn ON when you leave the ground in ways other than jumping (running off ledges, ledges changing position etc.)
My question is, how do you solve this problem? Objects have no way to know if they're "in the air" or not. I've heard you can use castcollision() to some degree, but I have problems that need to be worked around:
* The player will collide with many things other than the ground. This includes enemies, their projectiles, moving walls and lots of other things.
* If I CastCollision() and I don't grab the right collision (it might grab a projectile or somethign else), I'll have suspended gravity until you jump agian.
* If I CastCollisionList(), I'm not at all sure how to parse it to see if it's colliding with ground and not, say, a bullet.
Could I change the "::onCollision()" callback in the engine (working with C++) to make it so I COULD leave the constant force on?
I'm sorry to ask so many questions, but the documentation seems vague to me. I've read all the collision methods for scene objects and I can't wrap my brain around a way to give my objects a way to know for absolute sure that they are in the air.
It would be easy if there were an "::onNoCollision" callback.... or is there? I haven't quite figured out if the collision mode "CUSTOM" will hold the answer to my problem.
The way I see it, if I add a million calls to "castCollision()" every tick, I'm severely hindering processor speeds.
Any help on this subject would be helpful.
#2
and then when the player is colliding with the floor, use "$player.stopConstantForce()".
08/09/2006 (3:06 am)
Another way you could do it is messing with the impulse command. I've explained a way in this post. If you really want to turn gravity off, then you could do something like:<when jump key is pressed> $player.setImpluse(); $player.setConstantForceY();
and then when the player is colliding with the floor, use "$player.stopConstantForce()".
#3
@Apurva - I have no trouble getting the force to work with jumps. That's the easy part. The hard part is making it so that when the ground moves or when the player runs off the edge, the gravity turns back ON. If you keep all of the gravity code in the jump function, then it will ONLY change if you jump and only turn off if you collide when jumping.
For example, if I run off the edge and there's nothing below me, the gravity will still be off because i never turned it on by jumping. That's why I'm saying that I need some way to check that the object has become airborn - for many reasons OTHER than jumping.
08/09/2006 (7:08 am)
@Luke - The reason I don't leave the constant force on is because if the sprite is at rest, it bobs up and down jittering, or worse even in slowly burrows INTO the surface of the object it's sitting on. Try doing the collision demo in the documentation. Make a block with collision and have the rock fall and stay there (no horizontal movement). It bobs up and down violently before beginning to go below the collision poly. The constant force and collision detection don't seem to work together well at all :( I had thought of the trigger idea, but I really have to keep the processor cleared - I plan on putting lots of objects on the screen. Having a trigger on every tile space would eat up processing time. It'd be easier to implement a "::hasNOTcollided" callback in the source (i hope). I'll have to run to the C++ forum and ask about how to do that... Perhaps I can set up soom booleans to stop redundant collision detection.@Apurva - I have no trouble getting the force to work with jumps. That's the easy part. The hard part is making it so that when the ground moves or when the player runs off the edge, the gravity turns back ON. If you keep all of the gravity code in the jump function, then it will ONLY change if you jump and only turn off if you collide when jumping.
For example, if I run off the edge and there's nothing below me, the gravity will still be off because i never turned it on by jumping. That's why I'm saying that I need some way to check that the object has become airborn - for many reasons OTHER than jumping.
#4
If your response is set to rigid, it may or may not work.
I remember trying to find out how to do a "hasNotcollided" check as well, but never got round to finding out a way.
As for triggers, there's no need for it to be on every tile. When making levels, you could just put it on the edge tile so it will significantly cut down the number of triggers.
08/09/2006 (7:51 am)
The bobbing situation can often be fixed by increasing the max collision iterations, especially if your collision response is set to clamp. Try putting it to 2 (or more if required, but I found 2 to work fine):$player.setCollisionMaxIterations(2);
If your response is set to rigid, it may or may not work.
I remember trying to find out how to do a "hasNotcollided" check as well, but never got round to finding out a way.
As for triggers, there's no need for it to be on every tile. When making levels, you could just put it on the edge tile so it will significantly cut down the number of triggers.
#5
Or what if you run off a hill top? depending on your velocity, you ought to become airborn if you go over a hill or bump in the road. Do I have longer triggers across them?
For level building, I want to make somewhat elaborate scenes. If you recall, Super Mario World 2 (Yoshi's Island) has level desgin that hardly looks like tiles. Underneath, I suppose, are tiles with collision, but is it possible to build elaborate and beautiful non-repeating backgrounds and use tiles simply for collision? Is there an easier way to do concave collisions (for dips in level design)?
Also, as an aside question, do these "workarounds" ever actually work in a polished game sense? Every time I think of a solution, some problems crop up and I doubt I could catch all of the exceptions. The global gravity thing seemed like a good workaround, but it has other problems: the gravity keeps building and building if you don't jump, so running off the edge makes you drop like a brick. I suppose I could kep resetting the linearvelocityY onCollision 's, but I fear that slowing down gameplay at later times. Is my fear of slowing gameplay unwaranted or is it a real issue?
Also, does a trigger have an onLeave funtion? I know it has an onEnter.
Thanks a LOT for your responses, Apurva. I'll try the collision max changes later today. that might solve a problem and make me leave the gravity on at all times. Combined with the triggers, I'm not sure which way I would go - turning off and managing the gravity manually (opens gameplay to exploits) or leave the gravity on (slowing down system).
08/09/2006 (8:23 am)
So every edge tile, or tiles that will move (potentially) will need a trigger? That sounds like a better solution actually... But that leads me to other problems. What if an enemy's collision is meant to send you into the air? can you make the enemy class interact with the player class that way? How big do you make the trigger on the edge?Or what if you run off a hill top? depending on your velocity, you ought to become airborn if you go over a hill or bump in the road. Do I have longer triggers across them?
For level building, I want to make somewhat elaborate scenes. If you recall, Super Mario World 2 (Yoshi's Island) has level desgin that hardly looks like tiles. Underneath, I suppose, are tiles with collision, but is it possible to build elaborate and beautiful non-repeating backgrounds and use tiles simply for collision? Is there an easier way to do concave collisions (for dips in level design)?
Also, as an aside question, do these "workarounds" ever actually work in a polished game sense? Every time I think of a solution, some problems crop up and I doubt I could catch all of the exceptions. The global gravity thing seemed like a good workaround, but it has other problems: the gravity keeps building and building if you don't jump, so running off the edge makes you drop like a brick. I suppose I could kep resetting the linearvelocityY onCollision 's, but I fear that slowing down gameplay at later times. Is my fear of slowing gameplay unwaranted or is it a real issue?
Also, does a trigger have an onLeave funtion? I know it has an onEnter.
Thanks a LOT for your responses, Apurva. I'll try the collision max changes later today. that might solve a problem and make me leave the gravity on at all times. Combined with the triggers, I'm not sure which way I would go - turning off and managing the gravity manually (opens gameplay to exploits) or leave the gravity on (slowing down system).
#6
1) When you say send the player in to the air, do you mean like the way mario jumps off the enemies head? The trigger on the edge can be quite thin, but tall. This way, if the player jumps off, rather than run off, they would still hit the trigger. Imagine it being like a wall you can walk through. You need it to be tall enough so that you can't jump over it. The size would depend on your game design, such as how high the player can jump etc..
2) Hmm, this physics situation about running off hill tops does make it a bit more complicated. Although it's possible to place triggers at every bump/hill, it could get tedious. I really recommend you try increasing collisionMaxIterations so that your gravity can be on constantly.
3) Yoshi's Island - This is a very clever way of using tiles. Although they don't look like they're repeating, they are. The reason tiles are used is because the levels are often larger than the levels. However, due to certain limitations, not all computers can load images larger than levels so tiles are used instead. Since tiles are repeated, you can just have one instance of it and keep copy/pasting that to save on video memory. TGB has a great feature for having concave terrain. Simply click on the tile, in the level editor, and then click on "edit collision poly" Then create a collision shape to match the terrain. Don't forget, the tile can be semi-transparent so that you can create hills and things. I give a quick description of how to create collision polys here.
4) Workarounds are prone to having bugs. Usually these bugs can be found and another workaround is used to fix those. However, workarounds are not always 'bad' in the sense that they cannot function properly. It just means you may have to have a lot of checks to ensure that everything is working. Many games use workarounds, and although it's not the best thing to do all the time, as long as it's relatively efficient it should be fine.
5) Yes, triggers to have an onLeave function
6) Your welcome :). Hopefully the iteration solution works so that you don't have to find workarounds, but good luck on your project!
lol I think that covered everything...
08/09/2006 (9:05 am)
I'll try and answer the questions as best I can, but I'm sure other people will have other ideas that could also work.1) When you say send the player in to the air, do you mean like the way mario jumps off the enemies head? The trigger on the edge can be quite thin, but tall. This way, if the player jumps off, rather than run off, they would still hit the trigger. Imagine it being like a wall you can walk through. You need it to be tall enough so that you can't jump over it. The size would depend on your game design, such as how high the player can jump etc..
2) Hmm, this physics situation about running off hill tops does make it a bit more complicated. Although it's possible to place triggers at every bump/hill, it could get tedious. I really recommend you try increasing collisionMaxIterations so that your gravity can be on constantly.
3) Yoshi's Island - This is a very clever way of using tiles. Although they don't look like they're repeating, they are. The reason tiles are used is because the levels are often larger than the levels. However, due to certain limitations, not all computers can load images larger than levels so tiles are used instead. Since tiles are repeated, you can just have one instance of it and keep copy/pasting that to save on video memory. TGB has a great feature for having concave terrain. Simply click on the tile, in the level editor, and then click on "edit collision poly" Then create a collision shape to match the terrain. Don't forget, the tile can be semi-transparent so that you can create hills and things. I give a quick description of how to create collision polys here.
4) Workarounds are prone to having bugs. Usually these bugs can be found and another workaround is used to fix those. However, workarounds are not always 'bad' in the sense that they cannot function properly. It just means you may have to have a lot of checks to ensure that everything is working. Many games use workarounds, and although it's not the best thing to do all the time, as long as it's relatively efficient it should be fine.
5) Yes, triggers to have an onLeave function
6) Your welcome :). Hopefully the iteration solution works so that you don't have to find workarounds, but good luck on your project!
lol I think that covered everything...
#7
And I tried making a collision poly follow a slope; it can't go concave. Now, this was for a large imagemap, NOT a tile exactly. I was trying to stay away from too much tiling. Are there any good sources for good looking tiles? Because quite frankly the demo tiles look hideous. For example, how can I make some large tiles while still having smaller tiles? I know you can make a bunch of little tiles that have convex polys that combine to make what appears to be a concave poly. Is this the ONLY workaround? or could TGB support convex colisions?
I'm crossing my fingers that the iteration solution works... If it does work, why? Is it just telling it to check the collision twice before doing anything? is it telling the engine to be more
08/09/2006 (9:59 am)
What I meant by "enemy collision" is if the enemy swing a club at you, I want that to send the player into the air, like a golf swing. That would be setting an impulse on a polar coordinate. Can you have an object (enemy.cs) give an impulse to a player(player.cs)? How does this work? I know the player is global, but can I make references to that in an entirely seperate file? I'm not sure I understand the scope of these variables.And I tried making a collision poly follow a slope; it can't go concave. Now, this was for a large imagemap, NOT a tile exactly. I was trying to stay away from too much tiling. Are there any good sources for good looking tiles? Because quite frankly the demo tiles look hideous. For example, how can I make some large tiles while still having smaller tiles? I know you can make a bunch of little tiles that have convex polys that combine to make what appears to be a concave poly. Is this the ONLY workaround? or could TGB support convex colisions?
I'm crossing my fingers that the iteration solution works... If it does work, why? Is it just telling it to check the collision twice before doing anything? is it telling the engine to be more
#8
eg
That's a simple explanation of how local variables work.
For good looking tiles, your going to have to ask an artist. I haven't really worked with tiles. At the moment, TGB doesn't support concave collisions.
The collision iteration is effectively updating the position more times per tick. This makes it more accurate, but requires a more CPU. However, having maxiterations of 2 isn't going to put much strain on a CPU.
08/09/2006 (10:53 am)
Yes, if the objects are in different files, they can still be accessed as long as they are declared global ($). Local variables (%) are only valid in the bracket scope they're assigned to.eg
function myClass::onCollision(%srcObj, %dstObj etc...) { //note the start of the brace
echo(%srcObj); //local variable can be accessed since it's within the brace boundary
} //end brace. Here the local variable will lose it's value and cannot be accessed by anything outside this functionThat's a simple explanation of how local variables work.
For good looking tiles, your going to have to ask an artist. I haven't really worked with tiles. At the moment, TGB doesn't support concave collisions.
The collision iteration is effectively updating the position more times per tick. This makes it more accurate, but requires a more CPU. However, having maxiterations of 2 isn't going to put much strain on a CPU.
#9
in your code example, if I had a $player of class player, would I set an impulse and turn on the constant force as if it were in the same .cs file? $player.setconstantforcewhateverY(10)
Since $player is global, can it be grabbed and used in that function?
08/09/2006 (11:05 am)
I am an artist myself, I'm just unsure how to implement tiling on a larger scale than 1x1. Having all tiles the same would make it look like lego world. I want the ares to feel organic, and as such they should have contrasting sizes of elements.in your code example, if I had a $player of class player, would I set an impulse and turn on the constant force as if it were in the same .cs file? $player.setconstantforcewhateverY(10)
Since $player is global, can it be grabbed and used in that function?
#11
The trick is making tiles that loop into themselves :( that's a tricky thing to make look right.
08/09/2006 (11:22 am)
Those tile examples were great. I will look more closely and try to devise a similar plan of attack. I loved Rayman too!The trick is making tiles that loop into themselves :( that's a tricky thing to make look right.
#12
When the player collides with the platform, sometimes (not all the time) the horixzontal movement stops.
I think I have an idea of how it's happening, but I don't know how to fix it. See, I have a timer (25 milliseconds) which updates my player's speed to accelerate and decelerate based on key inputs. The problem is, I'm simply adding set amounts of velocity. So I do something like I set the players velocity to its current velocity +5 if you press right, -5 if you press left. I have it all working perfectly. However, when the object collides, it stops the object's horizontal movement. If before I'm travelling 80 and I hit the ground, I'm travelling 0... and with my accelerated movement it goes to +5 all the way back up to its max.
I wish I knew how to use the ::onCollision callback correctly. If I could, I would store a variable in my 25 millisecond timer and ::onCollision I would restore the rightful velocity of the player.
Can anyone help me with this? Or am I completely wrong about the source of the problem?
08/09/2006 (2:58 pm)
I added the constant force. but a huge problem just popped up:When the player collides with the platform, sometimes (not all the time) the horixzontal movement stops.
I think I have an idea of how it's happening, but I don't know how to fix it. See, I have a timer (25 milliseconds) which updates my player's speed to accelerate and decelerate based on key inputs. The problem is, I'm simply adding set amounts of velocity. So I do something like I set the players velocity to its current velocity +5 if you press right, -5 if you press left. I have it all working perfectly. However, when the object collides, it stops the object's horizontal movement. If before I'm travelling 80 and I hit the ground, I'm travelling 0... and with my accelerated movement it goes to +5 all the way back up to its max.
I wish I knew how to use the ::onCollision callback correctly. If I could, I would store a variable in my 25 millisecond timer and ::onCollision I would restore the rightful velocity of the player.
Can anyone help me with this? Or am I completely wrong about the source of the problem?
Torque Owner Luke Larson
Second, the way I get around having objects leaving a collision area is by using triggers. Make triggers on every object where each is moved slightly up a bit to ensure that it is collided with when you are on the platform. Now you can use the onEnter command for the trigger to take the force off and the onEnter command to turn it back on. Of course I see this as kind of a hack but it works without issue and is easy to implement.