在Swing中平稳地移动蛇

时间:2019-02-07 14:03:30

标签: java swing animation

我正在使用Swing用J​​ava开发一个简单的Snake游戏。 到目前为止,我制作了令我不安的蛇动画:当蛇移动时,它似乎无缘无故地滞后,但是当我用箭头键移动时,它就变得平滑了。

当它成一直线时,如何使它也平滑移动? 这是代码:

GameFrame

public class GameFrame extends JFrame {
    private GamePanel gamePanel;
    private JLabel scoreLabel;

    public GameFrame() throws HeadlessException {
        this.setTitle("Snake");
        this.setBounds(100, 100, 400, 400);
        this.setLocationRelativeTo(null);
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        this.setResizable(false);
        getContentPane().setLayout(null);
        getContentPane().setBackground(Color.BLACK);

        scoreLabel = new JLabel("0000");
        scoreLabel.setBounds(0, 0, 70, 20);
        scoreLabel.setForeground(Color.WHITE);
        getContentPane().add(scoreLabel);

        gamePanel = new GamePanel();
        gamePanel.setBounds(20, 20, 360, 350);
        this.add(gamePanel);

        this.setVisible(true);
    }
}

GamePanel

public class GamePanel extends JPanel implements KeyListener, ActionListener {
    private GameManager gameManager;
    private Timer timer;
    private final int DELAY = 150;

    GamePanel() {
        this.setOpaque(true);
        this.setBackground(new Color(51, 51, 51));
        this.addKeyListener(this);
        this.setFocusable(true);
        this.requestFocus();
        gameManager = new GameManager(this);
        timer = new Timer(DELAY, this);
        timer.start();
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        gameManager.renderSnake(g);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        gameManager.gameLoop();
    }

    @Override
    public void keyPressed(KeyEvent e) {
        switch (e.getKeyCode()) {
            case KeyEvent.VK_UP:
                gameManager.moveSnakeUp();
                break;
            case KeyEvent.VK_DOWN:
                gameManager.moveSnakeDown();
                break;
            case KeyEvent.VK_RIGHT:
                gameManager.moveSnakeRight();
                break;
            case KeyEvent.VK_LEFT:
                gameManager.moveSnakeLeft();
                break;
        }
    }

    @Override
    public void keyTyped(KeyEvent e) { }

    @Override
    public void keyReleased(KeyEvent e) { }
}

GameManager

public class GameManager {
    private Color snakeColor;
    private Snake snake;
    private GamePanel gamePanel;
    private boolean running;

    public GameManager(GamePanel gamePanel) {
        this.gamePanel = gamePanel;
        snakeColor = Color.GREEN;
        snake = new Snake();
        running = true;
    }

    public void gameLoop() {
        update();
        draw();
    }

    public void renderSnake(Graphics graphics) {
        Graphics2D graphics2D = (Graphics2D) graphics;
        graphics2D.setColor(snakeColor);
        for (Rectangle tile : snake.getBody())
            graphics2D.fillRect(tile.x, tile.y, tile.width, tile.height);
    }

    public void update() {
        snake.move();
    }

    public boolean isRunning() {
        return running;
    }

    public void draw() {
        gamePanel.repaint();
    }

    public void moveSnakeUp() {
        snake.setUpDirection();
    }

    public void moveSnakeDown() {
        snake.setDownDirection();
    }

    public void moveSnakeRight() {
        snake.setRightDirection();
    }

    public void moveSnakeLeft() {
        snake.setLeftDirection();
    }
}

public class Snake {
    private final int SNAKE_SPEED = 10;
    private final int BODY_WIDTH = 10;

    private LinkedList<Rectangle> body;
    private Directions direction;

    public Snake() {
        direction = Directions.RIGHT;
        body = new LinkedList<>();
        body.add(new Rectangle(50, 20, BODY_WIDTH, BODY_WIDTH));
        body.add(new Rectangle(40, 20, BODY_WIDTH, BODY_WIDTH));
        body.add(new Rectangle(30, 20, BODY_WIDTH, BODY_WIDTH));
        body.add(new Rectangle(20, 20, BODY_WIDTH, BODY_WIDTH));
        body.add(new Rectangle(10, 20, BODY_WIDTH, BODY_WIDTH));
    }

    public LinkedList<Rectangle> getBody() {
        return body;
    }

    public void setUpDirection() {
        if (direction != Directions.UP)
            direction = Directions.UP;
    }

    public void setDownDirection() {
        if (direction != Directions.DOWN)
            direction = Directions.DOWN;
    }

    public void setRightDirection() {
        if (direction != Directions.RIGHT)
            direction = Directions.RIGHT;
    }

    public void setLeftDirection() {
        if (direction != Directions.LEFT)
            direction = Directions.LEFT;
    }

    public void move() {
        Rectangle newHead = body.removeLast();
        newHead.x = body.peek().x;
        newHead.y = body.peek().y;

        switch (direction) {
            case UP:
                newHead.y -= SNAKE_SPEED;
                break;
            case DOWN:
                newHead.y += SNAKE_SPEED;
                break;
            case RIGHT:
                newHead.x += SNAKE_SPEED;
                break;
            case LEFT:
                newHead.x -= SNAKE_SPEED;
                break;
        }

        body.addFirst(newHead);
    }
}

我尝试使用Thread和不同的延迟时间值,但无济于事。如何改善呢?

非常感谢。

编辑

我找到了使用BufferedImage的解决方案,它确实带来了很大的不同,既简单又有效:

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    BufferedImage bufferedImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
    Graphics bufferedGraphics = bufferedImage.getGraphics();

    gameManager.renderSnake(bufferedGraphics);
    gameManager.renderFruit(bufferedGraphics);

    g.drawImage(bufferedImage, 0, 0, this);
}

编辑2

即使不使用Timer中的java.Swing,而是使用Thread,我终于设法制作出了不错的动画。对我来说很好。

对于这里感兴趣的是code

1 个答案:

答案 0 :(得分:1)

似乎是给您带来麻烦的是瓦片的增加。 我将其更改为1像素。有了它,它就更流畅了。我还添加了一些会随机增加大小的内容。您可以跳过平铺方法,而将单个对象用于一个方向上的线。您可以使用颜色和混合功能使其更加平滑。有很多改进的空间-但也许可以使您更进一步。 另外,我使用Netbeans的Swing编辑功能不会浪费太多时间。

We had trouble finding a sample.
Error code 400: [{

  "error": {
    "code": 400,
    "message": "Invalid JSON payload received. Unknown name \"id\" at 'structured_query.order_by[0]': Cannot find field.",
    "status": "INVALID_ARGUMENT",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.BadRequest",
        "fieldViolations": [
          {
            "field": "structured_query.order_by[0]",
            "description": "Invalid JSON payload received. Unknown name \"id\" at 'structured_query.order_by[0]': Cannot find field."
          }
        ]
      }
    ]
  }
}
]