我做了一个蛇游戏作为大学的任务,它运作得很好 - 除了它像疯了一样闪烁。我知道这是因为我直接在JFrame中绘制,而不是在提供双缓冲的JPanel中,但由于我没有太多的摇摆经验,我不知道如何实际做到这一点。任何帮助将不胜感激!
import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Random;
public class SnakeGame extends JFrame implements KeyListener, ActionListener{
//Initiate all the variables we need
public ArrayList<SnakeElement> snakeBody = new ArrayList<SnakeElement>();
public SnakeElement snake = new SnakeElement(100, 100);
public AppleElement apple = new AppleElement();
public int moveSnakeX = 1;
public int moveSnakeY = 0;
public int score = 0;
public int highscore = 0;
public int timer = 0;
public static final Font scoreFont = new Font("Arial", Font.BOLD, 20);
//Create the JFrame
public SnakeGame(){
this.setTitle("Snake");
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(600,600);
this.setResizable(false);
setLocationRelativeTo(null);
this.addKeyListener(this);
setBackground(Color.BLACK);
snakeBody.add(snake);
Timer t = new Timer(5, this);
t.start();
}
public void drawSomething(){
timer += 5;
//Spawns a new apple every 5 seconds
if(timer >= 5000){
System.out.println("Apple escaped!");
Random pos = new Random();
apple.setX(pos.nextInt(581 + 1 - 21) + 21); //Bound: (20, 580)
apple.setY(pos.nextInt(581 + 1 - 21) + 21); //Bound: (20, 580)
timer = 0;
}
Graphics g = this.getGraphics();
g.clearRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(Color.WHITE);
g.setFont(scoreFont);
g.drawString("Score: " + score, 500, 60);
this.checkCollision();
this.MoveSnake();
//Draws every element in snakeBody
for(int i = 0; i < this.snake.getSize()-1; i++) {
snakeBody.get(i).drawSnake(g);
}
//Updates the ArrayList snakeBody: all element-coordinates equals the element-coordinates before them
for(int i = snakeBody.size()-1; i > 0; i--) {
SnakeElement penultimate = snakeBody.get(i-1); //Gets the penultimate element in snakeBody
SnakeElement last = snakeBody.get(i); //Gets the last element in snakeBody
last.x = penultimate.x; //Sets the x-coordinate for the last element = the x-coordinate for the penultimate element
last.y = penultimate.y; //Sets the y-coordinate for the last element = the y-coordinate for the penultimate element
}
this.snake.drawSnake(g);
this.apple.drawApple(g);
}
public void MoveSnake(){
this.snake.setX(this.snake.getX() + moveSnakeX); //If moveSnakeX = 1 or -1, the snake moves horizontally
this.snake.setY(this.snake.getY() + moveSnakeY); //If moveSnakeY = 1 or -1, the snake moves vertically
//If snake crashes into a wall, save score and show "Game over"-message
if(this.snake.getX() == 0 || this.snake.getX() == 600 || this.snake.getY() == 0 || this.snake.getY() == 600){
if(score > highscore){
highscore = score;
}
this.GameOver();
}
}
public void checkCollision(){
Rectangle r1 = new Rectangle(snake.getX(), snake.getY(), snake.getHeight(), snake.getWidth());
Rectangle r2 = new Rectangle(apple.getX(), apple.getY(), apple.getHeight(), apple.getWidth());
Random pos = new Random();
//If snake eats the apple, spawn a new apple and grow snake, reset the timer and add 5 points to your score
if(r1.intersects(r2)){
System.out.println("Snake got the apple!");
apple.setX(pos.nextInt(581 + 1 - 21) + 21); //Random x-coordinate within (20, 580)
apple.setY(pos.nextInt(581 + 1 - 21) + 21); //Random y-coordinate within (20, 580)
this.snake.setSize(this.snake.getSize() +15);
this.GrowSnake();
timer = 0;
score += 5;
}
}
//Adds a snake element at the end of the snake
public void GrowSnake(){
for(int x = 0; x < 15; x++) {
SnakeElement snakeButt = new SnakeElement(snakeBody.get(snakeBody.size() - 1).x, snakeBody.get(snakeBody.size() - 1).y);
this.snakeBody.add(snakeBody.size(), snakeButt);
}
}
//Show an option message when game is over
Object [] options = {"Start over", "Exit game"};
public void GameOver(){
int answer = JOptionPane.showOptionDialog(null,
"Snake died!" +
"\nScore: " + score +
"\nHighscore: " + highscore,
"Game over!",
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE,
null,
options,
options[0]);
//Reset variables if player wants to restart game
if(answer == 0){
this.snake.setX(100);
this.snake.setY(100);
this.snake.setSize(0);
moveSnakeX = 1;
moveSnakeY = 0;
this.drawSomething();
score = 0;
} else { //Exit game
System.exit(0);
}
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
this.drawSomething();
if(e.getKeyCode() == KeyEvent.VK_UP){
//If snake is NOT moving down, make snake move up. If snake is moving down, it's not allowed to move up
if(moveSnakeY != 1){
System.out.println("Up");
moveSnakeX = 0;
moveSnakeY = -1;
} else {
System.out.println("You cannot turn in the opposite direction!");
}
}
if(e.getKeyCode() == KeyEvent.VK_DOWN){
if(moveSnakeY != -1){
System.out.println("Down");
moveSnakeX = 0;
moveSnakeY = 1;
} else {
System.out.println("You cannot turn in the opposite direction!");
}
}
if(e.getKeyCode() == KeyEvent.VK_LEFT){
if(moveSnakeX != 1){
System.out.println("Left");
moveSnakeX = -1;
moveSnakeY = 0;
} else {
System.out.println("You cannot turn in the opposite direction!");
}
}
if(e.getKeyCode() == KeyEvent.VK_RIGHT){
if(moveSnakeX != -1){
System.out.println("Right");
moveSnakeX = 1;
moveSnakeY = 0;
} else {
System.out.println("You cannot turn in the opposite direction!");
}
}
}
@Override
public void keyReleased(KeyEvent e) {
}
@Override
public void actionPerformed(ActionEvent e) {
this.drawSomething();
}