I'm having trouble with smooth character movement for a 2d game I'm making.
It looks like the character is double when moving. Kinda like this (its just one pixel though):
( ()
/ /{}\ ==>
| ||
The game runs on a solid 60 FPS and my monitor is not the problem (I have tested this on several monitors).
I'm using starling at the moment, but I've had this since I first stared making games (using openGL). I was hoping someone could tell me what I'm missing. Here is my code:
private var _x:Number = 20, _y:Number;
public function update(delta:Number):void
{
if(gravity){
_y += delta * 120;
}
if(_y + skin.image.height > game.stage.stageHeight){
_y = game.stage.stageHeight - skin.image.height;
gravity = false;
}
if(right && left){
skin.playAnimation("none");
}else if(left){
_x -= delta * speed;
skin.playAnimation("left");
}else if(right){
_x += delta * speed;
skin.playAnimation("right");
}
//update skin
skin.update(delta, Math.round(_x), Math.round(_y));
}
skin update method:
public function update(delta:Number, x:int, y:int):void
{
image.x = x;
image.y = y;
if(currentAnimation){//this is texture switching (I tried without, still happens)
currentAnimation.update(delta);
}else{
image.texture = textures[4];
}
}
Here is the game.
Based on my own experimentation, as well as all the data in the comments, I think the ghosting is dependent on the frame rate and the computer itself.
First, and most importantly, when I tried the game in the link, it had the described ghosting at the full frame rate of 60. However, when I tried to film a screencast for further analysis, that occupied some CPU, dropping the frame rate down to around 35 or 40. At that point, the ghosting stopped.
Second, because different people are reporting different experiences with the described ghosting, I'd also think that it has a little to do with the individual computers themselves, probably rooted in their available memory and CPU, though that's just a theory, as I don't have any benchmarks to go off of.
Third, I think part of it is also rooted in neuroscience, as different people perceive animation differently.
People always talk about wanting a higher frame rate, but honestly, to fix this, I would recommend LOWERING the frame rate. Flash Professional CS6 has a default frame rate of 24 FPS, and I have never experienced a ghosting problem to my memory. It is worth mentioning that Flash animators usually work in 24 FPS.
Then again, appearance-wise, it really isn't a major deal. It is one of those graphics flaws that people tend to ignore, similar to the motion blur you get on 24 FPS films, until they changed it to 48.
It seems to be something that all games have (I actually never noticed it on some games where I do notice it now) and I just have to live with it. Its not my hardware, its not my monitor. I tried it on a lot of computers (good to bad hardware) and it looks the same on all computers. It looks worse on the computers with bad hardware, but there is not a huge difference.
Related
I used script from Paul Irish
https://gist.github.com/paulirish/1579671
to create animation loop inside html site.
It works although it's faster in fullscreen mode than in browser window.
Also, I observed different speeds depending on canvas size and depending on browser I use.
Question: How can I ensure stable frame rate using the script?
Code is available here (Beginning WebGL, chapter 1 by Brian Danchilla):
https://github.com/bdanchilla/beginningwebgl/blob/master/01/2D_movement.html
Something like this should work. If the time delta between two frames is shorter than your FPS limit, the update function returns and waits for the next frame. But this will only limit the updates from happening too quickly; like emackey said, there's always the possibility the update loop will run more slowly.
var updateId,
previousDelta = 0,
fpsLimit = 30;
function update(currentDelta) {
updateId = requestAnimationFrame(update);
var delta = currentDelta - previousDelta;
if (fpsLimit && delta < 1000 / fpsLimit) {
return;
}
/* your code here */
previousDelta = currentDelta;
}
To embellish what #emackey said,
The short answer is you can't. You could ask the computer to do an infinite amount of work each frame. I can't promise to do that work in a finite amount of time.
On top of that each computer has a different amount of power. A cheap integrated GPU has much less power than a high end graphics card. An intel i3 is much slower than an i7.
You also mentioned changing the canvas size. Drawing a 300x150 canvas is only 45000 pixels worth of work. Drawing a 1920x1080 canvas would be 2,073,600 pixels of work or 46x more work
The best you can do is do the least amount of work possible, and or remove features on slow hardware either automatically or by user choice. Most games do this. They graphics setting options where the user can choose resolution, texture res, anti-alising levels and all kinds of other things.
That said, you can try to do your computations so things in your app move at a consistent speed relative to time. The framerate might slower on a slow machine or with a larger canvas but the distance something moves per second will remain the same.
You can do this by using the time value passed into requestAnimationFrame
function render(time) {
// time is time in milliseconds since the page was loaded
...do work...
requestAnimationFrame(render);
}
requestAnimationFrame(render);
For example here is NON framerate independent animation
function render(time) {
xPosition = xPosition + velocity;
...
requestAnimationFrame(render);
}
requestAnimationFrame(render);
and here is frame rate independent animation
var then = 0;
function render(time) {
var timeInSeconds = time * 0.001;
var deltaTimeInSeconds = timeInSeconds - then;
then = timeInSeconds;
xPosition = xPosition + velocityInUnitsPerSecond * deltaTimeInSeconds;
...
requestAnimationFrame(render);
}
requestAnimationFrame(render);
Note: The time passed into requestAnimationFrame is higher resolution than Date.now()
Here's an article on it with animations
You can't enforce a stable frame rate directly. Your page is not the only app running on the user's platform, and platform capabilities vary widely. requestAnimationFrame runs as fast as it can, not exceeding the display update interval on the target device, but potentially much slower depending on available CPU, GPU, memory, and other limitations.
The standard practice here is to measure the amount of time that has elapsed since the previous animation frame, typically with Date.now(), and each frame advance the animation by that amount of time. To the human eye, this makes the resulting animation run at a consistent speed, even if the frame rate is highly variable.
For example, sites such as Shadertoy and GLSL Sandbox run full-screen GLSL shaders and pass in a uniform called time (or iGlobalTime), which is a float representing the number of seconds elapsed since the shader started. This time value increases at irregular intervals depending on how long each animation frame took to render, but the result is that the float appears to count upwards at a stable 1.0 per second. In this way, shader playback based on this time value can appear consistent.
I created a web game with EaselJS, which have a few (2-6) Sprites that are moving on the canvas. Also they may scale up and down according to mouse events.
Here is how I move these Sprites:
container.enemies.forEach(function(drop) {
drop.x += drop.vx;
drop.y += drop.vy;
checkHitWall(drop);
var collided = drop.checkCollision(container.enemies);
if (collided) {
distributeVelocity(drop, collided);
}
});
Here is how I change their size:
growingObject = function(obj) {
if (obj.radius > canvasWidth / 4) {
return;
}
var rate = 1.01;
obj.gotoAndStop("growing");
obj.radius *= rate;
obj.scaleX = obj.scaleY = obj.scale * rate;
obj.scale = obj.scaleX;
}
and this function is called every tick when mouse is down.
The background is cached when it is created.
I don't know if there's best practice for moving/growing sprites with EaselJS.
The game runs find on a desktop browser, but is very laggy on a android phone.
I think these Sprites are not a heavy load for a phone. The profiling result shows draw method consumes most CPU time. How could I optimize this?
One idea: You can try reducing your framerate to reach a balance between smooth animation and acceptable speed. In my experience you can go to surprisingly low framerates on mobile before the game starts looking unacceptable. Try something like this, and adjust your velocity to simulate the same kind of speed you had at your previous fps. Obviously the exact tweaking is up to you.
createjs.Ticker.setFPS(12);
For a long time I've been searching for a solution to this problem, so I decided to post a tread instead when the search didn't clarify anything.
I have a textfield that is supposed to move across the screen. I've solved this by adding a speed to its x-value dynamically through an "enter-frame function". However, the movement is very "laggy" and consists of sudden "jumps" in the movement. I've tried a couple of possible solutions to this, all of them without luck.
embedding fonts
changing the textfield's antiAliasType
using BitmapData like this:
bmd = new BitmapData (myTextField.width, myTextField.height, true, 0);
bmd.draw (myTextField);
bm = new Bitmap (bmd);
bm.x = myTextField.x;
bm.y = myTextField.y;
bm.cacheAsBitmap = true;
bm.smoothing = true;
this.addChild(bm);`
And then moving the "bm" instance
None of these methods worked.
EDIT: By request, I am adding the relevant code for the actual movement of the text.
stage.addEventListener(Event.ENTER_FRAME, time);
private function time(evt:Event):void
{
bm.x-= textSpeed;
}
The variable textSpeed is defined as a public static var. Its value is 2.
*EDIT2: I've prepared a clean fla-file with nothing but moving text. The same lag occurs for me also here. The code is in the actions panel. Download link
the way Flash IDE works, is that setting the framerate is actually the 'maximum' framerate. That is, it doesn't force the animation to run at that rate - it can vary depending on the machine and available resources.
As far as I know, there's no way to force Flash to run at a certain framerate - the best way to make animations 'smooth' is to use Tween classes like TweenLite.
If you NEED to animate by incrementing position values, then I suggest making it time based instead, for example:
var fps = 24;
var moveTimer:Timer = new Timer(1000/fps);
moveTimer.addEventListener(TimerEvent.TIMER, onMoveTimer);
moveTimer.start();
function onMoveTimer(e:TimerEvent){
bm.x -= 1;
}
Again, this doesn't solve the smoothness of the animation, but it will be much more reliable across different machines than using enter frame.
Try increasing the framerate. Because you naturally try to read text as it animates, you can generally notice the gaps between frames at 24fps. Try setting stage.frameRate to 30, 48, or 60 (60 being the max) and see if that solves your issues. I've had similar issues with animating text in the past and increasing frame rate has fixed them.
I would also recommend only increasing it as needed. You are much more likely to drop frames with a higher frame rate (makes logical sense; each frame has less time to calculate as frame rate increases), so you might want to do something like:
stage.frameRate = 48;
// run animations here
stage.frameRate = 24; // in an Event.COMPLETE handler
That will make sure your animations are smooth while giving the rest of your application the best shot of running well on lesser devices. If you are running a lot of animations, you might consider keeping it elevated permanently.
You should also look into using the Greensock animation library (TweenLite/TweenMax) instead of Flash's built-in tweening. Greensock has a vastly superior API, both in terms of features and performances, especially on mobile.
As i am working on side view bike stunt game in which am trying to add slow motion effect when a bike performs stunts.
Is there any solution for showing such kind of slow motion effect in Box2D. can anybody help me in this regard
Thanks and regards,
Chandrasekhar
As mentioned already, changing the length of the time step can give a slow motion effect. It also has the side-effect of altering the way gravity affects bodies, and can complicate other things like recording a replay or syncing state across multiplayer games for example.
Another option is to use a fixed time step length for every time step, and keep track of the previous position and angle for all bodies. Then you can interpolate between the last frame and the current frame to draw them at an in-between frames position. This means that you are always drawing things a tiny bit behind their current position in the physics engine, but it should not be noticeable with typical frame-rates of 30-60fps.
An easy way to do this effect with or without Box2D is to step up a time modifier.
so lets say you move the player in a run function like so:
player.x += vel_x;
player.y += vel_y;
you could setup a time modifier variable that is initialized to 1
var time_mod:Number = 1;
then update all your movements as followed
player.x += vel_x * time_mod;
player.y += vel_y * time_mod;
then when you want "the slow motion effect" change your time_mod variable. For half of real time change your time_mod to 0.5. If you want to super speed change it to 2 or 3, super slow? change to 0.3
you get the idea?
I'm creating a Flash game which is based on the old Pacman and I'm not sure which is the best way to control the animation.
As I understand it these type of games were originally dependent on a game loop which ran faster or slower depending on the CPU, which is why I imagine that the most similar to use would be the ENTER_FRAME event.
This however presents the problem of having to have a specific frame rate and changing it later is out of the question, not to mention being limited to very few different "speeds" (see below). An example could be that the sprite has to move 12 pixels before the next move is determined. If the speed is then 4 pixels per frame, the math is quite simple:
[...]
public var stepCount:uint = 0;
[...]
function enterFrameHandler(e:Event):void
{
if(stepCount==0) {
//Some code to evaluate next move. Let's say it evaluates to MOVE RIGHT
}
if(MOVE_RIGHT)
{
x += 4;
}
stepCount++;
if(stepCount > 2)
{
stepCount = 0; //Now ready to evaluate direction again.
}
}
This all works fine, but let's say that I want the sprite to move 5 pixels per frame. Then the number of frames before making the next evaluation would not compute. The stepSize would have to be a multiple of 12, which limits the different possible speeds (1,2,3,4 and 6 pixels per frame).
This is why I attempted to base the movement on a Timer instead, which I also managed to get to work, but the movement was somewhat erratic and it seemed like the Timer was using far more memory than the ENTER_FRAME event. Instead of an even movement the Timer made the sprite slow down and speed up and slow down again.
Another possible solution could be the Tween class, but it seems extravagant.
Does anyone have experience with what works best in other games?
Morten Twellmann
You have several separate issues here. Your first question is, should you execute your game loop in a frame event or a timer event? The answer is easy - you should do it in a frame event. The reason is that regardless of how you move your characters, the screen is updated precisely once per frame. So any time you're calling your game loop more than once per frame you're wasting CPU, and any time you call it less than once per frame, you're sacrificing visual quality. So this one is easy, don't bother with timer events at all.
The next question is whether your game's movement should be tied to frames or miliseconds, and the answer is that it depends on the game. Ask yourself this: suppose that some user is playing your game, and their spaceship (or whatever) is flying along at a given speed. Suddenly, the user's anti-virus package does something heavy, and the CPU spike causes Flash to stop updating for one second. Once the spike is over, do you want the spaceship to continue moving from where it was when the spike started? Or do you want it to jump forwards to where it would be if it had continued moving during the spike? If you want the former, you should tie your movement to frames; if you want the latter, you should tie it to miliseconds. But which one is best depends on how you want your game to work.
The final question is, how exactly should you move the characters in your game? Based on what you wrote, I'd do it as follows. For frame-based movement (i.e. the first approach described earlier):
// the ship moves 25 pixels per second
var shipSpeed:Number = 25;
// the number of seconds per frame, based on the published framerate
var frameTime:Number = 1 / stage.frameRate;
// game loop called each frame:
function gameLoop() {
// ...
playerShip.x += shipSpeed * frameTime;
// ....
}
This way, the ship's movement on screen is constant, regardless of what framerate you publish your SWF at. Using a higher framerate simply makes the movement smoother. Likewise, to tie your movement to time instead of frames, simply change "frameTime" in the code above to refer to the time elapsed since the previous frame, as described in Allan's answer.
Yes frame rates will vary depending on CPU amongst other things. Therefore you need to take this into account with your game loop. What I like to do is get the time difference between the current frame and the old frame and use that value in my calculations. So if it happens that there is a delay the larger difference value will then make up for the fact less frames ran.
var _previousTime:Number;
//gameLoop is the function called on ENTER_FRAME
public function gameLoop(e:Event):void
{
var currentTime:Number = getTimer();
var difference:Number = currentTime - _previousTime;
_previousTime = currentTime;
//use difference variable with calculations involving movement
}