Pausing and resuming android game -> - java

I'm having difficulties pausing and resuming my game. I am presented with an error IllegalThreadStateException, but what is interesting here is that this code runs well and without issues on API 24. Testing on higher API's is where I run into troubles. Am I missing something? Any tips? I'm still a beginner so thank you all!
public class GameLoop extends Thread {
private final SurfaceHolder surfaceHolder;
private Game game;
public static final float MAX_UPS = 60;
private static final double UPS_PERIOD = 1E+3 / MAX_UPS;
public static boolean isRunning = false;
private double avarageUPS;
private double avarageFPS;
public GameLoop(Game game, SurfaceHolder surfaceHolder) {
this.game = game;
this.surfaceHolder = surfaceHolder;
}
public void startLoop() {
Log.d("GameLoop.java", "startLoop()");
isRunning = true;
start();
}
public void stopLoop() {
Log.d("GameLoop.java", "stopLoop()");
isRunning = false;
// Wait for thread to join
try {
join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#Override
public void run() {
Log.d("GameLoop.java", "run()");
super.run();
//Declare time and cycle count variables
int updateCount = 0;
int frameCount = 0;
long startTime;
long elapsedTime;
long sleepTime;
//Game loop
Canvas canvas = null;
startTime = System.currentTimeMillis();
while(isRunning){
//Poskusi posodobiti in render game
try{
canvas = surfaceHolder.lockCanvas();
synchronized (surfaceHolder){
game.update();
updateCount++;
game.draw(canvas);
}
}catch(IllegalArgumentException e){
e.printStackTrace();
}finally {
if(canvas != null){
try{
surfaceHolder.unlockCanvasAndPost(canvas);
frameCount++;
}catch(Exception e) {
e.printStackTrace();
}
}
}
//Pause game loop to not exceed target UPS
elapsedTime = System.currentTimeMillis() - startTime;
sleepTime = (long) (updateCount * UPS_PERIOD - elapsedTime);
if(sleepTime > 0){
try {
sleep(sleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//Skip frames to keep up with target UPS
while(sleepTime < 0 && updateCount < MAX_UPS-1){
game.update();
updateCount++;
elapsedTime = System.currentTimeMillis() - startTime;
sleepTime = (long) (updateCount * UPS_PERIOD - elapsedTime);
}
//Calculate avarage UPS in FPS
elapsedTime = System.currentTimeMillis() - startTime;
if(elapsedTime >= 1000){
avarageUPS = updateCount / (1E-3 * elapsedTime);
avarageFPS = frameCount / (1E-3 * elapsedTime);
updateCount = 0;
frameCount = 0;
startTime = System.currentTimeMillis();
}
}
}
public double getAvarageUPS() {
return avarageUPS;
}
public double getAvarageFPS() {
return avarageFPS;
}
}

If you're trying to call start again on the same thread, you can't. After a thread finishes, you'd need to create a new instance, the same instance can't be rerun.

Related

Android delay inside while loop

I have a class extending Thread. Inside this run I have a few method working in while loop. Now I want one of this methods gameSurface.updateBitmapObjects() to work with delay. How to achieve this? Here is my code:
GameThread.java:
public class GameThread<T extends GameSurface> extends Thread {
private boolean isRunning;
private long startTime, loopTime;
private long delay = 33;
private SurfaceHolder surfaceHolder;
private T gameSurface;
public GameThread(SurfaceHolder surfaceHolder, T gameSurface) {
this.surfaceHolder= surfaceHolder;
this.gameSurface = gameSurface;
isRunning = true;
}
#Override
public void run() {
while(isRunning) {
startTime = SystemClock.uptimeMillis();
Canvas canvas = surfaceHolder.lockCanvas(null);
if(canvas != null) {
synchronized (surfaceHolder) {
gameSurface.updateBitmapObjects();
gameSurface.drawMapBitmap(canvas);
((GameMainSurface)gameSurface).drawCoinAndCoins();
((GameMainSurface)gameSurface).drawFieldLines(canvas);
((GameMainSurface)gameSurface).updatePlayersLabels(canvas);
if (((GameMainSurface)gameSurface).isGameMainFragment()) {
((GameMainSurface)gameSurface).setSomeValues();
}
gameSurface.drawObjects(canvas);
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
loopTime = SystemClock.uptimeMillis() - startTime;
if(loopTime < delay) {
try {
Thread.sleep(delay - loopTime);
}
catch (InterruptedException e) {
Log.e("Interupted ex", e.getMessage());
}
}
}
}
}
GameMainSurface.java:
(...)
public void updateBitmapObjects() {
this.chibi1.update();
(...)
}
MovingObject.java:
// I want this method to work with delay let's say 100 ms
public void update() {
this.colUsing++;
if (colCount == 13) {
if (colUsing >= 9) {
if (rowUsing == ROW_TOP_TO_BOTTOM_CHIBI || rowUsing == ROW_BOTTOM_TO_TOP_CHIBI)
colUsing = 1;
else
colUsing = 0;
}
}
if (colCount == 4) {
if (colUsing >= 4) {
this.colUsing = 0;
}
}
}

Does my animation class keep too many images in RAM unnecessarily?

I have an animation class ready for my game. I think there are some optimization issues in this classroom.
Let's say there are more than 10 living entities with the same animations in my game.
Although they all have different animation times, the pictures of their animations are the same. When the code is like this, instead of keeping 2 pictures in RAM, wouldn't 20 pictures be kept? Code;
Animation idle;
BufferedImage idle1,idle2;
ArrayList<Soldier> enemyArmyArray = new ArrayList<Soldier>();
ArrayList<Animation> armyIdleAnimations = new ArrayList<Animation>();
w_idleImage1 = ImageIO.read(getClass().getResource("/Data/idle1.png"));
w_idleImage2 = ImageIO.read(getClass().getResource("/Data/idle2.png"));
for(int z = 0 ; z <= 10 ; z++) {
Soldier s = new Soldier();
armyArray.add(s);
idle = new Animation();
idle.addFrame(idle1, 400);
idle.addFrame(idle2, 400);
armyIdleAnimations.add(idle);
}
and this is my animation class:
public class Animation {
private ArrayList frames;
private int currentFrame;
private long animTime; // long takes up more memory than int but can hold
// more accurate numbers.
private long totalDuration;
public Animation() {
frames = new ArrayList();
totalDuration = 0;
synchronized (this) {
animTime = 0;
currentFrame = 0;
}
}
public synchronized void addFrame(BufferedImage image, long duration) {
totalDuration += duration;
frames.add(new AnimFrame(image, totalDuration));
}
public synchronized void update(long elapsedTime) {
if (frames.size() > 1) {
animTime += elapsedTime;
if (animTime >= totalDuration) {
animTime = animTime % totalDuration;
currentFrame = 0;
}
while (animTime >= getFrame(currentFrame).endTime) {
currentFrame++;
}
}
}
public synchronized BufferedImage getImage() {
if (frames.size() == 0) {
return null;
} else {
return getFrame(currentFrame).image;
}
}
private AnimFrame getFrame(int i) {
return (AnimFrame) frames.get(i);
}
private class AnimFrame {
BufferedImage image;
long endTime;
public AnimFrame(BufferedImage image, long endTime) {
this.image = image;
this.endTime = endTime;
}
}
public int getCurrentFrame() {
return currentFrame;
}
public void setCurrentFrame(int currentFrame) {
this.currentFrame = currentFrame;
}
public long getAnimTime() {
return animTime;
}
public void setAnimTime(long animTime) {
this.animTime = animTime;
}
}

Use of a thread messes up my pausing system

There is something wrong with my code. The timer overall seems to be working fine and the pause button does its job.
The problem is when you pause the clock at a specific time and then you unpause it.
If we (let's say) pause it at 8 seconds and we unpause it after a minute, it doesn't keep going like 9-10-11, etc. It goes 74-75-76... (I've broken it into minutes and seconds).
Is it a thread that causes the problem? (Also, I've overused freeze_sec and freeze_min time code snippets just to see if it would be fixed but it wasn't.)
Here is the code:
Thread t1 = null;
ss = new ServerSocket(6800);
while(true) {
s = ss.accept();
isr = new InputStreamReader(s.getInputStream());
br = new BufferedReader(isr);
message = br.readLine();
if (message.equals("START")) {
t1 = new Thread(new Thread1());
t1.start();
...
} else if (message.equals("PAUSE")) {
if(check) {
try {
check = false;
Thread1.PAUSE(true);
} catch (Exception e) {
System.out.println("Exception e");
}
} else {
check = true;
Thread1.PAUSE(false);
}
}
And Thread1 class looks like:
import java.io.*;
import java.util.Date;
import java.util.Scanner;
public class Thread1 extends MyServerFrame implements Runnable{
private static int current_min_time = 0;
private static int current_sec_time = 0;
private static int freeze_min_time = 0;
private static int freeze_sec_time = 0;
private static boolean pause = false;
private static int minutes = 0;
private int total_time_sec = 0;
private static boolean freeze_signal = false;
private static int k = 0;
#Override
public void run() {
long elapsedTime = 0L;
boolean bool = true;
int num = 0;
while (bool) {
Scanner scan = new Scanner(System.in);
if (minutes == 0) {
System.out.println("How many minutes for this half-time?");
Scanner in = new Scanner(System.in);
num = in.nextInt();
minutes = num;
}
long startTime = System.currentTimeMillis();
while (total_time_sec < minutes * 60 || freeze_signal == false) {
if (freeze_signal && k == 0) {
freeze_sec_time = current_sec_time;
freeze_min_time = current_min_time;
k++;
}
if (!pause) {
//perform db poll/check
if (elapsedTime / 1000 != current_sec_time) {
try {
clearTheFile("Half_Time.txt");
} catch (IOException e) {
System.out.println("Exception");
}
if (!freeze_signal && k > 0) {
current_sec_time = freeze_sec_time;
current_min_time = freeze_min_time;
k = 0;
}
current_sec_time++;
total_time_sec = current_sec_time + current_min_time / 60;
print_in_txt();
}
elapsedTime = (new Date()).getTime() - startTime;
if (current_sec_time == 60) {
if (!freeze_signal && k > 0) {
current_sec_time = freeze_sec_time;
current_min_time = freeze_min_time;
try {
clearTheFile("Half_Time.txt");
} catch (IOException e) {
System.out.println("Exception");
}
print_in_txt();
k = 0;
}
current_sec_time = 0;
current_min_time++;
total_time_sec = current_sec_time + current_min_time / 60;
startTime = System.currentTimeMillis();
elapsedTime = (new Date()).getTime() - startTime;
try {
clearTheFile("Half_Time.txt");
} catch (IOException e) {
System.out.println("Exception");
}
print_in_txt();
}
}
}
}
}
public static void clearTheFile(String txt_name) throws IOException {
try {
FileWriter fwOb = new FileWriter(txt_name, false);
PrintWriter pwOb = new PrintWriter(fwOb, false);
pwOb.flush();
pwOb.close();
fwOb.close();
} catch (IOException e) {}
}
public static void print_in_txt() {
PrintWriter out;
try {
out = new PrintWriter("Half_Time.txt");
out.println(String.format("%02d", current_min_time) + ":" + String.format("%02d", current_sec_time));
out.print("");
out.close();
} catch (FileNotFoundException e) {
System.err.println("File doesn't exist");
e.printStackTrace();
}
}
public static void PAUSE(boolean p) {
if (p) {
pause = true;
freeze_signal = true;
} else {
current_sec_time = freeze_sec_time;
current_min_time = freeze_min_time;
try {
clearTheFile("Half_Time.txt");
} catch (IOException e) {
System.out.println("Exception");
}
print_in_txt();
pause = false;
freeze_signal = false;
}
}
}
So, after spending some time bagging my head against the idea, I suddenly realised that you don't actually need the thread at all.
What you need is a way to calculate the duration between to points in time, which doesn't need a thread to update the state, it's done automatically.
The thread is just doing "other stuff"
So, based on that, I took a StopWatch class from one of my previous answers...
public class StopWatch {
private Instant startTime;
private Duration totalRunTime = Duration.ZERO;
public StopWatch start() {
startTime = Instant.now();
return this;
}
public StopWatch stop() {
Duration runTime = Duration.between(startTime, Instant.now());
totalRunTime = totalRunTime.plus(runTime);
startTime = null;
return this;
}
public StopWatch pause() {
return stop();
}
public StopWatch resume() {
return start();
}
public StopWatch reset() {
stop();
totalRunTime = Duration.ZERO;
return this;
}
public boolean isRunning() {
return startTime != null;
}
public Duration getDuration() {
Duration currentDuration = Duration.ZERO;
currentDuration = currentDuration.plus(totalRunTime);
if (isRunning()) {
Duration runTime = Duration.between(startTime, Instant.now());
currentDuration = currentDuration.plus(runTime);
}
return currentDuration;
}
}
And applied so it could be used within a Thread, which would simply print the running time.
Around this, I added the ability to pause, resume and stop the thread so as to demonstrate the basic idea...
public class StopWatchRunnable implements Runnable {
private final Lock pauseLock = new ReentrantLock();
private final Condition pauseCondtion = pauseLock.newCondition();
private final AtomicBoolean isPaused = new AtomicBoolean(false);
private final AtomicBoolean isRunning = new AtomicBoolean(true);
private final StopWatch stopWatch = new StopWatch();
#Override
public void run() {
stopWatch.start();
while (isRunning.get()) {
while (isPaused.get()) {
pauseLock.lock();
stopWatch.pause();
try {
pauseCondtion.await();
} catch (InterruptedException ex) {
} finally {
pauseLock.unlock();
stopWatch.resume();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
}
Duration duration = stopWatch.getDuration();
String formatted = String.format("%dhrs %02dmins, %02dseconds", duration.toHours(), duration.toMinutesPart(), duration.toSecondsPart());
System.out.println(formatted);
}
}
public void stop() {
pauseLock.lock();
try {
isPaused.set(false);
isRunning.set(false);
} finally {
pauseCondtion.signalAll();
pauseLock.unlock();
}
}
public void pause() {
pauseLock.lock();
try {
isPaused.set(true);
} finally {
pauseLock.unlock();
}
}
public void resume() {
pauseLock.lock();
try {
isPaused.set(false);
} finally {
pauseCondtion.signalAll();
pauseLock.unlock();
}
}
}
Runnable example...
This basically takes the code from above and dumps it into a simple runnable example which demonstrates the pause/resume functionality
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class StopWatchExample {
public static void main(String[] args) throws InterruptedException {
new StopWatchExample();
}
public StopWatchExample() throws InterruptedException {
StopWatchRunnable stopWatch = new StopWatchRunnable();
Thread thread = new Thread(stopWatch);
thread.start();
Thread.sleep(5000);
System.out.println("Pause...");
stopWatch.pause();
Thread.sleep(5000);
System.out.println("Resume...");
stopWatch.resume();
Thread.sleep(5000);
System.out.println("Stop...");
stopWatch.stop();
thread.join();
System.out.println("All done...");
}
public class StopWatch {
private Instant startTime;
private Duration totalRunTime = Duration.ZERO;
public StopWatch start() {
startTime = Instant.now();
return this;
}
public StopWatch stop() {
Duration runTime = Duration.between(startTime, Instant.now());
totalRunTime = totalRunTime.plus(runTime);
startTime = null;
return this;
}
public StopWatch pause() {
return stop();
}
public StopWatch resume() {
return start();
}
public StopWatch reset() {
stop();
totalRunTime = Duration.ZERO;
return this;
}
public boolean isRunning() {
return startTime != null;
}
public Duration getDuration() {
Duration currentDuration = Duration.ZERO;
currentDuration = currentDuration.plus(totalRunTime);
if (isRunning()) {
Duration runTime = Duration.between(startTime, Instant.now());
currentDuration = currentDuration.plus(runTime);
}
return currentDuration;
}
}
public class StopWatchRunnable implements Runnable {
private final Lock pauseLock = new ReentrantLock();
private final Condition pauseCondtion = pauseLock.newCondition();
private final AtomicBoolean isPaused = new AtomicBoolean(false);
private final AtomicBoolean isRunning = new AtomicBoolean(true);
private final StopWatch stopWatch = new StopWatch();
#Override
public void run() {
stopWatch.start();
while (isRunning.get()) {
while (isPaused.get()) {
pauseLock.lock();
stopWatch.pause();
try {
pauseCondtion.await();
} catch (InterruptedException ex) {
} finally {
pauseLock.unlock();
stopWatch.resume();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
}
Duration duration = stopWatch.getDuration();
String formatted = String.format("%dhrs %02dmins, %02dseconds", duration.toHours(), duration.toMinutesPart(), duration.toSecondsPart());
System.out.println(formatted);
}
}
public void stop() {
pauseLock.lock();
try {
isPaused.set(false);
isRunning.set(false);
} finally {
pauseCondtion.signalAll();
pauseLock.unlock();
}
}
public void pause() {
pauseLock.lock();
try {
isPaused.set(true);
} finally {
pauseLock.unlock();
}
}
public void resume() {
pauseLock.lock();
try {
isPaused.set(false);
} finally {
pauseCondtion.signalAll();
pauseLock.unlock();
}
}
}
}

Programming a game using the Javafx class from a tutorial and have come across an undefined class error

else if(left || right) {
if(currentAction != WALKING) {
currentAction = WALKING;
animation.setFrames(sprites.get(WALKING));
animation.setDelay(40);
width = 30;
Here is the code I am having issues with. namely the animation.setFrames and setDelay the setFrames uses a BufferedImage array and the setDelay is a long variable. The two errors that come up are
The method setFrames(BufferedImage[]) is undefined for the type Animation
and
The method setDelay(Duration) in the type Animation is not applicable for the arguments (int)
public void setFrames(BufferedImage[] frames) {
this.frames = frames;
currentFrame = 0;
startTime = System.nanoTime();
playedOnce = false;
this is the code for the setFrames and the code of delay's setter is just
public void setDelay(long d) {
delay = d;
}
Any assistance is welcome.
There were none of these errors in the tutorial
EDIT: I have created a new Animation class in the constructor but it did not solve it. Added Animation class
package Entity;
import java.awt.image.BufferedImage;
public class Animation {
private BufferedImage[] frames;
private int currentFrame;
private long startTime;
private long delay;
private boolean playedOnce; played; e.g. an attack so it does not
public void Animation() {
playedOnce = false;
}
public void setFrames(BufferedImage[] frames) {
this.frames = frames;
currentFrame = 0;
startTime = System.nanoTime();
playedOnce = false;
}
public void setDelay(long d) {
delay = d;
}
public void setFrame(int i) {
currentFrame = i;
}
public void update() {
if (delay == -1)
return;
long elapsed = (System.nanoTime() - startTime) / 1000000;
if (elapsed > delay) {
currentFrame++;
playedOnce = true;
}
}
public int getFrame() {
return currentFrame;
}
public BufferedImage getImage() {
return frames[currentFrame];
}
public boolean hasPlayedOnce() {
return playedOnce;
}
}
Thank you to Bandreid for the answer.
It need the object to be added and a new object created.

Stop, close, end, thread in java based on condition

I am not sure how to get this working. I want one this tread to stop once (startNumber == 0 || !Player.cCounting). !Player.cCounting is a boolean that is accessed. If either condition is met I want the loop to stop.
public class Console {
static long lastTime;
static boolean cCounting = true;
static long seconds = 0;
static long delta = 0;
static int startNumber = (int) Level.cookieTime / 1000;
Thread countDown;
public Console() {
cookieCountDown();
lastTime = System.currentTimeMillis();
}
public void cookieCountDown() {
countDown = new Thread(new Runnable() {
#Override
public void run() {
startNumber = (int) Level.cookieTime / 1000;
while (startNumber != 0) {
cCounting = Game.enter;
//System.out.println(cCounting);
try {
Thread.sleep(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
while (startNumber > 0 && cCounting) {
long now = System.currentTimeMillis();
delta = now - lastTime;
if (delta >= 1000) {
delta = 0;
lastTime = System.currentTimeMillis();
System.out.println("cookie " + startNumber);// print countdown;
startNumber--;
System.out.println(Player.cCounting);
if (Player.cCounting = false) {
end();
}
}
}
}
}
});
countDown.start();
}
public void end() {
System.out.println(startNumber);
System.out.println(cCounting);
if (startNumber == 0 || !Player.cCounting) {
System.out.println("stop");
//countDown.interrupt();
//countDown.stop();
}
}
}
You just need to exit your loop. Replace your end(); method call with return;. and make startNumber and Player.cCounting volatile e.g. volatile static int startNumber

Categories