问题
i made simple game by java , it's about "tennis background" and "tennis ball" , and the ball is randomally move automatically ,
my game consist of two file , 1st file fore Jpanel , and 2nd file for JFrame ,
my question is : i need to control of "stopping and resuming" the ball by clicking the mouse , i tried to put wait() during thread running loop , but it's faild , i don't know what is the reason ! , so please review my code and then tell me what is the wrong , and what is the true method of "pause&resume" thread in my simple game !
tennis.java file (which contain the thread):
/*
* tennis.java
*
* Created on Nov 15, 2011, 3:35:28 PM
*/
package io;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
public class tennis extends javax.swing.JPanel implements Runnable{
BufferedImage ball;
BufferedImage bg;
int ball_h = 0;
int ball_w = 0;
int height = 0;
int width = 0;
int yPos = -1;
int xPos = 10;
int pause = 20;
// Move Speed
int xMov = 5;
int yMov = 10;
boolean clicked = false;
int play = 0;
Thread runner;
/** Creates new form tennis */
public tennis() throws IOException {
ball = ImageIO.read(new File("tennis/ball.png"));
bg = ImageIO.read(new File("tennis/bg.jpg"));
ball_h = 50;
ball_w = 50;
height = 600 - ball_h;
width = 800 - ball_w;
runner = new Thread(this);
runner.start();
}
public void start(){
if(play == 0){
play = 1;
clicked = true;
}else{
play = 0;
clicked = true;
}
System.out.println(play);
}
public void stop(){
runner = null;
}
@Override
public void paint(Graphics g){
Graphics2D g2D = (Graphics2D) g;
g2D.drawImage(bg, 0, 0, 800,600, this);
g2D.drawImage(ball, xPos, yPos,50,50, this);
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 400, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 300, Short.MAX_VALUE)
);
}// </editor-fold>
// Variables declaration - do not modify
// End of variables declaration
@Override
public void run() {
while(runner == runner){
if(xPos >= (width))
{
xMov *= -1;
}
xPos += xMov;
if(xPos < 1)
{
xMov *= -1;
}
if(yPos >= (height-ball_h))
{
yMov *= -1 ;
}
yPos += yMov;
if(yPos < 1)
{
yMov *= -1 ;
}
repaint();
try {
if(play == 1){
Thread.sleep(pause);
}else{
synchronized(this){
while(play == 0){
wait();
}
}
}
} catch (InterruptedException ex) {
Logger.getLogger(tennis.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
Tennis3D.java file(frame for starting the game and define the thread) :
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/*
* Tennis3D.java
*
* Created on Nov 15, 2011, 3:42:42 PM
*/
package io;
import io.tennis;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Tennis3D extends javax.swing.JFrame implements MouseListener{
tennis tennis;
/** Creates new form Tennis3D */
public Tennis3D() {
super("Tennis3D");
setSize(800,600);
try {
tennis = new tennis();
add(tennis);
tennis.addMouseListener(this);
} catch (IOException ex) {
Logger.getLogger(Tennis3D.class.getName()).log(Level.SEVERE, null, ex);
}
setVisible(true);
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 400, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 300, Short.MAX_VALUE)
);
pack();
}// </editor-fold>
/**
* @param args the command line arguments
*/
public static void main(String args[]) {
Tennis3D tennis = new Tennis3D();
}
// Variables declaration - do not modify
// End of variables declaration
@Override
public void mouseClicked(MouseEvent e) {
tennis.start();
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
}
Thank you for your help :)
回答1:
This is piggy-backing on what Nerdtron wrote in the comment above. Typically a game loop looks like this
while (!game.isOver())
{
if (!game.isPaused())
game.update() // this moves your ball, players, etc
}
回答2:
Your approach is strange. Most games have a sort of main loop where methods update(deltaTime) and draw() are called sequentially.
Typical main loop:
initGame();
while(!gameOver)
{
readInput();
update(deltaTime);
draw();
}
update(dt) is something like
for(GameObject go : myObjectList)
{
go.update(deltaTime);
}
If you want to skip some objects you could use something like:
for(GameObject go : myObjectList)
{
if(go.isActive())
{
go.update(deltaTime);
}
}
So your task would be trivial if you use game-loop structure like that.
回答3:
To stop a thread wait()ing you need to call notifyAll() on the same object.
From the Javadoc for Object.wait()
Causes current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object.
I would suggest you call notifyAll() in a synchronized block when you set play = 1;
回答4:
A common way to achieve this is by using different states. So when you would put the game on pause it would go in PAUSE
state. When resumed it would go back in RUNNING
state or some other (more specific) state.
This is done by keeping the state in a variable. The C
-way is to define integers like follows:
final int PAUSE = 1;
final int RUNNING = 2;
The Java
-way is more like this: (using enum
s)
public enum State {
RUNNING,
PAUSE
}
Then, in your main loop (run
method) you check the state in which the game is at that moment, and perform actions accordingly.
switch(state){
case PAUSE:
Thread.sleep(100);
break;
case RUNNING:
// do something entertaining
break;
}
来源:https://stackoverflow.com/questions/8299010/how-to-pause-and-resume-a-simple-game-in-java