I am trying to do an animation whenever my character jumps. It works in the following way: when I jump, I first draw the animation of my char. If it is finished, I start modifying his position and also draw another texture, for the inAir moment. The problem is that the animation runs instantly (I tried putting the speed 1 frame per second,but it still runs instantly) and the character jumps before the animation is done. I suspect it considers it finished before it actually finishes. This is how I check if the animation is finished: first I check if the animation start (the jump button is pressed) and then I have an if condition like this:
if (animationStarted && rightJumpAnim.isAnimationFinished(System.currentTimeMillis()))
{
animationStarted = false;
animationFinished = true;
timePassed1 = 0;
}
After this, I put animationFinished to false when he touches the ground again. Any advice?
P.S. here is the code for running the jumpAnimation:
if (toDrawJumpRight1 == true) {
animationStarted = true;
timePassed1 += Gdx.graphics.getDeltaTime();
spriteBatch.draw(rightJumpAnim.getKeyFrame(timePassed1, false), posX + cameraX, posY + cameraY, sizeX, sizeY);
}
Your problem should be in the very first line you provided to us:
if (animationStarted && rightJumpAnim.isAnimationFinished(System.currentTimeMillis()))
The argument you must pass is the STATETIME of the animation.
if (animationStarted && rightJumpAnim.isAnimationFinished(timePassed1))
Edit:
Some more Informations to this problem:
You say you want 1 frame stay 1 Second.
Now we say, you have approx 5 frames.
5frames * 1 second = 5seconds for finish
so if statetime is over 5 seconds, your animation is played ONE time (is finished)
Animation.isAnimationFinished(float stateTime) checks now, if the current stateTime from your animation is higher than the 5 seconds.
System.currentTimeMillis is at this moment:
1440618906341
now.. whats bigger?
Have a nice Evening (I recommend using TimeUtils.millis instead of System.currentTimeMillis, guess it's optimated, fo' sure.)
Related
I have just started using the OpenGL ES 2 for android for my little game and have encountered a problem on redrawing the screen on each frame.
I have setup a loop on my Renderer's onDrawFrame, just a simple [ updateGameLogic() -> drawGame() ] or Thread.sleep() loop based on the time lapsed from last drawGame call.
Currently the updateGameLogic() method simply translate the camera to the +ve X direction (the game is 2d).
In the drawGame() call, I first clear my screen with GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT). Then I have 3 glBindTexture and glDrawElements calls for drawing 3 categories of objects with different texture atlas.
Here comes the problem, in between each frame drawn on screen, there is a blink of the previous frame appearing which is undesired and makes the game look dizzy. Precisely, say the game is just about to draw frame 3 from frame 2, right before frame 2 vanish and frame 3 appearing, there is a split moment where frame 1 is displayed.
I thought this may be due to the way the GLSurfaceView is buffered by the system so I experimented with calling multiple glClear before drawing but everything stays the same. Would be grateful if someone can provide some explanation / solution to the problem, and what I have done wrong, thanks. (basically paragraph 2 to 4 is all my code so I have not posted it, unless requested)
From the clarification in the comment, it sounds like you have something like this in your code:
public void onDrawFrame(GL10 gl) {
long currentTime = SystemClock.elapsedRealtime();
long deltaTime = currentTime - mLastFrameTime;
if (deltaTime < 33) {
Thread.sleep(33 - deltaTime);
return;
}
mLastFrameTime = currentTime;
updateGameLogic(deltaTime);
drawGame();
}
This will indeed cause problems. When onDrawFrame() is called, you have to render a frame. You can't just return without drawing anything. The caller will assume that you rendered a frame in any case, and it will end up being presented on the screen. If you decide not to render anything, whatever happened to be in the surface you were supposed to draw to will be presented. There's no telling what this will be, but it's quite likely that it's an old frame from 2-3 frames earlier.
If you want to artificially throttle the frame rate, e.g. to save power, unfortunately there's no very good way to do this in Android. Using sleeps in onDrawFrame() is kind of dirty (and inherently unreliable, IMHO), but it might be necessary in this case. The key is that either before or after you sleep, you still need to render a frame. As a first attempt, I would try tweaking the above to something like this:
public void onDrawFrame(GL10 gl) {
long currentTime = SystemClock.elapsedRealtime();
long deltaTime = currentTime - mLastFrameTime;
if (deltaTime < 33) {
Thread.sleep(33 - deltaTime);
currentTime = SystemClock.elapsedRealtime();
deltaTime = currentTime - mLastFrameTime;
}
mLastFrameTime = currentTime;
updateGameLogic(deltaTime);
drawGame();
}
Note that while there is still an artificial delay, there is no early return in the code anymore.
There are probably more robust variations of this idea for throttling the redraws to 30 fps. Some searching on SO or the rest of the internet should reveal previous discussions.
In my game, I want the camera to move based on the user swiping their finger. My issue is that when someone removes their finger from the screen, and places it down again, the camera jumps to a new position... I am guessing it has to do with the coordinates, I say this because if I click somewhere far from where I removed my finger from the screen, the camera jumps. Here is the code:
var speed : int = 1;
var lastPoint : Vector2; //make this private if you want to.
function Update()
{
var offset : float; //offset of the touch from last frame
if(Input.touches.Length 0)//make sure we have a touch in the first place
{
var evt : Touch = Input.touches[0]; //setting up touch events so we can get fancy.
if(evt.phase == TouchPhase.Began) //this is the first frame the screen has been touched for, simply save the point.
{
lastPoint == evt.position;
}
else if(evt.phase == TouchPhase.Moved
{
offset = evt.position.x - lastPoint.x ;//take the difference
//I'm going to use Transform.Rotate because it's handy dandy
transform.Rotate(0,offset * speed,0);
//save the new "lastPoint"
lastPoint = evt.position;
}
else if(evt.phase == TouchPhase.Ended)
{
//If you want the object to drift after you spin it you can make a function to go here.
//To do this, take the speed of the rotation and continue to rotate all while subtracting off of the speed.
//I would use the Transform.Rotate function on this too.
//If you need me to I could write this function too.
}
}
}
What is the solution to have the camera resume, and not jump once someone puts their finger down again?
I am also willing to redo it, if there is a better solution/more efficient method of solving the issue..
Thanks a lot!
The supplied code seems fine, all you need to do is when the user is not pressing, you update the lastPoint every frame. Or if you know when the user start to press, just set the lastPoint to the current pos before calculating the offset. This way the offset is zero the first frame the user touch the screen.
I have made 2 different animations in Adobe flash professional cs5.5 for an Android aplication.
And I want a code that makes it possible for a user of the app to play the animation as often they want, so if the user wants the animation to play 1 time the first animation will be playes, if the user wants to play it 2 times the animation 1 and 2 will be played, if the user wants the animation 3 times played the animation 1, 2 and 1 will be played and so on.
Can somebody help me with this problem and tell me if this is possible in jquery.
If I was you, the way I would approach this is by having a keyframe after each of the animations where you can type some code.
On the menu page or where ever you have the code for how many times the code should run, define a variable and call it something like "runTimes" which should become the amount of times the animation should run.
At the end of the animations do a simple if statement to check what the value of "runTimes" is and then decrement it. Depending on the value, it should use gotoAndPlay/gotoAndStop.
So, put this on the keyframe after the first animation:
if (runTimes > 0) {
runTimes--;
gotoAndPlay(<FIRST FRAME OF SECOND ANIMATION>);
} else {
gotoAndStop(<FRAME OF MAIN MENU>);
}
and this after the second animation:
if (runTimes > 0) {
runTimes--;
gotoAndPlay(<FIRST FRAME OF FIRST ANIMATION>);
} else {
gotoAndStop(<FRAME OF MAIN MENU>);
}
On the mainmenu frame, let's assume you have a textbox named "numTimes_txt" for the number of times to play and a button "playAnimations_btn" to start the animations.
import flash.events.MouseEvent;
var runTimes:int = 0;
playAnimations_btn.addEventListener(MouseEvent.CLICK, playAnims);
function playAnims(e:MouseEvent):void {
runTimes = parseInt(numTimes_txt.text);
play(); // or gotoAndPlay(<FIRST FRAME OF FIRST ANIMATION>);
}
I haven't tested this as I don't have my IDE on me right now, but this should work if I understand the question properly.
I am able to rotate camera with this code
camera.zoom = 3//in constructor
if(camera.zoom>1)
{
camera.zoom-=0.01f;
camera.rotate(15);
}
this is done in render, Now zooming effect works properly but when zooming completes my screen is stay rotated with current angle. like below.
I want that my screen stops after zooming at 0 degree.
In your code snippet
**camera.zoom=3;**
and in each iteration you are zooming camera by 0.01 till camera.zoom > 1
so you have total 20 iteration for zooming
Then rotate with 18 degree angle after iteration it will rotate in 360 degree.
I wrote this method to calculate current angle of camera:
public float getCameraCurrentXYAngle(Camera cam)
{
return (float)Math.atan2(cam.up.x, cam.up.y)*MathUtils.radiansToDegrees;
}
Then I call rotate method like this:
camera.rotate(rotationAngle - getCameraCurrentXYAngle(camera));
This code works, but it will rotate immediately in one call. to rotate it by a speed, you need to calculate appropriate 'rotationAngle' for every frame.
Have you tried rotating a multiple of 1.8 degrees with each iteration? Then you're image should have completed a number of full rotations once the 200 iterations have passed.
attention, the computer can't correctly represent most real numbers!
in binary 0.01 is a periodic number, so it will be truncated/rounded.
substrating/adding float numbers a few hundred times will add the rounding error and thus give you horribly wrong results.
(e.g. after 200 substractions, your camera.zoom value will be ~ 1.0000019 - NOT 1.0!)
that's why your loop is repeated 201 times, giving you a zoom value of 0.9900019 and a rotation of 361.7996 ~ 361.8 (when using 1.8 as in alex's answer).
you could use libGDX Interpolation functions:
time += Gdx.graphics.getDeltaTime(); //the rounding error is futile here,
//because it'll increase the animation time by max. 1 frame
camera.zoom = Interpolation.linear.apply(3, 1, Math.min(time, 1));
camera.rotate = Interpolation.linear.apply(0, 360, Math.min(time, 1));
this code would create an one second long animation of zooming from 3 to 1 and rotating from 0 to 360 (simply one whole roation)
I have to animate a circular count down timer and I'm doing it by animating the background of an ImageView using AnimationDrawable (each image has the according slice of the circle removed). The problem is that the user has the ability to pause this animation, so I have to reload the animation but then a problem appears. I've tried setting the the animation to null, setting the background of the ImageView to null, setting the visibility of the animation, but practically nothing helped, because number of frames remains the same. I have to find a workaround for deleting all frames and adding new ones or to reset the whole animation to the default state.
Step 1 - initializing the animation (starting frame index is 0)
timerView.setBackgroundResource(R.drawable.timer_switch);
timerAnimation = (AnimationDrawable)timerView.getBackground();
System.out.println("Number of frames: " + timerAnimation.getNumberOfFrames());
for (int frameIndex = startingFrameIndex; frameIndex < 60; frameIndex++) {
if (frameIndex < 10) {
uri = "drawable/timer_0000" + frameIndex;
} else {
uri = "drawable/timer_000" + frameIndex;
}
imageResourceId = getResources().getIdentifier(uri, null, getPackageName());
timerAnimation.addFrame(getResources().getDrawable(imageResourceId), timerImageFrameDuration);
}
Step 2 - here's the tricky part where I don't know what to do. Things that I've tried:
timerAnimation.stop();
timerAnimation.setCallback(null);
timerAnimation.setVisibility(true, false);
timerAnimation = null;
Step 3 - after calling step 2 I call step 1 again, but the Sys.out still displays 60 as the current number of frames. (starting index here is set to the last hidden frame when pause button was tapped.)
Any idea is welcomed.
Thanks
This will send the (AnimationDrawable) timerAnimation to the first frame as soon as stop() has been called:
timerAnimation.stop();
timerAnimation.selectDrawable(0);
I had the same problem where stopping the animation would stop on the current frame. I wanted it to behave like iOS, where stopping would go back to the first frame. This solution works for me:
((AnimationDrawable)(someButton.getBackground())).stop();
someButton.setBackgroundDrawable(null);
someButton.setBackgroundResource(R.drawable.animation);
This first stops it (probably not necessary). Then it kills the background animation. Finally, it recreates the background.
Another possible solution would be to have the same image for the first frame and last frame and do the following instead of calling the stop() method.
((AnimationDrawable)(someButton.getBackground())).setOneShot(true);
if anyone does look into this any further. There is also a method called setVisible(boolean visible, boolean restart). However, that did not work for myself.
You can try public boolean setVisible (boolean visible, boolean restart) and it will play the animation once. For example:
animationDrawable.setVisible(false, true);
I would setVisibility(true, true):
timerAnimation.stop();
timerAnimation.setVisibility(true, true);
visible boolean: true if visible, false otherwise
restart boolean:
when visible, true to force the animation to restart from the first frame
android.view.animation.Animation.reset() doesnt work?