# ActionScript 3, Timesteps, and the fixed time step

This topic is 1452 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hey everyone, I'm looking into creating a AS3 game and I am back to the place where things kind of fall apart
The Game Loop

This critical component has crippled me. I'm attempting to implement a fixed timestep game loop, but for some reason I have a very noticeable jitter/jerk moment

And a bunch of other things, but no matter what I unfortunately can't seem to get it 'working'.

On the above links, I have tried both approachs. It seems as if something has gone horribly wrong with my interpolation or set up of the loop.

Currently I'm am attempting to use Gafferon's approach again but...

My graphic ( a 32x32 square ) jitters constantly. It hiccups when moving and then twitchs in place when standing still. Even with interpolation

Can someone please point out wheat I'm doing wrong?

/* Above load in the image, set up other items, set the stage framerate to 60 */

public var fixedDelta:Number = 1 / 60;
public var minDelta:Number = 1 / 30;
public var accumulator:Number = 0.0;
public var ratio:Number;

//Called on ENTER FRAME
private function mainLoop(e:Event):void
{

//Get the time and calc delta time in seconds
now = getTimer();
deltaTime = (now - last) * .001;
if (deltaTime > minDelta)
deltaTime = minDelta;
last = now;

accumulator += deltaTime;

//While we need to update; Update
while (accumulator >= fixedDelta)
{
//Update with out fixed DT
update(fixedDelta);
accumulator -= fixedDelta;
}

//Calc the interpolation ratio
ratio = accumulator / fixedDelta;
render(ratio);
}

//Main update function
public function update(dt:Number):void
{
square.update(dt);
}

//Main render function
public function render(ratio:Number):void
{
canvas.fillRect(canvas.rect, 0x000000FF);
canvas.lock();

square.draw(ratio);

canvas.unlock();
}

//============== Square update and draw

//Square update
public function update(dt:Number):void
{
prevPosition.x = position.x;
prevPosition.y = position.y;

if(Main.keyboard.checkKey(Main.keyboard.KB_RIGHT))
position.x += 300 * dt;

if(Main.keyboard.checkKey(Main.keyboard.KB_LEFT))
position.x -= 300 * dt;
}

//Square draw function
public function draw(ratio:Number):void
{
renderPosition.x = int(position.x * ratio + prevPosition.x * (1 - ratio));
renderPosition.y = int(position.y * ratio + prevPosition.y * (1 - ratio));

Main.canvas.copyPixels(image, image.rect, renderPosition);
}

Edited by noodleBowl

##### Share on other sites

Try removing the 'ratio' stuff and working only with the delta time

Doing something like

x += velocity.x * deltatime;

Should suffice

##### Share on other sites

I just tried removing the interpolation, but unfortunatly while it stops the jittering when standing still. It does not solve the spikes of jitters while moving :(

##### Share on other sites

First of all, I think your issue may be the type casting that you're doing:

[source]

//Square draw function
public function draw(ratio:Number):void
{
renderPosition.x = int(position.x * ratio + prevPosition.x * (1 - ratio));
renderPosition.y = int(position.y * ratio + prevPosition.y * (1 - ratio));

Main.canvas.copyPixels(image, image.rect, renderPosition);
}
[/source]

In Flash, because you can do sub-pixel rendering, decimal values are used for x/y positioning. I have a feeling that the jumping you're seeing is because of the blind rounding that happens when casting to an int from a real. Maybe this will help?

[source]

//Square draw function
public function draw(ratio:Number):void
{
renderPosition.x = Number(position.x * ratio + prevPosition.x * (1 - ratio));
renderPosition.y = Number(position.y * ratio + prevPosition.y * (1 - ratio));

Main.canvas.copyPixels(image, image.rect, renderPosition);
}
[/source]

I also note that you're copying the square graphic to what I'm guessing is a mx.containers.Canvas instance. I don't want to presume anything but from the code I don't see any reason to be doing this. If it's a vector or bitmap graphic, you can use a Sprite or maybe even a Bitmap instance. It'll make your code cleaner and it should work faster than any custom blitting or pixel copy system.

For example:

[source]

var myGraphic:Sprite=new Sprite();

[/source]

Subsequently you won't need the render function since the above has already rendered the graphic. So your new update function would be:

[source]

//Square draw function
public function draw(ratio:Number):void
{
myGraphic.x = Number(position.x * ratio + prevPosition.x * (1 - ratio));
myGraphic.y = Number(position.y * ratio + prevPosition.y * (1 - ratio));

}
[/source]

That all being said, you would probably save yourself some time and frustration by using a tweening system (Flash's or something like Greensock, for example). You tell it which object to move, the start position, end position, and interval -- it takes care of moving the graphic. All of the graphics properties should always be available so you can always calculate collisions (or whetever) on every motion increment, and of course you can stop, reset, and rewind any animation. You can also just get the tweener to dispatch events instead of affecting the graphic (you then update the graphic position based on where the tweener tells you to).

Unless there's a compelling reason to move graphics around like you're doing, the solution that you've implemented is WAY too complicated and error-prone, not to mention limiting (tweens also do accelerations/decelerations and other nice effects).

Without seeing your ultimate application, here's how I would tackle graphic motion:

[source]

import flash.display.*;

import fl.transitions.Tween;

import fl.transitions.tweening.Regular; //Regular tweening equations; others include Strong, Elastic, Bounce, etc.

import fl.transitions.TweenEvent;

private var motionXTween:Tween;

private var motionYTween:Tween;

public function createSquare():Sprite {

//only need to create the square once!

var returnSquare:Sprite=new Sprite();

returnSquare.graphics.lineStyle(1,0x000000); //Black line, 1 pixel thick

returnSquare.graphics.moveTo(0,0);

returnSquare.graphics.beginFill(0xFF0000,1); //Red fill, 100% (1) opacity

returnSquare.graphics.lineTo(0,100); //Draw the 100x100 square...

returnSquare.graphics.lineTo(100,100);

returnSquare.graphics.lineTo(100,0);

returnSquare.graphics.lineTo(0,0);

returnSquare.graphics.endFill();

return (returnSquare);

}

public function onSquareMove(eventObj:TweenEvent):void {

if (eventObj.target== this.motionXTween) {

trace ("Square is now at X position: "+eventObj.position);

}

if (eventObj.target== this.motionYTween) {

trace ("Square is now at Y position: "+eventObj.position);

}

}

public function moveSquareTo(targetXPos:Number, targetYPos:Number):void {

var moveSquare:Sprite=this.createSquare();

this.motionXTween=new Tween(moveSquare, "x", Regular, moveSquare.x, targetXPos, 1, true); //Move "moveSquare", on "x" axis, using Regular tweening, from "moveSquare.x", to tagetXPos, using a duration of 1, in seconds

this.motionXTween.addEventListener(TweenEvent.MOTION_CHANGE, this.onSquareMove); //Call the onSquareMove function on every motion update -- completely optional!

this.motionXTween.start();

//Do the same thing for the Y axis...

this.motionYTween=new Tween(moveSquare, "y", Regular, moveSquare.y, targetYPos, 1, true);

this.motionYTween.start();

}

[/source]

You could probably shrink this code down a bit more but this is the essence of both creating the graphic and then moving it using a tween. You can also get rid of the onSquareMove event listener since it doesn't do anything except tell you where the square is while moving.

As I said, I'm making assumptions here; if you're loading the square then there are an extra couple of steps, and if you really do need to move the square around at the pixel level then it's best to combine your copyPixels call with the Tween event (use the event listener to assign the X/Y values instead of calculating them).

Hope this helps, and Merry Christmas!

Edited by Patrick B

##### Share on other sites

This topic is 1452 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Create an account

Register a new account

• ### Forum Statistics

• Total Topics
628718
• Total Posts
2984374

• 25
• 11
• 10
• 14
• 14