Java 中的贪吃蛇游戏,但我的重启按钮不起作用

lub*_*off 0 java swing restart jbutton

我的游戏重启按钮不起作用,点击它时它会倍增。我不太了解 Java 我认为自己很好。

游戏主要内容

package snake_game;

public class snake {

  public static void main(String arg[]) {

    new GameFrame();
    // is exacly the same as frame f = new frame();
    // this is shorter and does the same job

  }
}
Run Code Online (Sandbox Code Playgroud)

GamePanel

package snake_game;

// import java.awt.event.ActionEvent;
// import java.awt.event.ActionListener;
// import java.awt.Graphics;
// import java.awt.event.KeyAdapter;
// import java.awt.event.KeyEvent;
// or I could write simply 
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Random;

import javax.swing.JPanel;

public class GamePanel extends JPanel implements ActionListener {

  // panal dimentions
  static final int SCREEN_WIDTH = 600;
  static final int SCREEN_HEIGHT = 600;
  // panal dimentions
  // size
  static final int UNIT_SIZE = 25;
  // size to make 600 * 600 = 1200 px equel between 25 px
  static final int GAME_UNITS = (SCREEN_WIDTH * SCREEN_HEIGHT) / UNIT_SIZE;
  // size
  // delay how fast the game will be
  static final int DELAY = 75;
  // delay
  // dimentions
  final int x[] = new int[GAME_UNITS];
  final int y[] = new int[GAME_UNITS];
  // dimentions
  // snake
  int bodyParts = 6;
  // snake
  // apple
  int appleEaten;
  int appleX;
  int appleY;
  // apple
  char direction = 'R';
  boolean running = false;
  Timer timer;
  Random random;
  GamePanel game;
  JButton resetButton;

  GamePanel() {

    random = new Random();
    this.setPreferredSize(new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT));
    this.setBackground(Color.black);
    this.setFocusable(true);
    this.addKeyListener(new MyKeyAdapter());
    startGame();
    // when we want to make the program to continie we must say what the programm
    // must execute next

  }

  public void startGame() {
    newApple();
    running = true;
    timer = new Timer(DELAY, this);
    timer.start();
  }

  public void paintComponent(Graphics g) {
    super.paintComponent(g);
    draw(g);

  }

  public void draw(Graphics g) {

    if (running) {

      for (int i = 0; i < SCREEN_HEIGHT / UNIT_SIZE; i++) {
        g.drawLine(i * UNIT_SIZE, 0, i * UNIT_SIZE, SCREEN_HEIGHT);
        g.drawLine(0, i * UNIT_SIZE, i * SCREEN_WIDTH, i * UNIT_SIZE);

      }
      g.setColor(Color.red);
      g.fillOval(appleX, appleY, UNIT_SIZE, UNIT_SIZE);

      for (int i = 0; i < bodyParts; i++) {
        if (i == 0) {
          g.setColor(Color.green);
          g.fillRect(x[i], y[i], UNIT_SIZE, UNIT_SIZE);
        } else {
          g.setColor(new Color(45, 180, 0));
          // random color
          g.setColor(new Color(random.nextInt(255), random.nextInt(255), random.nextInt(255)));
          // random color
          g.fillRect(x[i], y[i], UNIT_SIZE, UNIT_SIZE);
        }

      }
      g.setColor(Color.red);
      g.setFont(new Font("Ink Free", Font.BOLD, 30));
      FontMetrics metrics = getFontMetrics(g.getFont());
      g.drawString("SCORE:" + appleEaten, (SCREEN_WIDTH - metrics.stringWidth("SCORE:" + appleEaten)) / 2,
          g.getFont().getSize());
    } else {
      gameOver(g);
    }
  }

  public void newApple() {
    appleX = random.nextInt((int) (SCREEN_WIDTH / UNIT_SIZE)) * UNIT_SIZE;
    appleY = random.nextInt((int) (SCREEN_HEIGHT / UNIT_SIZE)) * UNIT_SIZE;
  }

  public void move() {

    for (int i = bodyParts; i > 0; i--) {
      x[i] = x[i - 1];
      y[i] = y[i - 1];

    }
    switch (direction) {
      case 'U':
        y[0] = y[0] - UNIT_SIZE;
        break;
      case 'D':
        y[0] = y[0] + UNIT_SIZE;
        break;
      case 'L':
        x[0] = x[0] - UNIT_SIZE;
        break;
      case 'R':
        x[0] = x[0] + UNIT_SIZE;
        break;
    }

  }

  public void checkApple() {
    if ((x[0] == appleX) && (y[0] == appleY)) {
      bodyParts++;
      appleEaten++;
      newApple();
    }
  }

  public void checkCollisions() {
    // check if head collides with body
    for (int i = bodyParts; i > 0; i--) {
      if ((x[0] == x[i]) && (y[0] == y[i])) {
        running = false;
      }

    }
    // check if head touches left border
    if (x[0] < 0) {
      running = false;
    }

    // check if head touches right border
    if (x[0] > SCREEN_WIDTH) {
      running = false;
    }
    // check if head touches top border
    if (y[0] < 0) {
      running = false;
    }
    // check if head touches bottom border
    if (y[0] > SCREEN_HEIGHT) {
      running = false;
    }
    if (!running) {
      timer.stop();
    }
  }

  public void gameOver(Graphics g) {
    // score
    g.setColor(Color.red);
    g.setFont(new Font("Ink Free", Font.BOLD, 30));
    FontMetrics metrics1 = getFontMetrics(g.getFont());
    g.drawString("SCORE:" + appleEaten, (SCREEN_WIDTH - metrics1.stringWidth("SCORE:" + appleEaten)) / 2,
        g.getFont().getSize());
    // game over text
    g.setColor(Color.red);
    g.setFont(new Font("Ink Free", Font.BOLD, 75));
    FontMetrics metrics2 = getFontMetrics(g.getFont());
    g.drawString("Game Over", (SCREEN_WIDTH - metrics2.stringWidth("Game Over")) / 2, SCREEN_HEIGHT / 2);
    // restart button
    resetButton = new JButton();
    resetButton.setText("Restart");
    resetButton.setSize(100, 50);
    resetButton.setLocation(150, 150);
    resetButton.addActionListener(this);

    game = new GamePanel();

    this.add(resetButton);
    this.add(game);
    this.setVisible(true);
    // restart button
  }

  @Override
  public void actionPerformed(ActionEvent e) {

    if (running) {
      move();
      checkApple();
      checkCollisions();

    }
    repaint();

    // restart button
    if (e.getSource() == resetButton) {
      this.remove(game);

      game = new GamePanel();
      this.add(game);
      resetButton.setVisible(false);
      SwingUtilities.updateComponentTreeUI(this);
      // restart button

    }

  }

  public class MyKeyAdapter extends KeyAdapter {

    @Override
    public void keyPressed(KeyEvent e) {

      switch (e.getKeyCode()) {
        case KeyEvent.VK_LEFT:
          if (direction != 'R') {
            direction = 'L';
          }
          break;
        case KeyEvent.VK_RIGHT:
          if (direction != 'L') {
            direction = 'R';
          }
          break;
        case KeyEvent.VK_UP:
          if (direction != 'D') {
            direction = 'U';
          }
          break;
        case KeyEvent.VK_DOWN:
          if (direction != 'U') {
            direction = 'D';
          }
          break;

      }

    }

  }

}
Run Code Online (Sandbox Code Playgroud)

GameFrame

package snake_game;

import javax.swing.JFrame;

public class GameFrame extends JFrame {

  GameFrame() {
    GamePanel panel = new GamePanel();
    this.add(panel);
    this.setTitle("Snake");
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.setResizable(false);
    this.pack();
    this.setVisible(true);
    this.setLocationRelativeTo(null);
    this.setUndecorated(false);
  }
}
Run Code Online (Sandbox Code Playgroud)

Gil*_*anc 7

介绍

\n

我将您的代码复制到我的 Eclipse IDE 中并按原样运行。我收到以下运行时错误。

\n
Exception in thread "main" java.awt.IllegalComponentStateException: The frame is displayable.\n    at java.desktop/java.awt.Frame.setUndecorated(Frame.java:926)\n    at com.ggl.testing.SnakeGame$GameFrame.<init>(SnakeGame.java:41)\n    at com.ggl.testing.SnakeGame.main(SnakeGame.java:24)\n
Run Code Online (Sandbox Code Playgroud)\n

Oracle 有一个有用的教程:使用 Swing 创建 GUI。跳过使用 NetBeans IDE 学习 Swing 部分。密切关注Swing中的并发性部分。

\n

我编写 Swing 代码已有 10 多年了,并且我在浏览器中添加了 Oracle 网站书签。我仍然会查找如何使用某些组件以确保我正确使用它们。

\n

我做的第一件事就是减慢你的蛇的速度,这样我就可以测试游戏了。我将延迟 75 更改为延迟 750。这是当前 GUI 的屏幕截图。

\n

当前的图形用户界面

\n

查看您的代码,您扩展了一个JFrame. 您不需要扩展JFrame. 您不会更改任何JFrame功能。使用JFrame. 这引出了我的 Java 规则之一。

\n
\n

不要扩展 Swing 组件或任何 Java 类,除非您打算重写一个或多个类方法。

\n
\n

您确实扩展了JPanel. 没关系,因为您重写了该paintComponent方法。

\n

最后,你们的JPanel班级做的作业太多了。您还大量使用静态字段。即使您只创建一个JPanel,将每个类视为您将创建该类的多个实例也是一个好习惯。这会减少你日后遇到的问题。

\n

您的想法是正确的,创建了三个类。

\n

因此,让我们使用一些基本模式和 Swing 最佳实践来重写您的代码。此时,我不知道我们最终会创建多少个类。

\n

解释

\n

当我编写 Swing GUI 时,我使用model\xe2\x80\x93view\xe2\x80\x93controller (MVC) 模式。顾名思义,您首先创建模型,然后创建视图,最后创建控制器。

\n

应用程序模型由一个或多个普通 Java getter/setter 类组成。

\n

视图由一个JFrame、一个或多个JPanels以及任何其他必要的 Swing 组件组成。

\n

控制器由一个或多个Actions或组成ActionListeners。在 Swing 中,通常没有一个控制器可以“统治所有”。

\n

总结一下:

\n
    \n
  • 视图从模型中读取信息
  • \n
  • 视图不更新模型
  • \n
  • 控制器更新模型并重新绘制/重新验证您的视图。
  • \n
\n

模型

\n

我创建了两个模型类,SnakeModel并且Snake.

\n

该类SnakeModel是一个普通的 Java getter/setter 类,它保存一个Snake实例、吃掉的苹果数、苹果位置、游戏区域的大小和几个布尔值。一个布尔值指示游戏循环是否正在运行,另一个布尔值指示游戏是否结束。

\n

游戏区域使用 ajava.awt.Dimension来保存游戏区域的宽度和高度。宽度和高度不必具有相同的值。游戏区域可以是矩形的。

\n

游戏区域以单位来衡量。在视图中,我将单位转换为像素。这与你所做的相反。如果你想改变游戏区域,你所要做的就是改变类中的尺寸SnakeModel。视图中的所有内容均基于游戏区域尺寸。

\n

该类Snake包含java.util.List一些java.awt.Point对象和一个char方向。对象java.awt.Point保存 X 和 Y 值。由于我们处理的是对象,而不是 int 值,因此当我们需要一个新的 时,我们必须小心地克隆对象Point

\n

看法

\n

所有 Swing 应用程序都必须从调用该SwingUtilities invokeLater方法开始。此方法确保 Swing 组件在事件调度线程上创建和执行。

\n

我创建了一个JFrame绘图JPanel和一个单独的按钮JPanel。一般来说,将 Swing 组件添加到绘图中并不是一个好主意JPanel。通过创建一个单独的按钮JPanel,我几乎无需额外费用即可获得“开始游戏”按钮的附加功能。游戏运行时该按钮被禁用。

\n

JFrame必须按特定顺序调用这些方法。该setVisible方法必须最后调用

\n

JPanel我通过添加一个单独的乐谱区域使绘图变得更加复杂。

\n

JPanel我根据应用程序模型仅绘制游戏的状态,从而使绘图变得不那么复杂。时期。没有其他的。

\n

我将随机颜色限制为色谱的白色端,以保持蛇和绘图JPanel背景之间的对比度。

\n

我使用键绑定而不是键侦听器。优点之一是绘图JPanel不必聚焦。由于我有一个单独的按钮JPanel,因此绘图JPanel没有焦点。

\n

另一个优点是我可以用四行附加代码添加 WASD 键。

\n

一个缺点是键绑定代码看起来比键侦听器更复杂。一旦您编写了一些按键绑定的代码,您就会体会到其中的优点。

\n

控制器

\n

我创建了三个控制器类,ButtonListenerTimerListenerMovementAction

\n

ButtonListener实现ActionListener. 该类ButtonListener初始化游戏模型并重新启动计时器。

\n

TimerListener实现ActionListener. 类TimerListener就是游戏循环。这个类移动蛇,检查苹果是否被吃掉,检查蛇是否移出游戏区域或接触到自己,并重新绘制绘图JPanel。我使用您的代码作为此类中的代码的模型。

\n

班级MovementAction延长AbstractAction。类AbstractAction实现Action. 这个类根据按键改变蛇的方向。

\n

我创建了该类的四个实例MovementAction,每个方向一个。这使得actionPerformed类的方法变得更加简单。

\n

图片

\n

这是启动游戏时修改后的 GUI 的样子。

\n

在此输入图像描述

\n

这是游戏过程中修改后的 GUI。

\n

在此输入图像描述

\n

这是游戏结束时修改后的 GUI。

\n

在此输入图像描述

\n

代码

\n

这是完整的可运行代码。我创建了所有附加类的内部类,因此我可以将此代码作为一个块发布。

\n

您应该将单独的类放在单独的文件中。

\n

设置 Swing GUI 项目时,我为模型、视图和控制器创建单独的包。这有助于我保持代码的组织性。

\n
import java.awt.BorderLayout;\nimport java.awt.Color;\nimport java.awt.Dimension;\nimport java.awt.Font;\nimport java.awt.FontMetrics;\nimport java.awt.Graphics;\nimport java.awt.Point;\nimport java.awt.event.ActionEvent;\nimport java.awt.event.ActionListener;\nimport java.awt.event.KeyEvent;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Random;\n\nimport javax.swing.AbstractAction;\nimport javax.swing.ActionMap;\nimport javax.swing.BorderFactory;\nimport javax.swing.InputMap;\nimport javax.swing.JButton;\nimport javax.swing.JFrame;\nimport javax.swing.JPanel;\nimport javax.swing.KeyStroke;\nimport javax.swing.SwingUtilities;\nimport javax.swing.Timer;\n\npublic class SnakeGame implements Runnable {\n\n    public static void main(String arg[]) {\n        SwingUtilities.invokeLater(new SnakeGame());\n    }\n    \n    private final GamePanel gamePanel;\n    \n    private final JButton restartButton;\n    \n    private final SnakeModel model;\n    \n    public SnakeGame() {\n        this.model = new SnakeModel();\n        this.restartButton = new JButton("Start Game");\n        this.gamePanel = new GamePanel(model);\n    }\n\n    @Override\n    public void run() {\n        JFrame frame = new JFrame("Snake");\n        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);\n        \n        frame.add(gamePanel, BorderLayout.CENTER);\n        frame.add(createButtonPanel(), BorderLayout.SOUTH);\n        \n        frame.pack();\n        frame.setResizable(false);\n        frame.setLocationRelativeTo(null);\n        frame.setVisible(true);\n    }\n    \n    private JPanel createButtonPanel() {\n        JPanel panel = new JPanel();\n        panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));\n        panel.setBackground(Color.black);\n        \n        restartButton.addActionListener(new ButtonListener(this, model));\n        panel.add(restartButton);\n        \n        return panel;\n    }\n    \n    public JButton getRestartButton() {\n        return restartButton;\n    }\n\n    public void repaint() {\n        gamePanel.repaint();\n    }\n    \n    public class GamePanel extends JPanel {\n\n        private static final long serialVersionUID = 1L;\n        \n        private final int margin, scoreAreaHeight, unitSize;\n        \n        private final Random random;\n        \n        private final SnakeModel model;\n        \n        public GamePanel(SnakeModel model) {\n            this.model = model;\n            this.margin = 10;\n            this.unitSize = 25;\n            this.scoreAreaHeight = 36 + margin;\n            this.random = new Random();\n            this.setBackground(Color.black);\n            \n            Dimension gameArea = model.getGameArea();\n            int width = gameArea.width * unitSize + 2 * margin;\n            int height = gameArea.height * unitSize + 2 * margin + scoreAreaHeight;\n            this.setPreferredSize(new Dimension(width, height));\n            setKeyBindings();\n        }\n        \n        private void setKeyBindings() {\n            InputMap inputMap = this.getInputMap(JPanel.WHEN_IN_FOCUSED_WINDOW);\n            ActionMap actionMap = this.getActionMap();\n            \n            inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "up");\n            inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "down");\n            inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "left");\n            inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "right");\n            \n            inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), "up");\n            inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0), "down");\n            inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0), "left");\n            inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0), "right");\n            \n            actionMap.put("up", new MovementAction(model, \'U\', \'D\'));\n            actionMap.put("down", new MovementAction(model, \'D\', \'U\'));\n            actionMap.put("left", new MovementAction(model, \'L\', \'R\'));\n            actionMap.put("right", new MovementAction(model, \'R\', \'L\'));\n        }\n        \n        @Override\n        protected void paintComponent(Graphics g) {\n            super.paintComponent(g);\n            \n            Dimension gameArea = model.getGameArea();\n            drawHorizontalGridLines(g, gameArea);\n            drawVerticalGridLines(g, gameArea);\n            drawSnake(g);\n            drawScore(g, gameArea);\n            \n            if (model.isGameOver) {\n                drawGameOver(g, gameArea);\n            } else {\n                drawApple(g);\n            }\n        }\n\n        private void drawHorizontalGridLines(Graphics g, Dimension gameArea) {\n            int y1 = scoreAreaHeight + margin;\n            int y2 = y1 + gameArea.height * unitSize;\n            int x = margin;\n            for (int index = 0; index <= gameArea.width; index++) {\n                g.drawLine(x, y1, x, y2);\n                x += unitSize;\n            }\n        }\n\n        private void drawVerticalGridLines(Graphics g, Dimension gameArea) {\n            int x1 = margin;\n            int x2 = x1 + gameArea.width * unitSize;\n            int y = margin + scoreAreaHeight;\n            for (int index = 0; index <= gameArea.height; index++) {\n                g.drawLine(x1, y, x2, y);\n                y += unitSize;\n            }\n        }\n\n        private void drawApple(Graphics g) {\n            // Draw apple\n            g.setColor(Color.red);\n            Point point = model.getAppleLocation();\n            if (point != null) {\n                int a = point.x * unitSize + margin + 1;\n                int b = point.y * unitSize + margin + scoreAreaHeight + 1;\n                g.fillOval(a, b, unitSize - 2, unitSize - 2);\n            }\n        }\n\n        private void drawScore(Graphics g, Dimension gameArea) {\n            g.setColor(Color.red);\n            g.setFont(new Font("Ink Free", Font.BOLD, 36));\n            FontMetrics metrics = getFontMetrics(g.getFont());\n            int width = 2 * margin + gameArea.width * unitSize;\n            String text = "SCORE: " + model.getApplesEaten();\n            int textWidth = metrics.stringWidth(text);\n            g.drawString(text, (width - textWidth) / 2, g.getFont().getSize());\n        }\n        \n        private void drawSnake(Graphics g) {\n            // Draw snake\n            Snake snake = model.getSnake();\n            List<Point> cells = snake.getCells();\n            Point cell = cells.get(0);\n            drawSnakeCell(g, cell, Color.green);\n            for (int index = 1; index < cells.size(); index++) {\n//              Color color = new Color(45, 180, 0);\n                // random color\n                Color color = new Color(getColorValue(), getColorValue(), \n                        getColorValue());\n                cell = cells.get(index);\n                drawSnakeCell(g, cell, color);\n            }\n        }\n        \n        private void drawSnakeCell(Graphics g, Point point, Color color) {\n            int x = margin + point.x * unitSize;\n            int y = margin + scoreAreaHeight + point.y * unitSize;\n            if (point.y >= 0) {\n                g.setColor(color);\n                g.fillRect(x, y, unitSize, unitSize);\n            }\n        }\n        \n        private int getColorValue() {\n            // White has color values of 255\n            return random.nextInt(64) + 191;\n        }\n        \n        private void drawGameOver(Graphics g, Dimension gameArea) {\n            g.setColor(Color.red);\n            g.setFont(new Font("Ink Free", Font.BOLD, 72));\n            FontMetrics metrics = getFontMetrics(g.getFont());\n            String text = "Game Over";\n            int textWidth = metrics.stringWidth(text);\n            g.drawString(text, (getWidth() - textWidth) / 2, getHeight() / 2);\n        }\n        \n    }\n    \n    public class ButtonListener implements ActionListener {\n        \n        private final int delay;\n        \n        private final SnakeGame view;\n        \n        private final SnakeModel model;\n        \n        private final Timer timer;\n\n        public ButtonListener(SnakeGame view, SnakeModel model) {\n            this.view = view;\n            this.model = model;\n            this.delay = 750;\n            this.timer = new Timer(delay, new TimerListener(view, model));\n        }\n\n        @Override\n        public void actionPerformed(ActionEvent event) {\n            JButton button = (JButton) event.getSource();\n            String text = button.getText();\n            \n            if (text.equals("Start Game")) {\n                button.setText("Restart Game");\n            } \n            \n            button.setEnabled(false);\n            model.initialize();\n            timer.restart();\n        }\n        \n    }\n    \n    public class TimerListener implements ActionListener {\n        \n        private final SnakeGame view;\n        \n        private final SnakeModel model;\n\n        public TimerListener(SnakeGame view, SnakeModel model) {\n            this.view = view;\n            this.model = model;\n        }\n\n        @Override\n        public void actionPerformed(ActionEvent event) {\n            moveSnake();\n            checkApple();\n            model.checkCollisions();\n            if (model.isGameOver()) {\n                Timer timer = (Timer) event.getSource();\n                timer.stop();\n                model.setRunning(false);\n                view.getRestartButton().setEnabled(true);\n            }\n            view.repaint();\n        }\n        \n        private void moveSnake() {\n            Snake snake = model.getSnake();\n            Point head = (Point) snake.getHead().clone();\n            \n            switch (snake.getDirection()) {\n            case \'U\':\n                head.y--;\n                break;\n            case \'D\':\n                head.y++;\n                break;\n            case \'L\':\n                head.x--;\n                break;\n            case \'R\':\n                head.x++;\n                break;\n            }\n            \n            snake.removeTail();\n            snake.addHead(head);\n            \n//          System.out.println(Arrays.toString(cells.toArray()));\n        }\n        \n        private void checkApple() {\n            Point appleLocation = model.getAppleLocation();\n            Snake snake = model.getSnake();\n            Point head = snake.getHead();\n            Point tail = (Point) snake.getTail().clone();\n            \n            if (head.x == appleLocation.x && head.y == appleLocation.y) {\n                model.incrementApplesEaten();\n                snake.addTail(tail);\n                model.generateRandomAppleLocation();\n            }\n        }\n        \n    }\n    \n    public class MovementAction extends AbstractAction {\n\n        private static final long serialVersionUID = 1L;\n        \n        private final char newDirection, oppositeDirection;\n        \n        private final SnakeModel model;\n\n        public MovementAction(SnakeModel model, char newDirection,\n                char oppositeDirection) {\n            this.model = model;\n            this.newDirection = newDirection;\n            this.oppositeDirection = oppositeDirection;\n        }\n\n        @Override\n        public void actionPerformed(ActionEvent event) {\n            if (model.isRunning()) {\n                Snake snake = model.getSnake();\n                char direction = snake.getDirection();\n                if (direction != oppositeDirection && direction != newDirection) {\n                    snake.setDirection(newDirection);\n//                  System.out.println("New direction: " + newDirection);\n                }\n            }\n        }\n        \n    }\n    \n    public class SnakeModel {\n        \n        private boolean isGameOver, isRunning;\n        \n        private int applesEaten;\n        \n        private Dimension gameArea;\n        \n        private Point appleLocation;\n        \n        private Random random;\n        \n        private Snake snake;\n        \n        public SnakeModel() {\n            this.random = new Random();\n            this.snake = new Snake();\n            this.gameArea = new Dimension(24, 24);\n        }\n        \n        public void initialize() {\n            this.isRunning = true;\n            this.isGameOver = false;\n            this.snake.initialize();\n            this.applesEaten = 0;\n            \n            Point point = generateRandomAppleLocation();\n            // Make sure first apple isn\'t under snake\n            int y = (point.y == 0) ? 1 : point.y;\n            this.appleLocation = new Point(point.x, y);\n        }\n        \n        public void checkCollisions() {\n            Point head = snake.getHead();\n            \n            // Check for snake going out of the game area\n            if (head.x < 0 || head.x > gameArea.width) {\n                isGameOver = true;\n                return;\n            }\n            \n            if (head.y < 0 || head.y > gameArea.height) {\n                isGameOver = true;\n                return;\n            }\n            \n            // Check for snake touching itself\n            List<Point> cells = snake.getCells();\n            for (int index = 1; index < cells.size(); index++) {\n                Point cell = cells.get(index);\n                if (head.x == cell.x && head.y == cell.y) {\n                    isGameOver = true;\n                    return;\n                }\n            }\n        }\n        \n        public Point generateRandomAppleLocation() {\n            int x = random.nextInt(gameArea.width);\n            int y = random.nextInt(gameArea.height);\n            this.appleLocation = new Point(x, y);\n            return getAppleLocation();\n        }\n        \n        public void incrementApplesEaten() {\n            this.applesEaten++;\n        }\n        \n        public boolean isRunning() {\n            return isRunning;\n        }\n\n        public void setRunning(boolean isRunning) {\n            this.isRunning = isRunning;\n        }\n\n        public boolean isGameOver() {\n            return isGameOver;\n        }\n\n        public void setGameOver(boolean isGameOver) {\n            this.isGameOver = isGameOver;\n        }\n\n        public Dimension getGameArea() {\n            return gameArea;\n        }\n\n        public int getApplesEaten() {\n            return applesEaten;\n        }\n\n        public Point getAppleLocation() {\n            return appleLocation;\n        }\n\n        public Snake getSnake() {\n            return snake;\n        }\n        \n    }\n    \n    public class Snake {\n        \n        private char direction;\n        \n        private List<Point> cells;\n        \n        public Snake() {\n            this.cells = new ArrayList<>();\n            initialize();\n        }\n        \n        public void initialize() {\n