【问题标题】:Smooth animation in a snake game (java)?蛇游戏(java)中的流畅动画?
【发布时间】:2014-05-07 20:57:48
【问题描述】:

我用 java 制作了一个基本的蛇游戏,我需要一些帮助来获得更流畅的动画。蛇的每一段都是一个 20x20 的正方形,所以我让蛇以每刻 20 像素的步长移动。这使得蛇看起来像在网格上移动,这意味着它总是会与只在“网格”上生成的食物对齐。现在我的问题是,当我尝试将其移动 3 步时,它不再与“网格”对齐。我遇到的另一个更严重的问题是蛇通过移动第一个方格来移动,然后将所有其他方格设置到数组中的下一个位置(参见代码)。问题是,当它移动 3 步时,蛇会收缩,因此每个原点之间只有 3 的间隙,而不是 20。任何人都可以帮助解决这些问题吗?如果需要,我可以添加整个源代码。

import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferStrategy;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Random;
import javax.swing.Timer;

public class player1 extends Canvas implements Runnable {

private keyevents keyevent;
private element [] elements;
private element goal;
private int numSegments, score, endY, quitX, snakeSize, windowSize;
private Font scorefont;

private long cycleTime;
private final int FRAME_DELAY;
private BufferStrategy bf;
private boolean gameOver, isRunning;

public player1(Frame window) {
    setSize(new Dimension(window.getWidth(), window.getHeight()));
    FRAME_DELAY = 20;
    windowSize = 400;
    snakeSize = 20;
    score = 0;
    isRunning = false;
    numSegments = 5;
    scorefont =  new Font("Verdana", Font.BOLD, snakeSize);
    elements = new element [300];
    goal = new element(randompos(snakeSize,windowSize-snakeSize),randompos(snakeSize,windowSize-snakeSize), snakeSize, Color.green);
    keyevent = new keyevents();
    keyevent.setP1Keys(2,true);

    for (int i=0, xPos = round(windowSize/2), yPos = round(windowSize/2); i<numSegments; i++, xPos+=snakeSize) {
        elements[i] = new element(xPos,yPos, snakeSize, Color.blue);
    }

    addKeyListener(new KeyAdapter() {
        public void keyPressed(KeyEvent evt) {
            keyevent.moveIt(evt); 
            switch(evt.getKeyCode()){
            case KeyEvent.VK_ESCAPE:
                isRunning = false;
                screen.newMenu();
            }
        }
    });
}

public void start(player1 ex){
    isRunning = true;
    Thread gameThread = new Thread(ex);
    gameThread.setPriority(Thread.MIN_PRIORITY);
    gameThread.start(); 
}

public void run(){ 
    cycleTime = System.currentTimeMillis();
    while(isRunning){
        logic();
        render();
        sync();
    }
}

public void render() {
    if (bf==null){
        bf = getBufferStrategy();
    }
    Graphics2D g2 = null;
    try{
        g2 = (Graphics2D) bf.getDrawGraphics(); 
        g2.setColor(Color.black);
        g2.fillRect(0, 0, windowSize, windowSize);
        for (int i=0;i<numSegments;i+=1) {
            elements[i].draw(g2);
        }
        g2.setColor(Color.green);
        goal.draw(g2);
        g2.setColor(Color.orange);
        g2.fill3DRect(0, 0, windowSize, snakeSize, true);
        g2.setColor(Color.red);
        g2.setFont(scorefont);
        g2.drawString("Score: "+score, 5, snakeSize-4);
        FontMetrics fm = g2.getFontMetrics();
        g2.setColor(Color.blue);
        fm = g2.getFontMetrics();
        g2.setColor(Color.black);
        quitX = (windowSize - fm.stringWidth("ESC = quit")-5);
        g2.drawString("ESC = quit",quitX,snakeSize-snakeSize/5);
    }finally{
        g2.dispose();
    }
    bf.show();
    Toolkit.getDefaultToolkit().sync();
}

public void sync(){
    cycleTime = cycleTime + FRAME_DELAY;
    long difference = cycleTime - System.currentTimeMillis();
    try {
        Thread.sleep(Math.max(0, difference));
    }
    catch(InterruptedException e) {
        e.printStackTrace();
    }
}

public void logic(){
    int x = elements[0].getX();
    int y = elements[0].getY();
    Rectangle elementrect = elements[0].getRect();  
    keyevent.setP1Pressed(false);

    //Movement
    for(int i = numSegments-1; i>0; i--){
        elements[i].setX(elements[i-1].getX());
        elements[i].setY(elements[i-1].getY());
    }   
    if(keyevent.getP1Keys(0)){
        elements[0].setY(y+20);
    }
    else if(keyevent.getP1Keys(1)){
        elements[0].setY(y-20);
    }
    else if(keyevent.getP1Keys(2)){
        elements[0].setX(x-20);
    }
    else if(keyevent.getP1Keys(3)){ 
        elements[0].setX(x+20);
    }
    if(elements[0].getX()>windowSize-snakeSize){
        elements[0].setX(0);
    }
    else if(elements[0].getX()<0){
        elements[0].setX(windowSize-snakeSize);
    }
    if(elements[0].getY()>windowSize-snakeSize){
        elements[0].setY(0);
    }
    else if(elements[0].getY()<0+snakeSize){
        elements[0].setY(windowSize-snakeSize);
    }
    for(int i=0; i<numSegments; i++){
        elements[i].updateRect();
    }       

    //Collision
    if(elementrect.intersects(goal.getRect())){
        numSegments+=1;
        elements[numSegments-1] = new element(elements[numSegments-2].getX(),elements[numSegments-2].getY(), snakeSize,Color.blue);
        goal.setX(randompos(snakeSize,windowSize-snakeSize));
        goal.setY(randompos(snakeSize,windowSize-snakeSize));
        score+=1;
    }
    for(int i=1; i<numSegments; i++){
        if(elementrect.intersects(elements[i].getRect())){
            gameOver();
        }
    }
}

public void gameOver(){
    isRunning = false;
}

public int randompos(int min,int max){
    System.out.println(snakeSize);
    int range = max-min;
    Random randompos = new Random();
    int pos = randompos.nextInt(range)+min;
    pos*=2;
    pos += snakeSize;
    pos /= snakeSize*2;
    pos *= snakeSize*2;
    pos/=2;
    return pos;
}
}

【问题讨论】:

  • 为什么不移动 20 倍(即 2、5、10)?然后,您的蛇将与地图上的每个块对齐,应该可以解决您的问题。不像 3,你的蛇只会与每 3 个方块对齐。

标签: java swing animation


【解决方案1】:

1) 正确使用 Java 命名约定 player1 应该是 Player1

2) 不要使用 pre_historic AWT Canvas,使用 Swing JPanel, JLabel or JComponent,同样适用于 Frame ---&gt; JFrame

3) 不要使用KeyListener,因为您的画布需要Focus,最简单的是使用KeyBinding

4) 你对Concurency in Swing 有疑问,使用javax.swing.Timer 而不是Runnable#Tread 的错误实现

5) 永远不要将 Thread.sleep(Math.max(0, difference)); 用于 AWT/Swing J/Components,因为阻塞 EventDispatchTread,并且由于 Thread.sleep() 的错误实现,您的 GUI 将被冻结 os 保持 un_responsible,请使用 javax.swing.Timer处理秋千中的任何事件

6) 在此处发布 SSCCE,展示您真正的 uissues,而不是一堆 un_relatted 代码和一些其他错过(也许是,也许不是)重要的课程,

【讨论】:

  • 我想为你的每一分都给你+1,但这是不可能的:-(
  • 谢谢您的帮助。我会先解决所有这些问题,然后我会回到我在这里发布的问题。我是一个编程/java 菜鸟,所以我需要做很多事情。
  • 很高兴为您提供帮助,在这个论坛上有很多相关的问答
【解决方案2】:

除了@mKorbel 的出色建议之外,请考虑为您的蛇段使用java.util.Queue

Queue<Element> snake = new LinkedList<Element>();

然后单个动画步骤只需删除最旧的Element 并添加一个根据游戏的位置和速度规则偏移的新的:

snake.remove();
snake.add(newElement());
this.repaint();

【讨论】:

  • @mKorbel:我想说这是你第二点的一部分,但我会添加相关的引用,“Swing 程序应该覆盖paintComponent() 而不是覆盖paint()。”—@987654322 @.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多