Game Development Community

Rotating and moving sprites

by Philip Mansfield · in Torque Game Builder · 03/01/2005 (7:04 am) · 10 replies

I'm slowly getting to grips with T2D, but not being a coder, I'm struggling. Still, I'm making progress day by day :)

I'm trying to figure out how to get my players sprite zooming about on the screen as I want it to. For the effect, think an Asteroids ship with the thruster stuck on, but the player can rotate the ship to change direction.

So far, my Action Map fires these procedures:
function playerCW()
{
	$player.setAngularVelocity( -90 );
	$player.setLinearVelocityPolar(($player.getRotation()+90),10);
}

function playerCWStop()
{
	if ( $player.getAngularVelocity() < 0 )
		$player.setAngularVelocity( 0 );
}
This rotates the player clockwise. There are corresponding functions for anti-clockwise. I hope I have used the various set functions correctly, but here's how I'm using them and what's happening at the moment:

setAngularVelocity(-90) - This is the speed at which the player rotates, and as long as the key is held down, the player rotates. Releasing the key stops the rotation.

setLinearVelocityPolar(($player.getRotation()+90),10) - This gets the players current rotation value and adds 90 to it so it's pointing the same way as the sprite (to the right). The second value is the speed the sprite should move.

This all works, except that setLinearVelocityPolar is only called once per keypress. So if you hold the rotation key down, you can effectively fly backwards. The next quick tap of the rotation key sorts it out and you fly in the right direction again. I want the ship to constantly be moving in the direction it's facing.

I get the feeling that I'm *almost* there, but there's a bit of the puzzle that's fallen down the back of the sofa and I can't reach it.

Any advice would be appreciated :)

#1
03/01/2005 (8:40 am)
You'll need to use a schedule to handle applying the setLinearVelocityPolar

function playerCW()
{
	$player.setAngularVelocity( -90 );
	$turnCW=true;
	playerCWSched();
}

function playerCWSChed()
{
	if($turnCW)
	{
		$player.setLinearVelocityPolar(($player.getRotation()+90),10);
		//Every 1/4 second (250 milliseconds) apply thrust
		schedule(250, 0, "playerCWSched");
	}
}

function playerCWStop()
{
	if ( $player.getAngularVelocity() < 0 )
		$player.setAngularVelocity( 0 );
	$turnCW=false;
}
#2
03/01/2005 (8:42 am)
I'm running into the same issue. Here an idea I had, but haven't had time to try yet.

1) when any keypress is detected (turn L, R, thrust), set a boolean flag like $playerThrust = true, or $playerTurn = true.

2) Also, when the keypress turning keypress is detected, schedule an event to call a function like 'updateThrust'. Im not sure how often to call this function to keep the ship pointing in the right direction, maybe 30fps, which would be 33ms

3) In this updateThrust function, check if $playerThrust AND $playerTurn == true. If so, then update the setLinearVelocityPolar. In this function, I suppose here is where we schedule the next updateThrust event? (I'm not sure if you can schedule a recurring event). You probably want to have a condition here where we check if $playerTurn is still true, so the event chain can break if the player isn't turning.

(We do this because, I don't think an event can be stopped once it is called, so the keyup event for the turn can't really stop these events from happening. We have to keep checking if the original conditions that started the chain are still true... I think :)

4) on the key up events, set the flags for false, so the event will not get re-scheduled next time its called.

Something like this will probably work, but not sure if I hit all the steps exactly. There might also be a way to schedule an event callback based on the changing rotation of a sprite. Somebody could chime in here... that would be better, since it would update the thrust if the sprite changed orientation due to physics. Alternately, we could not even bother with setting flags for turning... just call the updateThrust event as long as the $playerThrust is true. I was trying to be efficient about it, but it's probably better to not bother checking about turning, and just assume that the player orientation might change at any time...

There's another topic here about calling regular events, to simulate game loop functionality. You may want to check that out. I'm pretty sure what you DONT want to do is try and update the thrust with the sceneUpdate callback (not sure if that's what it's called). That would probably start affecting framerate. Could be wrong about that though.

Let me know if you figure it out!
#3
03/01/2005 (8:51 am)
Excellent posts, thanks :)

I didn't try the sceneUpdate function, as I knew once other things were happening on screen, it would likely cause problems.

I'll have a play with the schedule tonight and see how I get on. Obviously I will need to vary the timer until I get something that gives me the right feel, but might I run into problems if I end up repeating the call every 33ms? If I have to rotate multiple objects, I'm worried that the program will spend more time working on rotations than it will doing anything else.

Edit -> Had a quick play and it works great. Had to change the schedule to 100ms and it seems OK, but I need to balance out turn rate and velocity anyway.

The controls would go a bit funky if you suddenly changed direction, but I've changed the keyup code to be:
function playerCWStop()
{
	if ( $player.getAngularVelocity() < 0 )
	{
		$player.setAngularVelocity( 0 );
		$turnCW=false;
	}
}
And the funkyness seems to have gone.

Thanks again, and here's to more progress on my game tonight :)
#4
03/01/2005 (10:40 am)
LabRat has the best solution. I've seen people avoid the schedule function like it's heavy or a performance killer but it's actually very lightweight.

In my old Asteroids demo, I used almost the same exact solution and it worked perfectly.

www.subreal.net/vids/asteroids.jpg
- Melv.
#5
03/01/2005 (5:59 pm)
Just so you guys know, Melv and I are ready to bust out pretty much an infinity of quick demos like that, we just hate to release programmer art. So if there are any talented 2D artists out there that wouldn't mind contributing some art and getting their name in the credits, we could bust out tons of simple demos + tutorials on them very quickly. For this asteroids one, all we'd need is a really cool looking ship and some asteroids. :)
#6
03/01/2005 (6:04 pm)
Pffssshh - come on Josh - I'm sure your progammer art will look better than mine :P
#7
03/02/2005 (12:01 am)
I was still not getting thrust updates if I just held down the thrust key, and bounced off of walls ( I have walls in my demo :) So check this out... works sweet!
function playerThrust()
{
        //Set the player moving forward
        $playerThrustFlag = true;
        $playerCurDir = $player.getRotation(); // store the current direction
        schedule (33, 0, "playerThrustSched");
        $player.setConstantForcePolar( $player.getRotation()+90, $playerThrustAmount );
	
}

function playerThrustSched()
{
        //see if ship dir has changed. If so, update the thrust
        if( $player.getRotation() != $playerCurDir )
                $player.setConstantForcePolar( $player.getRotation()+90, $playerThrustAmount );
        
        //Is player still thrusting? Reschedule event if so.
        if( $playerThrustFlag == true )
                schedule (33, 0, "playerThrustSched");
}
#8
03/02/2005 (12:52 am)
@Phil: Yes, that's a good way to do it. Have your key-bindings change a flag and then call the initial function that repeatedly adjusts your flight-path and reschedule another if need be.

You may/may-not know this but the schedule returns an event-id which you can do stuff with like the following:-

// Schedule a thrust event.
$thrustEvent = schedule( 100, 0, "doSomeThrust" );

// Is an event pending?
if ( isEventPending( $thrustEvent ) )
   // Yes, so cancel the event.
   cancel( $thrustEvent );

This above code doesn't do anything useful but the "isEventPending()" and "cancel()" calls are extremely valuable.

- Melv.
#9
03/02/2005 (5:39 pm)
@Melv: Oh, cool... no I didn't know that. That's great, thanks.

You know in that other thread about getting the player to look at the mouse? Well, now I'm using that to set the player rotation, so I *really* have to be constantly updating the polar force. Right now, I am just heavy-handedly seting the player rotation to be the angle of the mouse curor. I'd like it eventually to detect whether the mouse angle is to the left or right of the player angle, then set the player rotation towards it. I probably want to do something so it slows down then stops as it approaches the target angle, to avoid constant re-corrections.

... I should continue this in the other thread so it's in the right place.
#10
03/03/2005 (2:24 am)
@Phil: Yes, I see the effect you're trying to achieve. The problem I've got, as you can understand, is to balance providing abilities such as this with making the SDK calls too complex. In the end, your game-development would want a specific effect that would require going to C++ and making some minor changes.

I can tell you now that I could go to T2D and do that work very quickly, say 1 hour. Design though is another matter, trying to find the sweet-spot of functionality/minimal complexity takes longer.

I guess that's my job right there.

I'm really trying to find the time to make some posts that just jump in and provide insight into how to achieve certain effects such as this but fixing bugs, responding to posts and fighting a cold is making this hard to achieve although I'm enjoying replying to posts because the buzz around here is getting me through my cold. :)

- Melv.