当我通过主菜单开始游戏(蛇游戏)时,它不起作用 - 它基本冻结,也可能是因为我已经到达那里的无限循环。但是当我删除那个循环时,它确实可以工作,因为我可以关闭应用程序 - 当从菜单启动游戏时我不能这样做,但没有那个循环,我的蛇就无法移动。当我通过main开始游戏时 - 只需通过调用类“View”,它就能正常工作。
我知道我应该使用Threads而不是loop,但我不知道如何正确使用它们。
部分代码不起作用:
public void Draw() throws InterruptedException, IOException{
addKeyListener(this);
bf = this.getBufferStrategy();
while(true){
tmp = System.currentTimeMillis()/1000;
sec = tmp - start;
if (sec % 5 == 0) {
Obstacles(30);
}
g = bf.getDrawGraphics();
g.setColor(Color.BLACK);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(Color.LIGHT_GRAY);
for (int i = 0; i < obs.size(); i++) {
g.fillRect(obs.get(i).x*SCALE, obs.get(i).y*SCALE, SCALE, SCALE);
}
for (Point point : snakeParts) {
g.setColor(Color.BLUE);
g.fillRect(point.x * SCALE, point.y * SCALE, SCALE, SCALE);
}
g.fillRect(head.x * SCALE, head.y * SCALE, SCALE, SCALE);
switch(kind){
case 0:
g.setColor(Color.RED);
break;
case 1:
g.setColor(Color.YELLOW);
break;
case 2:
g.setColor(Color.GREEN);
break;
}
g.fillRect(bonus.x * SCALE, bonus.y * SCALE, SCALE, SCALE);
string = "Score: " + score + ", Length: " + tailLength + ", Time: " + time / 20;
g.setColor(Color.WHITE);
g.drawString(string, this.getWidth()/2-80, 45);
Move();
bf.show();
Thread.sleep(speed);
}
}
从主菜单按钮开始游戏:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
try
{
if (cfg.nick())
{
this.setVisible(false);
new View().setVisible(true);
new View().startGame();
}
} catch (InterruptedException ex)
{
Logger.getLogger(HerniMenu.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex)
{
Logger.getLogger(HerniMenu.class.getName()).log(Level.SEVERE, null, ex);
}
}
感谢您的帮助!
答案 0 :(得分:3)
这是一个Swing程序,使用Swing执行重复任务的最简单方法是通过Swing Timer。请查看Swing Timer Tutorial了解详细信息,但要点是:
javax.swing.Timer
对象,传递延迟时间和ActionListener。actionPerformed(ActionEvent e)
方法中,您编写了想要重复的代码。 SwingUtilities.invokeLater(...)
调用。这是可行的,但它比需要的更复杂,并且使用Swing Timer会更简单。stop()
方法即可。繁荣。就是这样。ArrayList<Point>
的状态,调用repaint()
然后在paintComponent方法中遍历ArrayList,在基于Point的位置绘制每个snake段ArrayList中的位置。例如:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
public class SimpleSnake extends JPanel {
private static final int PREF_W = 900;
private static final int PREF_H = 650;
private static final int SNAKE_WIDTH = 24;
private static final int TIMER_DELAY = 20; // milliseconds
private static final int SNAKE_LENGTH = 20;
private List<Point> pointList = new ArrayList<>();
private boolean right = true;
private boolean down = true;
private JButton startButton = new JButton("Start");
private JButton stopButton = new JButton("Stop");
private Timer swingTimer = new Timer(TIMER_DELAY, e -> timerActionPerformed(e));
public SimpleSnake() {
// fill snake
for (int i = 0; i < SNAKE_LENGTH; i++) {
int x = (2 * (i + 1) * SNAKE_WIDTH) / 3;
int y = (2 * (i + 1) * SNAKE_WIDTH) / 3;
pointList.add(new Point(x, y));
}
startButton.addActionListener(e -> swingTimer.start());
stopButton.addActionListener(e -> swingTimer.stop());
setBackground(Color.BLACK);
add(startButton);
add(stopButton);
}
// called by Swing Timer's ActionListener
private void timerActionPerformed(ActionEvent e) {
// get last point in ArrayList
Point lastPoint = pointList.get(pointList.size() - 1);
// if at any wall, reverse the direction of snake flow
if (lastPoint.x - SNAKE_WIDTH / 2 < 0) {
right = true;
}
if (lastPoint.x + SNAKE_WIDTH / 2 > getWidth()) {
right = false;
}
if (lastPoint.y - SNAKE_WIDTH / 2 < 0) {
down = true;
}
if (lastPoint.y + SNAKE_WIDTH / 2 > getHeight()) {
down = false;
}
// remove first Point
pointList.remove(0);
// calculate the next Point to add
int x = lastPoint.x;
if (right) {
x += (2 * SNAKE_WIDTH) / 3;
} else {
x -= (2 * SNAKE_WIDTH) / 3;
}
int y = lastPoint.y;
if (down) {
y += (2 * SNAKE_WIDTH) / 3;
} else {
y -= (2 * SNAKE_WIDTH) / 3;
}
// add point to ArrayList
pointList.add(new Point(x, y));
repaint(); // and repaint the JPanel
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// to make smooth graphics
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.BLUE);
// iterate through the points, drawing the snake segments
for (Point p : pointList) {
int x = p.x - SNAKE_WIDTH / 2;
int y = p.y - SNAKE_WIDTH / 2;
g2.fillOval(x, y, SNAKE_WIDTH, SNAKE_WIDTH);
}
}
// size the JPanel correctly
@Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
JFrame frame = new JFrame("SimpleSnake");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new SimpleSnake());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
答案 1 :(得分:2)
正如您已经诊断出来的那样,问题在于您有一个线程正在执行运行游戏和控制窗口的所有逻辑。要解决此问题,您需要将功能分离为单独的线程。网上有很多解释和例子,其中一些基础知识是: - http://docs.oracle.com/javase/tutorial/essential/concurrency/ - http://www.javaworld.com/article/2077138/java-concurrency/introduction-to-java-threads.html