Game Development Community

Continious keyboard update

by Maurice Ribble · in Torque Game Builder · 12/14/2006 (8:11 pm) · 8 replies

The basic tutorials I read through had a very simple key command system. They basically did one action when you pressed the key and another action when you released the key. This was done with something like this:

moveMap.bindCmd(keyboard, "up", "playerForward();", "playerForwardStop();");

I need something a little more complex. I have one key that turns a player and another that accelerates a player forward (like in asteroids). The problem is that the player keeps going forward in the direction that he was first pointed and not the continuously rotating direction. Is there is a clean way to handle this with scripts in TGB? If there is no clean way to handle this, is there some function in the scripts that get called every frame which I could use to recalculate this?

#1
12/14/2006 (8:26 pm)
Presumably, what you want is the functions playerForward() and playerForwardStop() to apply forces to the player in the direction they're pointing, rather than a set pair of Axes?

If that's the case, you can just get the foward vector of the ship and apply a force in that direction, inside of the playerForward() function? Then in playerForwardStop, you could zero any forces still acting on the ship?

Gary (-;
#2
12/14/2006 (9:42 pm)
There's a function (I can't recall what exactly) that constrains movement to "forward", which is wherever the sprite/object/actor is facing.
#3
12/15/2006 (3:49 am)
Thanks for the responses, but neither of them address the problem I'm having. They both discuss moving in the direction the ship is headed which I have solved. What I need is to continuously calculate new headings. Here is more code and an example of the problem.

function PlayerShip::onLevelLoaded(%this, %scenegraph)
{
$ShipPlayer = %this;
moveMap.bindCmd(keyboard, "up", "playerForward();", "playerForwardStop();");
moveMap.bindCmd(keyboard, "right", "playerRight();", "playerRightStop();");
}

function playerForward()
{
$ShipPlayer.moveForward = true;
$ShipPlayer.updateMovement();
}

function playerRight()
{
$ShipPlayer.turnRight = true;
$ShipPlayer.updateMovement();
}

function PlayerShip::updateMovement(%this)
{
if(%this.turnRight)
{
$ShipPlayer.setAngularVelocity( 25 );
}

if(%this.moveForward)
{
%angle = %this.getRotation();
%this.setLinearVelocityPolar( %angle, 20 );
}

if(!%this.turnLeft && !%this.turnRight)
{
%this.setAngularVelocity( 0 );
}

if(!%this.moveForward && !%this.moveBackward)
{
%this.setLinearVelocity( 0, 0 );
}
}

I removed the left and backward code to make it smaller. In the future I will need to work on accelerations instead of directly on velocities, but this shows my current problem. Now here is my example.

Lets say my ship is stopped and pointing at 90 degrees (ie along the x axis). Now I press the up and right arrows at the same time. Here is what happens in the physics engine (each line is the next time quantum in the physics engine).
velocity = 0 units at 90 degress, ship orientation is 90 degrees (not moving yet)
velocity = 20 units at 115 degrees, ship orientation is 115 degrees (correct)
velocity = 20 units at 115 degrees, ship orientation is 140 degrees (wrong)
velocity = 20 units at 115 degrees, ship orientation is 165 degrees (more wrong)
velocity = 20 units at 115 degrees, ship orientation is 190 degrees (more wronger)

So the problem is that the ship orientation updates, but its velocity direction does not. If I could get PlayerShip::updateMovement to get called at ever tick of the physics engine the problem would be fixed correctly. If I can't do that then an alternative would be to setup a callback that calls this ever xx ms. Does anyone have any better ideas? I don't have time right now to see if this callback every xx ms is possible in the scripting language, but I'll figure that out this weekend unless someone has a better idea or can tell me this sort of callback is possible?
#4
12/15/2006 (4:03 am)
Like I said, there's a function that sets your velocity based on the sprite/object/actor's facing automatically, which is the very hurdle you're currently trying to overcome. From the reference:

setForwardMovementOnly(%status)
Quote:Purpose
Sets whether or not an object can move only in the direction of its rotation.

Syntax
%status - Bool
True enables forward movement only, false disables it.
setForwardSpeed(%speed)
Quote:Purpose
Applies a linear velocity to the
object in the direction of its rotation.

Syntax
%speed - Float
The magnitude of the velocity.

As for checking the rotation of the ship and updating the velocity vector, assuming you sstill want to do this manually, you'll either use a looping schedule, or you can throw everything into onUpdateScene().
#5
12/15/2006 (5:35 am)
Sorry for my previous mis-understanding.

SetForwardMovementOnly() won't work since I want to be able turn the ship when not applying a forward acceleration and have the ship turn without altering course. I think if I do small increments with setForwardSpeed (ie slowly applying acceleration) and clamp my max speed to something reasonable might work. I'll have to play around with it. If that fails onUpdateScene will allow me to do what I need.

Thanks!
#6
12/15/2006 (1:11 pm)
I have basic asteroid physics implemented in a test game I'm making. It does basically everything you say (turn without altering momentum, incremental acceleration, etc.). If you're interested, here's a copy of my player.cs

function playerShip::onLevelLoaded( %this, %scenegraph ) {
   $player = %this;
   
   worldLimit( $player );
   
   moveMap.bindCmd( keyboard, "left", "playerLeft();", "playerLeftStop();" );
   moveMap.bindCmd( keyboard, "right", "playerRight();", "playerRightStop();" );
   moveMap.bindCmd( keyboard, "up", "playerUp();", "playerUpStop();" );
   moveMap.bindCmd( keyboard, "down", "playerDown();", "playerDownStop();" );
   
   $player.setMaxLinearVelocity( $player.maxSpeed );
   $player.setMinLinearVelocity( -$player.maxSpeed );
}

function playerLeft() {
   $player.setAngularVelocity( -$player.turnSpeed );
}

function playerLeftStop() {
   if( $player.getAngularVelocity() < 0 ) {
      $player.setAngularVelocity( 0 );
   }
}

function playerRight() {
   $player.setAngularVelocity( $player.turnSpeed );
}

function playerRightStop() {
   if( $player.getAngularVelocity() > 0 ) {
      $player.setAngularVelocity( 0 );
   }
}

function playerUp() {
   $player.setImpulseForcePolar( $player.getRotation(), $player.speed );
   $playerUpSchedule = schedule( 20, 0, "playerUp" );
}

function playerUpStop() {
   if( isEventPending( $playerUpSchedule ) ) {
      cancel( $playerUpSchedule );
   }
}

function playerDown() {
   $player.setImpulseForcePolar( $player.getRotation(), -$player.speed );
   $playerDownSchedule = schedule( 20, 0, "playerDown" );
}

function playerDownStop() {
   if( isEventPending( $playerDownSchedule ) ) {
      cancel( $playerDownSchedule );
   }
}

function worldLimit( %this ) {
   %diffX = 49.5 + ( %this.getSizeX() );
   %diffY = 37 + ( %this.getSizeX() );
   %this.setWorldLimit( NULL, -%diffX, -%diffY, %diffX, %diffY, true );
}

$player.turnSpeed, $player.maxSpeed, and $player.speed are dynamic fields (currently set to 270, 30, and 1 respectively). This way I can mess with them and test the results instantly.

And you can ignore the worldLimit function. It's irrelevant to the movement. I use that as part of my dynamic wrapping system. :)
#7
12/15/2006 (6:58 pm)
Thanks Renolc. This does seem that the idea of applying an impulse is cleaner than what I was planning. One more question. I looked in the reference guide tdn.garagegames.com/wiki/TGB/Referencefor information on schedule() and couldn't find it. Is there some place where I could find all these functions? I know what schedule does, but in the future I might need a different one. I thought the reference guide had everything, but unless I'm somehow missing it, I don't see schedule().
#8
12/15/2006 (7:18 pm)
Didn't look in TDN, but schedule is covered in both incarnations in the new docs (1.1.3). There are entries in TGB Reference and also a component tutorial in Scripting/Scheduling Events.

The TGB Reference in the new docs is more up to date than the one on TDN - I tried to make sure everything on TDN made it to the new ones and added a whole bunch on top.