I am attempting to create a simple animation in which a series of bubble rotate around a centre point. I have one version of animation where the bubbles spread from the centrepoint before they begin to rotate, which works fine, but as soon as I click one of the images (which sparks the animation) the screen freezes for a moment and then the bubbles appear in their end position, rather than showing each step they made.
What I have so far is:
while(bubble[1].getDegree() != 270)
{
long time = System.currentTimeMillis();
//the below if statement contains the function calls for
//the rotating bubble animations.
next();
draw();
// delay for each frame - time it took for one frame
time = (1000 / fps) - (System.currentTimeMillis() - time);
if (time > 0)
{
try
{
Thread.sleep(time);
}
catch(Exception e){}
}
}
public void draw()
{
for(int i = 1; i < bubble.length; i++)
{
iconLabel[i].setLocation(bubble[i].getX(), bubble[i].getY());
textLabel[i].setLocation((bubble[i].getX()+10),(bubble[i].getY()+10));
}
}
For clarity, the method "next()" merely changes the position of the bubble to the appropriate place, I know this to be functioning as I have had the animation work before but once I implemented the animation to JLabels it stopped working.
Any help would be appreciated.
The drawing is frozen because you block the event dispatch thread. Drawing is done in the same thread as the while loop, and since the loop prevents anything else happening while it's running, swing can get to drawing only after the loop is finished, so only the last position is drawn.
Use a swing Timer instead:
timer = new Timer(delay, new ActionListener() {
public void actionPerformed(ActionEvent e) {
// whatever you need for the animation
updatePositions();
repaint();
}
});
timer.start();
And then call timer.stop() when all the frames you need have been processed.
Related
I have a Java Swing component that prints "hello" every 1 minute.
timer = new Timer();
timer.schedule(new HelloWordTask(), TIME, TIME);
However, I want to reset timertask when a user moves mouse.
int count = 0;
private CustomMouseAction extends MouseAdapter {
#Override
public void mouseMoved(MouseEvent e) {
timer.cancel();
timer = new Timer();
timer.schedule(new HelloWordTask(), TIME, TIME);
System.out.println("moved " + count++);
}
}
Whenever I am moving a mouse, my timer gets rescheduled, which is the expected behaviour. However, it means that new Timer is created for every "bit" of movement. For example, when I move my mouse around 5 cm, ~30 print statements show up.
Is there a way to make the program more efficient? Moreover, would it be possible to somehow "reduce" the mouseMoved detection rate? For example, instead of being called 30 times, can I make it only being called 10 times (I assume if this was possible, there is a small chance to miss refresh chance).
Test with different n values until you're satisfied.
int count = 0, lastX = 0, lastY = 0, n = 30;
private CustomMouseAction extends MouseAdapter {
#Override
public void mouseMoved(MouseEvent e) {
int ix= e.getX();
int iy= e.getY();
if (Math.abs(lastX-ix)<n && (Math.abs(lastY-iy)<n) return;
lastX= ix;
lastY= iy;
timer.cancel();
timer = new Timer();
timer.schedule(new HelloWordTask(), TIME, TIME);
System.out.println("moved " + count++);
}
}
For example, when I move my mouse around 5 cm, ~30 print statements show up.
Is there a way to make the program more efficient?
This is the whole point of event driven programming. The OS generates the event so you know the user is doing something. You can't control how frequently the events are generated. You can only control the processing you do when the event is generated.
However, it means that new Timer is created for every "bit" of movement.
You should not be using a util.Timer. Instead you should be using a javax.swing.Timer.
Don't keep creating a new Timer in the mouseMoved() method. Instead you should create and start the Timer when your frame is made visible. Then in the mouseMoved() method you just invoke the restart() method of the Timer.
See: Application Acvitity for a reusable class that you may find helpful.
I have this loop
while (true) {
game.update();
view.repaint();
Thread.sleep(DELAY);
}
In the game.update various components of the game have their position changed and those updates are reflected when the repaint() method is called on the view. The view extends JComponent and loops through the game objects and calls their print methods.
What I want to do is have a boolean called nextLevel in the game and if it's true Flash text on the screen for the player to notify them that they're going onto the next level. Maybe flash 4-5 times. Then continue the game.
Is this possible? I have been playing around with Thead.Sleep() but this only seems to pause the displaying and in the background the game is still going on.
Any ideas on how to do this?
Maybe you want to avoid threading by using a Timer object.
an example like that could be
int flashTimer = 0;
if(nextLevel) {
Timer timer = new Timer(1000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
//flash something method here
flashTimer++;
}
});
timer.start();
}
and then check your flashTimer if it reaches the number you want then just stop the timer by timer.stop();
Just an idea which seems to me a bit simpler. the 1000 value is milliseconds which is passed and executes the code inside the actionPerformed method every 1 sec.
Hope it helped
I'm attempting to get an animation working in a game I'm developing. The animation works by setting a button size to very small, then gradually growing it to its normal size again. I have it working, except I'm having timing issues.
Sometimes the button will grow almost instantly, sometimes it goes VERY slow. I'm looking for something inbetween, and I need it to ALWAYS grow at that size, not some times fast sometimes slow.
I've looked into it and I found this pseudocode:
distance_for_dt = speed * delta_time
new_position = old_position + distance_for_dt
Unfortunately I don't understand what's being said, and I don't know how to apply this to my code. Can anyone help with that or explain what's being said in the above pseudocode?
Here's my timer code, timer is already defined above as a Timer, and z[] is just a pair of coordinates:
timer = new Timer(18, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Dimension dim = button[z[0]][z[1]].getSize();
if (dim.getHeight() < 79.9) {
button[z[0]][z[1]].setSize((int) (dim.getWidth() + 6), (int) (dim.getHeight() + 6));
} else {
button[z[0]][z[1]].setSize(80, 80);
timer.stop();
}
}
});
timer.start();
Depending on how many updates you're calling on your Swing application, it may be getting "backed up" and slowing down. For instance, if you wanted to accomplish the animation without a Timer, you could just do something like this:
// example method to do animation
public void animateButton(final int wait){
Thread thread = new Thread(){
public void run(){
// some loop structure to define how long to run animation
Dimension dim = button[z[0]][z[1]].getSize();
while (dim.getHeight() < 79.9){
SwingUtilities.invokeLater(new Runnable(){
//update Swing components here
});
try{ Thread.Sleep(wait); }
catch(Exception e){}
}
}
}
}
thread.start();
}
I think this may be similar to how a Timer updates the GUI, as Timers run on a separate thread. I would look into whether or not you need to use invokeLater(new Runnable) inside a timer to properly schedule the task. I had to do this to allow a project I was working on to keep responsive during long tasks. If you really needed to ensure the speed and maybe DROP updates to adjust for system lag, then you'll need to be calculating how complete the animation is vs how much time has passed, using a method call such as System.currentTimeMillis() or System.nanoTime(). Then, adjust accordingly for each step of the animation.
In my game I want to draw the screen black after losing or winning a level and then draw a message in white on to the screen. After a few seconds delay I then want the screen to disappear when touched. Below is part of my draw() method. The problem is that screen freezes (or the thread sleeps) before the screen is drawn black and the text is drawn, even though the sleep command is after the text and canvas is drawn. Any ideas why this is happening?
if (state == WIN || state == LOSE){
canvas.drawColor(Color.BLACK);
message = "Touch Screen To Start";
canvas.drawText(message + "", mCanvasWidth / 2, mCanvasHeight / 2, white);
try {
GameThread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
I have a feeling that the canvas function doesn't actually display anything until it returns. Especially if you are running on Android >3.0 with hardware acceleration, or any configuration with double buffering, it won't actually update the screen until it finishes.
Instead when you draw the black screen, store the current time. Something like:
mStartTime = System.currentTimeMillis();
Then in the function watching for presses, check how many seconds have passed and see if enough time is happening, something like:
if( (System.currentTimeMillis() - mStartTime)/1000 > 5){
//Put code here to run after 5 seconds
}
This should draw your text and avoid blocking the Ui thread (a big no no in every respect).
It could be that the call to drawText is taking a few fractions of a second longer than you realize, and since you immediately call sleep, you are actually sleeping the thread before you draw.
Try putting a small loop, for( i < 10000 ) or something before the call to sleep and see if that helps.
Use CountDownTimer
http://developer.android.com/reference/android/os/CountDownTimer.html
new CountDownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
mTextField.setText("seconds remaining: " + millisUntilFinished / 1000);
// Here you do check every second = every 1000 milliseconds
}
public void onFinish() {
// Here you can restart game after 30 seconds which is 30K milliseconds.
mTextField.setText("done!");
}
}.start();
I wanted to animate a line on the view. Ex: A progressive line starting at (0,120) and progresses upto (100,120). I've already tried this with plain canvas.drawLine() but was unable to apply an animation while drawing a line.
What I wanted to see is once the view is loaded a set of straight lines(of varying length) being drawn on the view. I don't want them as static lines. I wanted to see these lines when they are being drawn on the canvas.
I've tried couple of other options like, using the shape drawables and applying animations from the anim/xmls. Most of them didn't solve my problem. Extensive googling show the animations which are applied to the views directly. Here I dont want to create multiple image views as I'll end up having 6 lines on the view and i need to animate each of the line with different colors.
In future I should be able to move the lines up and down change there colors and do other kind of animations on each one of the lines.
Remembering the above constraints can you suggest me how to write a custom implementation for the same.
well are you not just using canvas.drawline(...), or canvas.drawlines(...), Your View could have the variables which represent the lines, maybe an arraylist of Points or something. I am currently trying to draw a line with moving values on a game I am making. I simply just change the values put into the drawline function, and my line animates as those values change. However it seams whenever the line has a slope closer to 1 my loop slow down and my other animations slow along with it. Are you having a similar problem when animating the lines? or are you just not able to get them drawn?
it sounds like your problem is in your game loop... I use a thread to loop through my draw and update methods, as I never was able to get the invalidate() thing working...
so below is a class called mainthread, it is created in your surfaceview in this case the surfaceview is called DrawView...
import android.graphics.Canvas;
import android.view.SurfaceHolder;
public class MainThread extends Thread {
// desired fps
private final static int MAX_FPS = 75;
// maximum number of frames to be skipped
private final static int MAX_FRAME_SKIPS = 0;
// the frame period
private final static int FRAME_PERIOD = 1000 / MAX_FPS;
// Surface holder that can access the physical surface
private SurfaceHolder surfaceHolder;
// The actual view that handles inputs
// and draws to the surface
private DrawView gamePanel;
// flag to hold game state
public boolean running;
public void setRunning(boolean running) {
this.running = running;
}
public MainThread(SurfaceHolder surfaceHolder, DrawView gamePanel) {
super();
this.surfaceHolder = surfaceHolder;
this.gamePanel = gamePanel;
}
#Override
public void run() {
Canvas canvas;
long beginTime; // the time when the cycle begun
long timeDiff; // the time it took for the cycle to execute
int sleepTime; // ms to sleep (<0 if we're behind)
int framesSkipped; // number of frames being skipped
sleepTime = 0;
while (running) {
canvas = null;
// try locking the canvas for exclusive pixel editing
// in the surface
try {
canvas = this.surfaceHolder.lockCanvas();
synchronized (surfaceHolder) {
beginTime = System.currentTimeMillis();
framesSkipped = 0; // resetting the frames skipped
// update game state
this.gamePanel.doUpdate();
// render state to the screen
// draws the canvas on the panel
this.gamePanel.doDraw(canvas);
// calculate how long did the cycle take
timeDiff = System.currentTimeMillis() - beginTime;
// calculate sleep time
sleepTime = (int)(FRAME_PERIOD - timeDiff);
if (sleepTime > 0) {
// if sleepTime > 0 we're OK
try {
// send the thread to sleep for a short period
// very useful for battery saving
Thread.sleep(sleepTime);
} catch (InterruptedException e) {}
}
while (sleepTime < 0 && framesSkipped < MAX_FRAME_SKIPS) {
// we need to catch up
this.gamePanel.doUpdate(); // update without rendering
sleepTime += FRAME_PERIOD; // add frame period to check if in next frame
framesSkipped++;
}
}
} catch(ClassCastException cce) {
}finally {
// in case of an exception the surface is not left in
// an inconsistent state
if (canvas != null) {
surfaceHolder.unlockCanvasAndPost(canvas);
}
} // end finally
}
}
}
using this thread it will call your update and draw methods approprietly, for onTouch just override the surfaceview (DrawView)'s onTouch method to access it normally. in order to stop the thread for what ever reason just set running to false.