Using Thread.sleep(milliseconds) would delay execution of the whole program for the specified milliseconds. My problem is how do I slow down (not delay) object movement from one container into another container in my java code (implemented using JOGL - from canvas context) , so that the movement is noticeable which otherwise happens so fast?
Here is my approach for the problem: I use Stack to represent the amount of objects on each containers. Whenever user clicks on either of the container[source], the containers Stack is to be popped until it is empty. At the same time Stack of the destination container is to be pushed. for each iteration, the containers are redrawn containing objects represented by their corresponding Stack size.
fraction of the code relevant for this Question:
public void moveObjects(Container source, Container destination) {
while (!source.stack.isEmpty()) {
destination.stack.push(destination.stack.size() + 1);
source.stack.pop();
//redraw both containers with their new amount of objects represnted using their stack size
}
}
or
public void moveObject(int source, int dest) {
while (!this.container[source].stack.isEmpty()) {
this.container[dest].stack.push(this.container[dest].stack.size() + 1);
this.container[source].stack.pop();
try {
Thread.sleep(100);
} catch (InterruptedException ie) {
// Handle exception here
}
}
}
I have only managed to move the objects from the source to destination one by one but the movement is too fast to be noticed by eye. How do I aproach this problem?
If I understand you correctly you want to move multiple objects visibly on the screen without this happening instantaneous.
As you have noticed Thread.sleep(time) is a bad idea as it freezes the whole application.
A way around this is to supply your update logic with the elapsed time:
long lastTime = System.nanoTime();
while(running)
{
long now = System.nanoTime();
updateLogic(now-lastTime); //this handles your application updates
lastTime = now;
}
void updateLogic(long delta)
{
...
long movementTimespan +=delta
if(movementTimespan >= theTimeAfterWhichObjectsMove)
{
//move objects here
//...
movementTimespan -= theTimeAfterWhichObjectsMove;
}
//alternatively you could calculate how far the objects have moved directly from the delta to get a smooth animation instead of a jump
//e.g. if I want to move 300 units in 2s and delta is x I have to move y units now
}
This allows you to track the time since the last update/frame and if you use it for animation it makes the speed of the object movement independent from the executing systems spees.
Related
I am beginner when it comes to java and I have come across with a problem that I haven't found a solution to just yet. The thing is that I have working methods for drawing an letter and also for rotating it - when I set rotation it works the way it should. However I would like to make this slightly more interactive, at school we were given the basic framework for that - I was able to create a button that when you click on it the letter's angle changes and the letter is redrawed correctly. But I would like to make it an animation, for example you click on the button and for 10 seconds (or until you press the button again) the letter will be rotating.
On the internet I found a way to perform an action after certain period of time, and I thought I will use this. I wanted to add an angle and redraw an image, after let's say 1 second, then it would repeat - I thought this would make it look like it is animated. But I was wrong. I tried so many ways to do this, the best thing was that after few seconds that I set I want the animation to go for, it changed an angle and redraw, unfortunately it was the final state and it didn't draw states in between to create an animation. And this latest code doesn't even do that, the program just freezes.
int animation = 0;
int steps = 0;
public void G_draw() {
graphic.clear();
if (animace==1)
{
animation();
}
letter('a', G_Color.G_cBlack, 2, 2);//drawing an letter
}
public void G_mousePressed(G_Button button, int x, int y) {
if (button.equals(G_Button.B_LEFT)&&x>700&&x<750&&y>500&&y<520){
animation=1;
G_draw();
}
}
public void animation() {
long start = System.currentTimeMillis();
long end = start + 2 * 1000;
while (System.currentTimeMillis() < end) {
}
langle+=30; // adding an angle
steps++;
G_repaint();
G_draw();
if (steps<4) animace();
}
instead of this
long start = System.currentTimeMillis();
long end = start + 2 * 1000;
while (System.currentTimeMillis() < end) {
}
use
Thread.sleep(# in milliseconds);
We can't see where you use langle
This line if (steps<4) animace(); only runs when animace<>1 otherwise it's skipped because animate()calls G_draw() calls animate and so on.
I have a problem with my java game. I’m beginner, but i have to write it as a school project.
Game is called „Birthday Cake” there is 7 candles on the cake and randomly one of it is showing for let say 30s and during this time u have to click on it to get point, if u don’t click on it during this time next candle will show. Game end when 10 candle shows.
I made for loop and i tried to make it work for sooo long that I’m dying from frustration
my for loop works but it is so fast that i use Thread.sleep(1000), i tried lots of solutions it looks ok. BUT when i start my game nothing is happening and after few seconds all 7 candles shows and quickly disappear. I think I’m doing something wrong, but i have no idea what.
if(Dane.start){
int liczbaLosowa = 0;
for(int i=0; i<10 ;i++){
liczbaLosowa = (int)(Math.random()*7);
this.wspX= wspX_p[liczbaLosowa];
this.wspY= wspY_p[liczbaLosowa];
g2d.drawImage(plomienImg, wspX, wspY,null);
Toolkit.getDefaultToolkit().sync();
try {
Thread.sleep(1000);
} catch (Exception ex) { }
//repaint();
}
Dane.start=false;
}
this loop is inside JPanel paintComponent...
Never,
Never,
NEVER
call Thread.sleep(...) inside of paintComponent ever. Please understand that this method largely determines the perceived responsiveness of your program and anything that slows it down or freezes it will severely slow down and freeze your GUI. In fact you should never call Thread.sleep inside the code of most Swing programs (all that runs on the Swing event thread) but doing so in paintComponent is an even worse sin. The solution is to use a Swing Timer, and put code that you want to be called repeatedly at regular intervals inside of the Timer's ActionListener's actionPerformed code. Within this method, change the value held by fields within your class, for instance wspX and wspY, call repaint(), and then use those fields inside of paintComponent to determine what gets painted where.
Thread.sleep() is a bad call which can lead into many problems. i was told to never use it. instead i will show you the way i do my game loops. it might not be the perfect game loop but it is good.
i recommand implemets runnable and putting your loop in your run method.
public void run(){
init(); //initialisation of images, sound..etc. will be executed once only
int fps = 60 //number of update per second.
double tickPerSecond = 1000000000/fps;
double delta = 0;
long now;
long lastTime = System.nanoTime();
while(running){
now = System.nanoTime();
delta += (now - lastTime)/tickPerSecond;
lastTime = now;
if(delta >= 1){
tick();
render();
delta--;
}
}
}
private void init(){
//initialisation image, sound, loading world, generate maps....etc
}
private void tick(){
//tick player, world, entities..etc
}
private void render(){
//render graphics.
}
also dont forget to create start and stop method for the thread. you can change the fps to what number you would like, no need to go higher than 60.
I am (still) working on a game, and as it nears completion, new problems arise. So here's the short story:
After fixing a few bugs and implementing new features, I may -or may not, have run into a small 'memory' issue. Each level has a set amount of time that the player has to solve it. When this time runs out, the level reloads. It is after this reloading, be it after failing to solve a level in time or after completing a level, that the game gradually starts slowing down. My timer ticks every second, the level reloads at the same speed, but when moving objects after X-reloads, they move more sluggish/laggish, as if skipping frames.
I have looked at my ArrayLists, and they are neatly (up for debate) empties, and my Timers are reset aswel. Below is some of the (relevant) code I'm using:
OnTick() in my Update-timer
MoveObjects() moves all objects, updateDraw() updates the screen. This timer has a 15x1000ms timer with a 250ms tickspeed
public void onTick(long millisUntilFinished) {
if(!loadingNewLevel)
MoveObjects();
updateDraw();
}
prepareNewLevel
This function prepares all necessary variables for a new level. It is called at both a level-reset and a level-completion
public void prepareNewLevel(){
level.clear();
movables.clear();
totalSolved = 0;
solvable = 0;
levelWidth = 0;
levelHeight = 0;
allCollided = false;
}
updateDraw(); refreshes the screen
public void updateDraw(){
RelativeLayout rl = (RelativeLayout)findViewById(R.id.game);
rl.removeAllViewsInLayout();
//Level
for(GameObject go : level){
ImageRAW(go.spriteID, R.id.game, go.position.x, go.position.y);
}
for(GameObject go : movables){
ImageRAW(go.spriteID, R.id.game, go.position.x, go.position.y);
}
//Timer
if(remaining_time >= 10000)
TextViewRAW(TIMER_ID, R.id.game, 32, 32, "00:"+String.valueOf(remaining_time/1000)+" Level "+String.valueOf(currLevel+1), 18, 0);
else
TextViewRAW(TIMER_ID, R.id.game, 32, 32, "00:0"+String.valueOf(remaining_time/1000)+" Level "+String.valueOf(currLevel+1), 18, 0);
}
Now, the latter piece of code I posted is why I surmise something is wrong with my memory-management, as I am directly drawing on to the screen from my RAW folder. How do I handle the memory of directly-drawn RAW files, if this is the case?
I will also give you access to some of the relevant Java files:
https://www.dropbox.com/s/kqu7sfi8qnlt9w6/Game.java?dl=0
https://www.dropbox.com/s/9ofpg1xj4anlvi0/UtilLib.java?dl=0
The latter of these files contains functions I'm using throughout the project, such as the ImageRAW() function mentioned earlyer.
-Zubaja
I'm working on an application that records the users screen, webcam and microphone whilst he/she is performing certain activities. It will be used for research purposes. The application has been successfully tested on Windows, but on Mac OS X (Maverick with Java 7.0.45) the application becomes slow and unresponsive when recording is started.
This is why I find this difficult to comprehend:
The recording is done in a separate thread, so how could it influence the responsiveness of another thread? Especially as after each run either Thread.yield() or Thread.sleep(...) are called.
Logs show that whilst attempting to record at 15 FPS, the resulting frame rate was 2 FPS. So it seems the code that does the capturing of a single frame might be too slow. But why then does it work fine on Windows?
Just a quick note: the application was successfully tested by tons of users on Windows, but I only got to test it on a single Mac. However, that one was just formatted and got a clean install of OS X Maverick, Java (and Netbeans).
Below you will find the code that records the screen and writes it to a video using Xuggler. The code for recording the webcam is similar, and I'd doubt recording the audio has anything to do with it. My question is:
What might be the cause of the application becoming unresponsive?, and
How could the code be made more efficient and so improve FPS?
IMediaWriter writer = ToolFactory.makeWriter(file.getAbsolutePath());
Dimension size = Globals.sessionFrame.getBounds().getSize();
Rectangle screenRect;
BufferedImage capture;
BufferedImage mousePointImg;
writer.addVideoStream(0, 0, ICodec.ID.CODEC_ID_H264, size.width, size.height);
int i = 0;
while (stop == false) {
// Get mouse cursor to draw over screen image.
PointerInfo mousePointer = MouseInfo.getPointerInfo();
Point mousePoint = mousePointer.getLocation();
Point screenPoint = new Point((int) (mousePoint.getX() -
Globals.sessionFrame.getBounds().getX()), (int) (mousePoint.getY() -
Globals.sessionFrame.getBounds().getY()));
// Get the screen image.
try {
screenRect = new Rectangle(Globals.sessionFrame.getBounds());
capture = new Robot().createScreenCapture(screenRect);
} catch ( ... ) { ... }
// Convert and resize the screen image.
BufferedImage image = ConverterFactory.convertToType(capture,
BufferedImage.TYPE_3BYTE_BGR);
IConverter converter = ConverterFactory.createConverter(image,
IPixelFormat.Type.YUV420P);
// Draw the mouse cursor if necessary.
if (mouseWithinScreen()) {
Graphics g = image.getGraphics();
g.drawImage(mousePointImg, (int) screenPoint.getX(),
(int) screenPoint.getY(), null);
}
// Prepare the frame.
IVideoPicture frame = converter.toPicture(image, (System.currentTimeMillis() -
startTimeMillis()) * 1000);
frame.setKeyFrame(i % (getDesiredFPS() * getDesiredKeyframeSec()) == 0);
// Write to the video
writer.encodeVideo(0, frame);
// Delay the next capture if we are at the desired FPS.
try {
if (atDesiredFPS()) {
Thread.yield();
} else {
Thread.sleep(1000 / getDesiredFPS());
}
} catch ( ... ) { ... }
i++;
}
writer.close();
There are several architectural issues that I can see in your code:
First if you want to execute something at a fixed rate, use the ScheduledThreadPoolExecutor.scheduleAtFixedRate(...) function. It will make your entire delay code part obsolete as well as ensuring that certain OS timing issues will not interfere with your scheduling.
Then to make things faster you need to take your code apart a bit. As far as I can see you have 3 tasks: the capture, the mouse-drawing/conversion and the stream writing. If you put the capture part in a scheduled Runnable, the conversion into multi-parallel execution as Callables into an Executor, and then in a 3rd thread take the results from a result list and write it into the stream, you can fully utilize multi-cores.
Pseudocode:
Global declarations (or hand them over to the various classes):
final static Executor converterExecutor = Executors.newFixedThreadPoolExecutor(Runtime.getRuntime().availableProcessors());
final static LinkedBlockingQueue<Future<IVideoPicture>> imageQueue = new LinkedBlockingQueue<>();
// ...
Capture Runnable (scheduled at fixed rate):
capture = captureScreen();
final Converter converter = new Converter(capture);
final Future<IVideoPicture> conversionResult = converterExecutor.submit(converter);
imageQueue.offer(conversionResult); // returns false if queue is full
Conversion Callable:
class Converter implements Callable<IVideoPicture> {
// ... variables and constructor
public IVideoPicture call() {
return convert(this.image);
}
}
Writer Runnable:
IVideoPicture frame;
while (this.done == false) {
frame = imageQueue.get();
writer.encodeVideo(0, frame);
}
You can ensure that the imageQueue does not overflow with images to render if the CPU is too slow by limiting the size of this queue, see the constructor of LinkedBlockingQueue.
Alright, i'm making a small game, and I need to limit my FPS, because, when I play on my really fast computer, I have around 850 FPS, and the game will go like, REALLY fast, and when I switch to my older computer, it goes alot slower, so I will need to limit my FPS to get this right. How do I limit my FPS?
My main game loop:
public void startGame(){
initialize();
while(true){
drawScreen();
drawBuffer();
plyMove();
//FPS counter
now=System.currentTimeMillis();
framesCount++;
if(now-framesTimer>1000){
framesTimer=now;
framesCountAvg=framesCount;
framesCount=0;
}
try{
Thread.sleep(14);
}catch(Exception ex){}
}
}
How I draw the screen, and draw all of the other things, players, the ball, etc.
The game is a pong remake, btw.
public void drawBuffer(){
Graphics2D g = buffer.createGraphics();
g.setColor(Color.BLACK);
g.fillRect(0,0,600,500);
g.setColor(Color.GREEN);
g.fillRect(ply1.getX(),ply1.getY(),ply1.getWidth(),ply1.getHeight());
g.setColor(Color.RED);
g.fillRect(ply2.getX(),ply2.getY(),ply2.getWidth(),ply2.getHeight());
g.setColor(Color.WHITE);
g.fillOval(ball1.getX(),ball1.getY(),ball1.getWidth(),ball1.getHeight());
g.drawString("" + framesCountAvg,10,10);
}
public void drawScreen(){
Graphics2D g = (Graphics2D)this.getGraphics();
g.drawImage(buffer,0,0,this);
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
It sounds like your display it tied to your game engine. Make sure the two are disconnected. You want the game playing at the same speed no matter what the framerate is. If your fast computer repaints the screen faster that is ok if the engine is causing the game to play at a constant speed.
Rather than limiting your FPS, make it so that the game doesn't go really fast when the fps is high.
Presumably you have code that does certain things each frame e.g. moves the character forward if a button is pressed. What you want to do instead is move the character forward an amount dependent on the amount of time that has passed since the previous frame.
As aforementioned you need to separate your display loop from your update loop somewhere at the core of you game there is probably something like this
while (1)
{
drawscene();
update();
}
and in update you are advancing the time by a fixed amount e.g 0.17 sec. If you drawing at exactly 60fps then the animations are running in realtime, at 850fps everything would be sped by a factor 14 (0.17*850) to prevent this you should make your update time dependent. e.g.
elapsed = 0;
while (1)
{
start = time();
update(elapsed);
drawscene();
sleep(sleeptime);
end = time();
elapsed = end - start;
}
A description of what I meant in my comment. Inside your method plyMove(); I suspect there is something like
plyMove() {
ply1.x += amountX;
ply1.y += amountY;
}
Instead make the movement depending on the time elapsed
plyMove(double timeElapsed) {
ply1.x += amountX * timeElapsed;
ply1.y += amountY * timeElapsed;
}
where you calculate timeElapsed from the time difference inside your main loop and scale it accordingly to get a decent movement.
double timePrev = System.currentTimeMillis();
while(true) {
double timeNow = System.currentTimeMillis();
double elapsed = timeNow - timePrev;
drawScreen();
drawBuffer();
plyMove(0.001 * elapsed);
timePrev = timeNow;
}
If you really want a fixed timeframe game you could do this:
float timer = 0;
float prevTime= System.currentTimeMillis();
while(true)
{
draw();
float currentTime = System.currentTimeMillis();
timer += currentTime - prevTime;
while (timer > UPDATE_TIME) // To make sure that it still works properly when drawing takes too long
{
timer -= UPDATE_TIME;
update();
}
}
Where UPDATE_TIME is at what interval you want to update at in milliseconds.
One way would be using
try {
Thread.sleep(20);
} catch(InterruptedException e) {}
at the end of the main loop. Adjust the number to your needs.