I am just a beginner in Java. We have a college project and we are making a game called othello (also called reversi), we are using Java applet for the game. Board design and gameplay is complete and is working fine but we are having an issue with the timer.
The problem is player's move is not detected until timer has elapsed completely, i.e suppose timer for each move is 10 sec and if the user places his move at the 5th sec, his move will be detected only after 10 sec This behavior does not serve any purpose.
The method I am following is:
Display the time(integer) on the applet screen
Sleep for one sec
Increment time and update graphics
The whole thing is put inside the loop which is actually creating the problem. I need a better and in fact a working modification to this code.
Here are the code of two relevant functions
void startTimer() {
Graphics g = getGraphics();
for(sec =0 ; sec < 10 ; sec++){
String time = new String();
time = Integer.toString(sec);
g.drawString(time, WIDTH+80, 145);
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(NewApplet.class.getName()).log(Level.SEVERE, null, ex);
}
update(getGraphics());
}
}
public boolean mouseUp(Event e, int x, int y) {
int column = (int)(x / (WIDTH / 8));
int row = (int)(y / (WIDTH / 8));
if (turn == BLACK) {
if (placeLegalCheck(column, row, turn) == true){
flipDisk(column, row, turn);
turn = - turn;
diskCount();
startTimer();
update(getGraphics());
try {
Thread.sleep(500);
} catch (Exception excep){
}
}
}
if (turn == WHITE) {
if (placeLegalCheck(column, row, turn) == true){
flipDisk(column, row, turn);
turn = - turn;
diskCount();
startTimer();
update(getGraphics());
try {
Thread.sleep(500);
} catch (Exception excep){
}
}
}
return true;
}
Related
So I am trying to stop my program from flickering but from other peoples problems I can't find a solution that applies to my code. It just flickers and I've seen a suggestion from another persons post to change to paintComponent but I don't see how it works when compared to paint. Any help would be greatly appreciated thanks.
package runalreadypls;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.Timer;
public class GameGen extends JFrame implements KeyListener{
private static final long serialVersionUID = -7177541209377865450L;
Random rand = new Random();//Random generator for map
double move = 0;//Moves graphics generation
int timed = 750;//Moving delay
int speed = 2;//Moves Faster
int [][] world=new int[10][100];//Map generation
int WIDTH = 720;//Width of frame/window
int HEIGHT = 480;//Height of frame/window
String exitMSG;//Exit message
String user;//username
int charX = 0;//Starting coordinates for character
int charY= 4;
BufferedImage img1;//Graphics generation
static double score = 0;//Score of player
GameGen(){//Start game
super("Runner");//Set frame specifications
this.setSize(WIDTH,HEIGHT);
this.setLocationRelativeTo(null);
this.setUndecorated(true);
this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
this.setResizable(false);
this.setFocusable(true);
this.setVisible(true);
//Adds spacebar listener
addKeyListener(this);
//Starts world generation
worldGen();
//Paints world
repaint();
//Swing Timer for moving of character and background
Timer timer = new Timer(timed ,null);
timer.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
//Increasing speed
if (speed < 400){
speed = speed + 5;
}
timer.setDelay(timed - speed);
//Increasing score
score = score + 3;
//Moving character
charX= charX + 1;
//Checks if game is over
if(gameOverCollision()){
timer.stop();//Ends "delayed loop"
}
//Gravity
//If charY is not below the screen to prevent array out of bounds
if (charY < 9){
if (world[charY+1][charX] == 0){//Moves character down/Gravity
charY = charY+1;
deleter();//Deletes character previous coords
mover();//Moves character coords on array
}
}
deleter();//Deletes character previous coords
mover();//Moves character coords on array
}
});
timer.start();//Starts "delayed loop" / swing timer
}
public void deleter(){//Deletes character previous coords so there is only one character on the screen
for(int x = 0;x <9;x++){
for(int y = 0; y < 100; y++){
if (world[x][y] == 2){
world[x][y] = 0;
}
}
}
}
public void mover(){//Moves character on the array
world[charY][charX] = 2;
repaint();
}
/*
*
* 0 = Background
* 1 = Surface
* 2 = Player
* 3 = Below Surface
*
* */
public void worldGen(){
int xAt = 5;
world[4][0] = 2;//Character placement
world[5][0] = 1;//First tile placement
for (int x = 1; x < 100; x++){ //Starting place
int X =3;
X = rand.nextInt(X)+1;//Random Number Generator
if (xAt <= 6 && xAt>=3){//If where the ground is at is between 7 and 2 (exclusive)then it will generate normally
if (X == 1){
xAt =xAt+ 1;
world[xAt][x] = 1;
}else if (X == 3){
xAt =xAt - 1;
world[xAt][x] = 1;
}else if (X==2){
world[xAt][x]=1;
}
/*
* If where the ground is at is too low between 7 and 9 (which is the bottom 3 tiles)
* then it will generate with more chances of going up instead of staying the same
*
*/
}else if(xAt >6 && xAt <9){
if (X==1 || X==3){
xAt =xAt- 1;
world[xAt][x] = 1;
}else if (X==2){
world[xAt][x]=1;
}
/*
* If where the ground is at is too low between 1 and 4((exclusive) which is the top 3 tiles)
* then it will generate with more chances of going down instead of staying the same
*
*/
}else if(xAt >1 && xAt <3){
if (X==1 || X==3){
xAt =xAt+ 1;
world[xAt][x] = 1;
}else if (X==2){
world[xAt][x] = 1;
}
}
}
//Generates ground below the surface
for(int x = 0;x <9;x++){
for(int y = 0; y < 100; y++){
if (world[x][y] == 1){
world[x+1][y] = 3;
}
if (world[x][y] == 3){
world[x+1][y] = 3;
}
}
}
}
#Override
public void paint(Graphics g){
super.paint(g);
g.setColor(Color.WHITE);
g.setFont(new Font("TimesRoman", Font.PLAIN, 100));
g.drawString(Integer.toString((int) score), 220, 100);
//Checks through 2d array to generate images
for(int x = 0;x <9;x++){
for(int y = 0; y < 100; y++){
if(world[x][y] == 0){
try {//If background then accesses background image
img1 = ImageIO.read(new File("src/runalreadypls/Background.png"));
} catch (IOException e) {
e.printStackTrace();
}
} else if(world[x][y] == 1){
try {//If surface then accesses surface image
img1 = ImageIO.read(new File("src/runalreadypls/Ground.png"));
} catch (IOException e) {
e.printStackTrace();
}
}else if (world[x][y] == 2){
try {//If surface then accesses character image
img1 = ImageIO.read(new File("src/runalreadypls/Character2.png"));
} catch (IOException e) {
e.printStackTrace();
}
}else if (world[x][y] == 3){
try {//If below surface then accesses below surface image
img1 = ImageIO.read(new File("src/runalreadypls/Foreground.png"));
} catch (IOException e) {
e.printStackTrace();
}
}
g.drawImage(img1,(int) (45*(y-move)),60*x,null);//Draws images in procedural order
}
}
move = move + .65;//Moves screen
}
/*
*
* WALL collision
* If player misses jump
* Game is over
*
*
* */
public boolean gameOverCollision(){
//Checks if the player has missed a tile or if they have finished the map
if(world[charY][charX] == 1||charX == 99){
/*
*
* Adds current players score to the high score file
*
* */
try {
fileAppend();
} catch (IOException e) {
e.printStackTrace();
}
/*
*
* Sorts high scores in order of greatest to least
*
* */
try {
fileSort();
} catch (IOException e) {
e.printStackTrace();
}
//Deletes window
dispose();
//Exit Msg
exitMSG = "Thank you for playing " +Game.name() +" your score is: " + score;
JOptionPane.showMessageDialog(null, exitMSG, "Thank you for Playing!", JOptionPane.ERROR_MESSAGE);
//Recreates main menu
new Game();
//Reseting Score and speed
score = 0;
speed = 2;
return true;
//Checks if player has finished the map
}else{
return false;
}
}
public void fileSort()throws IOException,FileNotFoundException{
List<Integer> list = new ArrayList<Integer>();//Array list to store integers
File file = new File("highscores.txt");//File
BufferedReader br = null;//br
br = new BufferedReader(new FileReader(file));//br
String text = null;//text
while ((text = br.readLine()) != null) {//Putting integer into list
list.add((int) Double.parseDouble(text));//Converting line text to int and putting into list
}
if (br != null) {//closing
br.close();
}
Collections.sort(list);//sort list
Collections.reverse(list);//reverse list for descending order
FileWriter fw = new FileWriter("highscores.txt");//Write to file
BufferedWriter bw = new BufferedWriter(fw);
for(Integer lists: list) {
bw.write(lists);//WRiting to file
bw.newLine();//New line
}
bw.close();//Closing
fw.close();
}
public void fileAppend()throws IOException{
//Declaring writers
FileWriter fw = null;
BufferedWriter bw = null;
PrintWriter pw = null;
fw = new FileWriter("highscores.txt", true);
bw = new BufferedWriter(fw); pw = new PrintWriter(bw);
pw.println(score); //Adding to file
//Closing
pw.close();
bw.close();
fw.close();
}
/*
*
* Listens to spacebar input to move character up a tile
*
* */
#Override
public void keyPressed(KeyEvent e) {
if(charY<9 && charY >0){
if (e.getKeyCode()==KeyEvent.VK_SPACE){
if(world[charY][charX+1] == 1){
charY-=1;//Moving character Y coords up a tile
deleter();//Deletes character previous coords
mover();//Changing player's tile in array
}
if(world[charY][charX+1] != 1){
score = score -3; //Substracts score if player jumps early
}
}
}
}
#Override
public void keyReleased(KeyEvent e) {
}
#Override
public void keyTyped(KeyEvent e) {
}
}
Similar suggestions to the many similar questions:
Draw within the protected void paintComponent method of a JPanel, not within a JFrame's paint method. This will give you double buffering by default.
Never read in a file or resource within a painting method. This method's speed is the most important factor in the perceived responsiveness of your program and you should do nothing to slow it down. It should be for painting and painting only.
Instead, read the image into a variable once, and then draw the image from the variable within paintComponent.
Paint background images to a BufferedImage and then draw that within the paintComponent method.
Double Buffer Drawing
in the run() method, you should have something like this --
while(running) {
gameUpdate();
gameRender();
repaint(); // Note: I would not use this either, you should also
// have thead.sleep() call to stop event coalescence: when
// JVM is overloaded by repaint() request, JVM may combine
// request, causing rendering request to be skipped and
// animation to "jump."
}
Well, inorder to reduce flikering -- "jump" -- you should apply a double buffering thechnique. One way to do this to have the gameRender() draw into its own Graphics object, which would represent an image the same size of the screen.
My Example:
// Global variables for off-screen rendering
private Graphics dbg;
private Image dbImage = null;
private void gameRender() {
/* Draw the current frame to an image buffer*/
if(dbImage == null) { // create the buffer
dbImage = createImage(PWIDTH, PHEIGHT);
if(dbImage == null ) {
System.out.println("dbImage is null");
return;
}
else
dbg = dbImage.getGraphics();
}
//clear the background
dbg.setColor(Color.white);
dbg.fillRect(0, 0, PWIDTH, PHEIGHT);
// Draws game elements
// ...
if(gameOver)
gameOverMessage(dbg);
} // end gameRender()
dbImage is placed on screen by the paintComponent() as a result of the repaint() request in the run() loop -- while(running)...gameUpdate(), Render(), repaint()..
Here is the call that would place dbImage on screen. This call is made after rendering steps have been completed (the above code):
public void paintComponent(Graphic g) {
super.paintComponent(g);
if (dbImage != null)
g.drawImage(dbImage, 0,0,null);
}
If extensive drawing is done directly to the screen, the process may take long enough to become noticiable by the user. the call to drawImage() in paintComponent() is fast enough that the change from one frame to the next is preceived as instantaneous.
paintComponent should be kept simple
Futhermore, I would also convert to active rendering, since the call to repaint() is only a request, its hard to know when repaint() has completed... which means the sleep time in the animation thread (while(running)...ect) is basically a guess.. When I say sleep time, I mean this:
running = true;
while (running) {
gameUpdate(); // Game state is updated
gameRender(); // Render to a buffer
paintScreen(); // Note: Change from repaint() to paintScreen(),
// will explain later.
try {
Thread.sleep(20); // sleep a bit.. 20 ms to be exact.
} catch(InterruptedException ex){}
} // end of run()
There should be a specified sleeping time for for 3 main reasons: 1. it stops the animation thread, which frees up the CPU for other task, like garbage collection by the JVM. 2. the sleep call gives the preceeding request to repaint() time to be proccessed. 3. sleep reduces the chances of event coalescence because it give the JVM time to complete tasks instead of combining task causing "jumping" affect in the animation.
However, using the repaint() request, as stated before the sleep time is little more than a guess; if the specified time is too long, then the animation speed is impaired for no reason. if the dely is too short, then the repaint requests may be queued by the JVM and skipped if the load is too lard, causing "flickering"
Active rendering puts the task of active rendering the buffer into your hands, allowing the render time to be accurately measured.
like so,
running = true;
while (running) {
gameUpdate(); // Game state is updated
gameRender(); // Render to a buffer
paintScreen(); // Note: Change from repaint() to paintScreen(),
// will explain later.
try {
Thread.sleep(20); // sleep a bit.. 20 ms to be exact.
} catch(InterruptedException ex){}
System.exit(0);
/**
* Actively render the buffer image to screen
*/
private void paintScreen() {
Graphics g;
try {
g = this.getGraphics(); // get the panel's graphic context
if ((g != null) && (dbImage != null))
g.drawImage(dbImage, 0, 0, null);
Toolkit.getDefaultToolkit().sync(); // sync the display on some
// systems
g.dispose();
}
catch (Exception e) {
System.out.println("Graphics context error: " + e);
} // end catch
} // end paintScreen()
} // end of run()
I would like to explain more, but the rest I leave to you to explore, it is a world of fun.. Forgive any puncuation and spelling -- I am in a rush.. Goodluck
respectfully,
#author James Stowell - !di0m -
Full implementation w/ concerns of seperating updates from rendering mentioned in the comments section below:
Since I prefer writing 3D games, I will use the J3DTimer, you may employ other high resolution timers, the JMF timer is an option...
The run() method without possible pauses:
private static final int MAX_FRAME_SKIPS = 5;
// number of frames that can be skipped in any one animation loop
// i.e the game state is updated but not rendered
private static final int NO_DELAYS_PER_YIELD = 16;
// number of frames with a delay of 0 ms before the animation
// thread yields to other running threads.
#Override
public void run() {
/* Repeatedly update, render, sleep so loop takes close
* to period nsecs. Sleep inaccuracies are handled.
* The timing calculation use the Java 3D timer.
*
* Overrruns in update/renders will cause extra updates
* to be carried out so UPS ~== requested FPS
*/
long beforeTime, afterTime, timeDiff, sleepTime;
long overSleepTime = 0L; // Number zero of type long (0L)
int noDelays = 0;
long excess = 0L;
beforeTime = J3DTimer.getValue();
running = true;
while (running) {
gameUpdate(); // Game state is updated
gameRender(); // Render to a buffer
paintScreen(); // Draw buffer to screen
afterTime = J3DTimer.getValue();
timeDiff = afterTime - beforeTime;
sleepTime = (period - timeDiff) - overSleepTime; // Time left in this
// loop
if (sleepTime > 0) { // Some time left in this cycle
try {
Thread.sleep(sleepTime/1000000L); // nano -> ms
} catch (InterruptedException ex) {}
overSleepTime =
(J3DTimer.getValue()-afterTime) - sleepTime;
}
else { // sleepTime <= 0; frame took longer than the period
excess -= sleepTime; // store excess time value
overSleepTime = 0L;
if (++noDelays >= NO_DELAYS_PER_YIELD) {
Thread.yield(); // Give another thread a chance to run
noDelays = 0; // New thread, no delays.
} // end inner if
} // end outer if
beforeTime = J3DTimer.getValue();
/* If frame animation is taking too long, update the game state
* without rendering it, to get the updates/sec bearer to required
* FPS
* */
int skips = 0;
while((excess > period) &&(skips < MAX_FRAME_SKIPS)) {
excess -= period;
gameUpdate(); // Update state, but don't render
skips++;
}
} // end while
System.exit(0); // So enclosing JApplet/JFrame exits
} // end of run()
/**
* Actively render the buffer image to screen
*/
private void paintScreen() {
Graphics g;
try {
g = this.getGraphics(); // get the panel's graphic context
if ((g != null) && (dbImage != null))
g.drawImage(dbImage, 0, 0, null);
Toolkit.getDefaultToolkit().sync(); // sync the display on some
// systems
g.dispose();
}
catch (Exception e) {
System.out.println("Graphics context error: " + e);
} // end catch
} // end paintScreen()
In a game board we are developing in Java we want to show a sort of rolling dice when a button is pressed. We are trying to use the following image as a sprite:
so when the button is pressed, here's what happens:
private void startAnimationDie(final JPanel panel) {
int launchResult = /* getting a launch dice result from the core game (from 1 to 6)*/
new Thread() {
public void run() {
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
BufferedImage[] animationBuffer = initAnimationBuffer();
BufferedImage[][] exactDieFaces = initExactDieFaces();
int launchResult = coreGame.launchDie();
coreGame.getMyPartecipant().setLastLaunch(launchResult);
AnimationSprite animation = new AnimationSprite(animationBuffer, Constants.DIE_ANIMATION_SPEED);
animation.start();
JLabel resultDie = new JLabel();
resultDie.setBounds(60, 265, Constants.DIE_SIZE, Constants.DIE_SIZE);
for (int counter = 0; counter < Constants.DIE_ANIMATION_SPEED * 100; counter++) {
animation.update();
//panel.removeAll();
panel.updateUI();
//System.out.println("infor");
resultDie.setIcon(new ImageIcon(animationBuffer[counter % Constants.ROTATIONS]));
panel.add(resultDie);
panel.updateUI();
updateUI();
}
panel.removeAll();
panel.updateUI();
AnimationSprite resultAnimation = new AnimationSprite(exactDieFaces[launchResult - 1], 6);
resultAnimation.start();
resultAnimation.update();
System.out.println("0");
resultDie.setIcon(new ImageIcon(exactDieFaces[launchResult - 1][0]));
System.out.println("1");
resultDie.setBounds(60, 265, Constants.DIE_SIZE, Constants.DIE_SIZE);
System.out.println("2");
panel.add(resultDie);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
userPlayer.getGamePanel().makePossibleMoveFlash();
}
});
} catch (Exception ex) {
}
}
}.start();
where exactDieFaces contains the dice faces according to the pawn color which is launching and that face will be shown after the simulated rolling has finished; on the other hand, animationBuffer contains 40 or 50 random faces of all colors taken from the sprite image like that:
private BufferedImage[] initAnimationBuffer() {
BufferedImage[] result = new BufferedImage[Constants.ROTATIONS];
int rowSprite, colSprite;
Random random = new Random();
for (int i = 0; i < Constants.ROTATIONS; i++) {
rowSprite = 1 + random.nextInt(5);
colSprite = 1 + random.nextInt(5);
result[i] = DieSprite.getSpriteExact(0 /* offset */,colSprite, rowSprite);
}
return result;
}
The problem is that nothing is shown during the animation: I expected to see many dice faces change one after the other until the for cycle ends but nothing is shown...The only thing I see is the launch result according to the color pawn which has launched the die but meanwhile there is nothing...can you help me?
If I understand your code correctly you are attempting to update the UI many times within the same for loop. That's not how animation works. You need a timer which regularly notifies you to move to the next frame to view.
A good place to start in understanding how to use timers is here in the Java tutorial.
i have a problem with one thing. I have a map of 10 cities and a civilian. I want the civilian to be walking from city to city randomly. But the problem is that the city is beeing chosen on and on so the civilian is changing the destination before he reachs it. This is my part of a code of a Jpanel where everything is drawn:
#Override
public void run() {
while (running) {
update();
repaint();
try {
Thread.sleep(17);
} catch (InterruptedException ex) {
}
}
}
private void update() {
if (game != null && running == true) {
c.goTo(cities); // c is civilian
}
}
and this is part of code for civilian
private boolean set = true;
public void move(int x, int y) {
if (this.location.x != x || this.location.y != y) {
if (this.location.x > x) {
this.location.x -= 1;
} else {
this.location.x += 1;
}
if (this.location.y > y) {
this.location.y -= 1;
} else {
this.location.y += 1;
}
}
}
public void goTo(ArrayList<City> cities) {
City city;
if (set) {
city = cities.get(rand());
move(city.location.x, city.location.y);
set = false;
} else {
set = true;
}
}
public int rand() {
int i;
Random rand = new Random();
i = rand.nextInt(10);
return i;
}
How to solve it ?
So, your problem is here:
while (running) {
update();
repaint();
try {
Thread.sleep(17);
} catch (InterruptedException ex) {
}
}
You're calling update every 17 milliseconds which in turn is causing your civilian to move to a new city every 17 milliseconds. You could make a separate statement that calls update while another boolean statement is false so that you travel only when he is in a city.
For example:
boolean travelling = //whatever you go about to configure this
while(travelling == false){
update();
}
This will cause him to only travel when he is not in a city. Here is some very rough code (you will have to configure it to your liking):
//civilian x //civilian y
if(this.location.x == //randomed city.x && this.location.y == //randomed city.y){
travelling = false;
}
This will most likely need to be within the run() method in your first set of code, so it can be checked over and over. But let me explain what the above code is doing:
First, you have a thread or something keeping it running checking if your civilian's x and y correspond to the most recently randomed city's x and y, obviously when they're the same, the civilian is at the city.
Second, when the x and y's are the same, the statement makes travelling false
Third, When travelling is false, your custom update method is called, picking a new city, at random and putting your civilian back on the move.
Sorry if this is a very closed question that won't be useful to others, but I'm just stumped by this bug and I haven't been able to solve it for weeks!
I am working on a wave based survival game and am currently working on a spawning mechanism.
The code I wrote works perfectly for one wave, but somehow doesn't restart for further waves.
I have written the code below:
public void run() {
while (ingame) {
if (enemyList.isEmpty()) {
stopSpawn = false;
try {
Thread.sleep(500);
spawnNewEnemy();
} catch (InterruptedException ex) {
System.out.println("Interrupted");
}
} else {
if (!enemyList.isEmpty() && !stopSpawn) {
// getEnemyAmount returns the amount of enemies that should be spawned this wave
for (int enemiesSpawned = 0; enemiesSpawned < getEnemyAmount(); enemiesSpawned++) {
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
}
System.out.println(currentWave);
spawnNewEnemy();
}
stopSpawn = true;
}
}
}
}
Here is the spawnNewEnemy method
public void spawnNewEnemy() {
Random spawn = new Random();
int spawnX = spawn.nextInt(500);
int spawnXTest = b.bX - spawnX;
if (spawnXTest < 20) {
spawnX = spawnX + 20;
} else {
}
int spawnY = spawn.nextInt(500);
int spawnYTest = b.bX - spawnY;
if (spawnYTest < 20) {
spawnY = spawnY + 20;
} else {
}
spawnY = spawnY + 20;
spawnX = spawnX + 20;
enemyList.add(new Enemy(spawnX, spawnY));
}
I can read the following in your code:
If the list of enemies is empty, you set stopSpawn to false and spawn an enemy.
That triggers your else-statement.
There, you spawn enemies based on the enemy count.
stopSpawn is set to true, thus your else-statement doesn't get triggered anymore.
Nothing happens anymore untill your enemylist is empty.
If your enemylist is empty again, you start over.
The logics seems ok, so I'm thinking either the way you spawn enemies through spawnNewEnemy() is faulty, or the way you remove enemies from the enemyList is faulty. I see neither of that code so that is as far as I can go in this answer.
I guess your problem with a loop is in stopSpawn value.
You set it to true after the first wave and likely not setting to `false' before starting the next wave.
I am coding Oregon Trail for a school project and I am implementing the hunting mini game. We are using model view presenter with a card layout. When the HuntingPanel gets switched to it calls run, and the JOptionPane comes up, but then the whole application freezes and I have to force quit. I coded the entire hunting game in a separate project, and just now brought the files over to the Oregon Trail game. It works fine in its own project with its own JFrame. I'm not sure what to do.
I call this to initialize the panel, switch to it, and run the game.
public void initialize(int ammo) {
player.setBullets(ammo);
bulletLabel.setText("Bullets: "+player.getBullets());
presenter.switchToPanel(OregonTrailPresenter.HUNTING_PANEL);
run();
}
This is my run method.
public void run() {
// starting message
JOptionPane.showMessageDialog(null, "You have reached a nearby field to hunt. You will stay\nhere until " +
"you run out of ammunition or click Return to Trail.");
// while the player has bullets or doesn't click return to trail
while (player.getBullets() > 0 && stillHunting) {
// creates random animals
checkForAnimal();
// moves and updates screen
repaint();
update();
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
endHunting();
}
And here are other method used.
private void checkForAnimal() {
int x = 0;
int y = rand.nextInt(MAX_Y)-40;
int rand1 = rand.nextInt(100);
String str = null;
if (rand1 < 50) {
str = "left";
x = MAX_X-40;
}
else if (rand1 >= 50) {
str = "right";
x = 0;
}
double gen = rand.nextGaussian(); // gen is a number from -inf to +inf
gen = Math.abs(gen); // gen is now a number from 0 to inf
if (gen >= 1.9 && gen < 2.1) { //1.19%
animalList.add(new Bunny(x,y,str));
}
if(gen >= 2.1 && gen < 2.2) { //0.9%
animalList.add(new Bear(x,y,str));
}
if (gen >= 2.2 && gen < 2.3) {
animalList.add(new Deer(x,y,str));
}
}
public void update() {
for (int i = 0; i < animalList.size(); i++) {
animalList.get(i).move();
}
}
You have to implement javax.swing.Timer instead of Thread.sleep(int), because this code line freezes all GUI during EDT until Thread.sleep(int) ends. Here is demonstrations what happens if the GUI is delayed during EDT by Thread.sleep(int)
Your program "freezes" because you did not start a new thread for the while loop. Since the panel updates and redraws are handled in the main thread, you are preventing them from happening. To fix this problem you have to start a new thread. You can do this by making your class implement runnable and use new Thread(this).start() to run your loop.
class HuntingGame extends JPanel implements Runnable {
public void initialize(int x) {
//...
new thread(this).start();// This will run your 'run()' method in a new thread.
}
}