2

我正在写蛇游戏。我被动画困住了,因为我想获得流畅的动画。我不知道如何加倍缓冲图像以获得双缓冲。必须做什么才能使其成为双缓冲?我使用扩展 JFrame 的主框架,在这里我添加了两个 JPanel - 一个用于状态栏,一个用于动画。以下是用于蛇动画的类:

播放器类

 package snake;

import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.util.ArrayList;

import javax.swing.ImageIcon;

public class Player 
{
private int headSizeX;
private int headSizeY;
private int tailSizeX;
private int tailSizeY;
private int x;
private int y;
private int speed = 5;
private int snakeSize = 40;
private Image[] snake = new Image[5];
private ArrayList<Integer> X,Y;
private static int imageNr = 0;
private int c = 0;

private int tmp;
private boolean death = false;
static int player;
private static boolean inverse = false;
private boolean left = false;
private boolean right = false;
private boolean up = true;
private boolean down = false;
public Player()
{
    initPlayer();
    headSizeX = snake[0].getWidth(null);
    headSizeY = snake[0].getHeight(null)-2;
    tailSizeX = snake[4].getWidth(null);
    tailSizeY = snake[4].getHeight(null);
    System.out.println("tail: "+tailSizeX+" "+tailSizeY);
    x = MainGamePanel.getSizeX()/2;
    y= MainGamePanel.getSizeY()-130;
}

public void initPlayer()
{
    int imgNr = 5;
    X = new ArrayList<Integer>();
    Y = new ArrayList<Integer>();   
    String name = "green";
    switch (player) 
    {
    case 1:
        name = "green"; break;
    case 2:
        name = "red"; break;
    case 3:
        name = "blue"; break;
    }

    for (int nr = 1; nr <= imgNr; nr++)
    {
        snake[nr-1] = new ImageIcon("img/" +name+"/snake" +nr+".png").getImage();
    }

    X.add(MainGamePanel.getSizeX()/2);
    Y.add( MainGamePanel.getSizeY()-200);
    X.add( MainGamePanel.getSizeX()/2);
    Y.add( MainGamePanel.getSizeX()/2+33);
    for (int i = 2; i < snakeSize; i++) {
        X.add( MainGamePanel.getSizeX()/2);
        Y.add( MainGamePanel.getSizeX()/2 + i*20+13);
    }
}

public void paint(Graphics g)
{
    //g.drawImage(snake[imageNr], x,y,headSizeX,headSizeY,null);

    for (int i = 0; i < snakeSize; i++) {
        if (i == 0)
            g.drawImage(snake[imageNr], X.get(i), Y.get(i), null);
        else
            g.drawImage(snake[4], X.get(i), Y.get(i), null);
    }
    /*g.drawImage(snake[4],x, y+headSizeY, tailSizeX, tailSizeY, null);
    for (int i = 1;i<snakeSize;i++)
        g.drawImage(snake[4],x, y+i*tailSizeY+headSizeY, tailSizeX,     tailSizeY, null);*/
}

public void update()
{
    y = MainGamePanel.getSizeY()-headSizeY - 35;
    for (int i = snakeSize-1; i > 0; i--) {
        X.set(i, X.get(i-1));
        Y.set(i, Y.get(i-1));
    }

    if (left) {
        tmp = X.get(0);
        X.set(0, tmp-20);
        imageNr = 3;
    }
    if (right) {
        tmp = X.get(0);
        X.set(0, tmp+20);
        imageNr = 1;
    }
    if (up) {
        tmp = Y.get(0);
        Y.set(0, tmp-20);
        imageNr = 0;
    }
    if (down) {
        tmp = Y.get(0);
        Y.set(0, tmp+20);
        imageNr = 2;
    }
}

public void keyPressed(KeyEvent e)
{
     int key = e.getKeyCode();

        if ((key == KeyEvent.VK_LEFT) && (!right)) {
            left = true;
            up = false;
            down = false;
            System.out.println("LEWO");
        }

        if ((key == KeyEvent.VK_RIGHT) && (!left)) {
            right = true;
            up = false;
            down = false;
            System.out.println("PRAWO");
        }

        if ((key == KeyEvent.VK_UP) && (!down)) {
            up = true;
            right = false;
            left = false;
            System.out.println("GÓRA");
        }

        if ((key == KeyEvent.VK_DOWN) && (!up)) {
            down = true;
            right = false;
            left = false;
            System.out.println("DÓŁ");
        }
}

public void collision()
{
    death = true;
}

public void reset()
{
    imageNr = 0;
    death = false;
}

public void setInverse(boolean set)
{
    inverse = set;
}

public void increaseSpeed(int inc)
{
    speed += inc;
}

public void decreaseSpeed(int dec)
{
    speed -=dec;
}

public int getSnakeSize()
{
    return snakeSize;
}

public void increaseSnakeSize()
{
    snakeSize += 1;
}

public void decreaseSnakeSize(int dec)
{
    snakeSize -= dec;
}
}

MainGamePanel.class

package snake;

import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;

import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;

@SuppressWarnings("serial")
public class MainGamePanel extends JPanel implements KeyListener{

private Image bounds;
private Player player;
public static int sizex;
private Image tail;
private Image background;
private int lives;
private int speed;
private int levels;
private int counter = 0;
private int appleCounter = 0;
private static int level = 1;
public static int sizeX = 784;
public static int sizeY = 617;
public static int applesNumber;
private boolean gameover = false;
private boolean gameend = false;
private boolean death = false;
private boolean levelCompleted = false;
private Graphics buffer;
private BufferedImage img;
public MainGamePanel(int[] settings)
{   
    lives = settings[0];
    speed = settings[1];
    levels = settings[2];
    bounds = new ImageIcon("img/bounds.jpg").getImage();
    setFocusable(true);
    addKeyListener(this);
    //new Apple();
}

public void init()
  {
    player = new Player();
    img = new BufferedImage(sizeX, sizeY, 2);

    Levels.getLevel(1);

    this.applesNumber = Levels.getApplesNumber();
    this.background = new ImageIcon("img/bg/" + Levels.getBackground()).getImage();
  }


public void addNotify()
  {
    super.addNotify(); 
    init();
  }

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

    buffer = img.getGraphics();
    buffer.drawImage(background, 0,0, sizeX, sizeY, null);
    player.paint(buffer);
    for (int i = 0; i <= getWidth(); i += 12) {
        buffer.drawImage(bounds, i, 0, this);
        buffer.drawImage(bounds, i, getHeight()-12, this);
    }

    for (int i = 12; i < getHeight(); i += 12) {
        buffer.drawImage(bounds, 0, i, this);
        buffer.drawImage(bounds, getWidth()-12, i, this);
    }
    g.drawImage(this.img, 0, 0, getWidth(), getHeight(), null);

    buffer.clearRect(12, 12, sizeX, sizeY);

}

public void play()
{
    if (level == this.levels) gameend = true;
    this.player.reset();
    this.counter = 0;
    this.appleCounter = 0;
    long StartTime = System.currentTimeMillis();
    player.update();
    repaint();
    /*do
    {
        Thread.yield();
    }
    while (System.currentTimeMillis() - StartTime < this.speed);*/
}

public void gameLoop()
{
    while(true)
    {
        play();
        try
        {
            Thread.sleep(150);
        }
        catch (InterruptedException ex)
        {

        }
        if (death)
        {
            lives -= 1;
            death = false; continue;
        }
        levelCompleted = false;
        level+=1;

        Levels.getLevel(level);

        applesNumber = Levels.getApplesNumber();


    }
}
public static int getApp()
{
    return applesNumber;
}

public static int getSizeX()
{
    return sizeX;
}

public static int getSizeY()
{
    return sizeY;
}

public void setGameOver()
{
    gameover = true;
}

@Override
public void keyPressed(KeyEvent e) 
{
    if (e.getKeyCode() == KeyEvent.VK_ESCAPE) System.exit(0);
    player.keyPressed(e);   
}

@Override
public void keyReleased(KeyEvent e) {}

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

和 JFrame 的 Game.class

package snake;

import java.awt.Dimension;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import java.awt.BorderLayout;

@SuppressWarnings("serial")
public class Game extends JFrame {

//public SnakeTheGame start;
private ImageIcon icon;
StatBar statbar;
private MainGamePanel start;   

public static final int WIDTH = 800;
public static final int HEIGHT = 700;
public static final int MIN_WIDTH = 450;    
public static final int MIN_HEIGHT = 450;

public Game()
{
    start = new MainGamePanel(new int[] { Settings.getLives(), Settings.getSpeed(), Settings.getLevels() });
    statbar = new StatBar();
    icon = new ImageIcon("img//icon.png");
    setBounds(200, 200, WIDTH, HEIGHT);
    setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
    setTitle("Snake The Game");
    setIconImage(this.icon.getImage());
    setLocationRelativeTo(null);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    setLayout(new BorderLayout());
    getContentPane().add(statbar, BorderLayout.SOUTH);
    getContentPane().add(start, BorderLayout.CENTER);
   // this.createBufferStrategy(2);
    this.start.setVisible(true);
    start.requestFocus();

}

public void start()
{
    start.gameLoop();
}
}
4

1 回答 1

2

JPanel 默认是双缓冲的。您需要做的是删除循环以支持执行 60 FPS 的计时器,调用 play() 并调用其中一个重绘方法。


示例代码

(从 java.util 导入。我没有使用你的名字。)

private class AnimationTask extends TimerTask {

    @Override
    public void run() {
        play();
        animationPanel.repaint();
    }

}

private Timer timer;

/**
 * Creates new form AnimationDemoFrame
 */
public AnimationDemoFrame() {
    timer = new Timer();
    initComponents();
    timer.schedule(new AnimationTask(), 150);
}

private void play() {
    ;
}
于 2012-05-13T08:55:08.640 回答