Game Development Community

Simple Character Physics

by Seth Willits · in Torque Game Builder · 03/05/2005 (4:01 pm) · 14 replies

I'm accustomed to doing things a bit differently than in T2D, so I'm wonder how you go about adding typical character movement using acceleration. From a stand still the character can accelerate to a walk, if a certain key is held then it accelerates to a run, release the movement key and it slows to a halt. Press the key in the opposite direction while moving and the character screeches until it slows to a stop then begins accelerating the opposite direction. Stuff that guys back in the 80s knew and I still don't. :^)

I thought constant force or impulse force might be used here as well as maximum velocity (and possibly friction), but using the force methods I can't seem to get the character to move at all. Hopefully someone can just give me a couple of quick pointers while I'm trying to figure this out on my own.

#2
03/05/2005 (4:20 pm)
The code in that post just uses on/off velocity, not acceleration. Unless there's more than meets the eye?
#3
03/05/2005 (4:21 pm)
The only thing i can think of is using a lot of conditional statements to check for certain actions.

I know there is a function to detect keypress but I don't remember it off the top of my head. But if someone else remembers it I would just do a loop during that time to gradually reduce or excel the whole
$player.setLinearVelocityX(-20);

As far as changing directions and speed you could add a variable that you set to true or false and put it in whatever function you created for player move left.


So lets say when you press the left button you set the variable to
$moveleft=0

So when you press the right key you do and if statement to check the status of that variable. in psudo:
If moveleft=0 then
function for player screetch animation
function to reduce player speed
moveleft=1
else
moveleft=1

If that helps.

there may be simpler ways of doing things. But I always seem to do things the dificult way anyway.
#4
03/05/2005 (4:24 pm)
Right. The logic part of it is easy. What I don't get is which functions to use to apply the force to create the acceleration. Sorry if I wasn't clear.
#5
03/05/2005 (4:25 pm)
@Seth: Perhaps you could run a loop while a key is pressed that uncreases velocity up to where you want it and leaves it there until acted upon by something else of course. Not very pretty, but I'm still struggling through figuring stuff out.
#6
03/05/2005 (4:28 pm)
Thats where I was going Matt.

There is a callback of sorts that tells when a button is being pushed. I replied to a post about it. And IT MAY be in the code snipet for double jump but you could just put a condition in there that says when X is being pushed raise players veloctiy.

I will post the function when i dig through all the posts that I made
#7
03/05/2005 (4:35 pm)
I'm not at all sure if this is what you need, but here's the code for player movement in Cloudburst:

function applyVelUp()
{
	$player.setImpulseForce ("0 -" @ $playerMovementRate, true) ;
	$applyVelUp = schedule ($velTime, 0, "applyVelUp") ;		
}

function applyVelDown()
{
	$player.setImpulseForce ("0 " @ $playerMovementRate, true) ;
	$applyVelDown = schedule ($velTime, 0, "applyVelDown") ;		
}

function applyVelLeft()
{
	$player.setImpulseForce ("-" @ $playerMovementRate @ " 0", true) ;
	$applyVelLeft = schedule ($velTime, 0, "applyVelLeft") ;		
}

function applyVelRight()
{
	$player.setImpulseForce ($playerMovementRate @ " 0", true) ;
	$applyVelRight = schedule ($velTime, 0, "applyVelRight") ;		
}


function PlayerMove (%dir, %on)
{
	if ($playerDead || $paused)
	  return ;
	if (%on) {
		%anim = "" ;
		
		switch (%dir) {
			 case 1: // up
			   %anim = "animPlayerShipUp" ;
			   $applyVelUp = schedule ($velTime, 0, "applyVelUp") ;		
			 case 2: // down
			   %anim = "animPlayerShipDown" ;
			 	 $applyVelDown = schedule ($velTime, 0, "applyVelDown") ;		
			 case 3: // left
				 $applyVelLeft = schedule ($velTime, 0, "applyVelLeft") ;		
			 case 4: // right
			   $applyVelRight = schedule (%velTime, 0, "applyVelRight") ;		
		}
		if (%anim !$= "") {
		  $player.playAnimation( %anim, false);
		 }

	} else {
		switch (%dir) {
			case 1: // up
			  cancel ($applyVelUp) ;
			  $player.playAnimation( "animplayershipidle", false);
			case 2: // down
			  cancel ($applyVelDown) ;
			  $player.playAnimation( "animplayershipidle", false);
			case 3: // left
			  cancel ($applyVelLeft) ;
			case 4: // right
			  cancel ($applyVelRight) ;
		}	  
	}
}

And here's what happens with the key bindings:

playerMap.bindCmd(keyboard, "up", "playerMove(1, 1);", "playerMove(1, 0);");
	playerMap.bindCmd(keyboard, "down", "playerMove(2, 1);", "playerMove(2, 0);");
	playerMap.bindCmd(keyboard, "left", "playerMove(3, 1);", "playerMove(3, 0);");	
	playerMap.bindCmd(keyboard, "right", "playerMove(4, 1);", "playerMove(4, 0);");

Here's how it works: When you press and hold a key, the playerMove() function gets invoked with a direction number and status flag of on/off. It starts a timer that then begins to add impulse force to the player object in the appropriate direction. This scheduled task then repeats endlessly, as long as you hold down the key. When you release it, however, playerMove() gets called with that direction turned off. Which then cancels the task.

The animation code also banks the ship either up or down, depending on which movement type is being engaged. I had to modify T2D a bit, so it holds the last frame when a non-cycled animation completes, so this effect won't look right on an out-of-the-box T2D.

$playerMovementRate adjusts how much velocity is applied per tick, and $velTime is how many times per second to apply that velocity. The player object has damping set on, so if you start moving and then let go of the keys, it will slow down on its own.
#8
03/05/2005 (4:47 pm)
So it looks like setImpulseForce has to be called repeatedly, not just once? Maybe that's what it was. I was doing it once, but it seems weird to do it multiple times.

It looks like there's a typo in your code. Case 4 for when applying the velocity has %velTime rather than $velTime. I don't know if that makes a difference in your code, but it's different than the others.

Thanks David. I'll report back...
#9
03/05/2005 (8:20 pm)
Thanks to Noolness in the IRC room I figured out that the value I was passing to setImpulseForce and setConstantForce when I tried them were way too small so it seemed like nothing was happening.
#10
03/05/2005 (11:10 pm)
Seth, yep... as you can see in some of the example code Melv or I have posted, you sometimes have to use seeming large numbers for your impulse forces.

Note that for player movement, if you want just simple movement, you could of course also just do $player.setLinearVelocity += (10 + $player.getLinearVelocity) (or whatever values you want). Then you can set whatever values you want for maxLinearVelocity, or straight check it in your code.
#11
03/05/2005 (11:19 pm)
Yeah, but that's too cheesy ;)

Right now I have acceleration left & right working ok. Jumping is half ok (jumps too high - fiddling with the numbers is tedious) and I'm working on getting the collision response working correctly.

player.cs
scene.cs
datablocks.cs

The rigid body response is cool, but when the player hits the ground, he spins of and lands on his head :)
#12
03/06/2005 (12:25 am)
On the up side you just made the first T2D break dancing game ;)
#13
03/06/2005 (1:50 am)
@Seth: You can use "setMaxAngularVelocity(0)" to stop the player rotating due to rigid-body response.

- Melv.
#14
03/06/2005 (2:07 am)
@Matthew: hehehehe

@Melv: Thanks. That's a good tip! When I've fiddled a bit more with it, I'll post with better specifics & questions (hopefully answers!) on getting jumping and direction transitioning.