我尝试过不同的方法为这个蛇游戏制作两个背景,一个是黑色的菜单,另一个是白色的游戏。我找到的最佳解决方案是使用setBackground。但是当我运行游戏时,Thread.sleep搞砸了,现在蛇速度非常快。为了尝试解决这个问题,我将多个值放入Thread.sleep中,但无论值如何,蛇都以相同的速度行进。
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.lang.Thread;
import java.util.Random;
public class Snake extends JPanel implements KeyListener, MouseListener{
public boolean right = false;
public boolean left = false;
public boolean up = false;
public boolean down = false;
public int snakex[] = new int[10000000];
public int snakey[] = new int[10000000];
public int snakeLength = 0;
public int applex;
public int appley;
public int buttonX = 150;
public int buttonY = 125;
public boolean appleEaten = true;
public static boolean reset = false;
public static boolean ingame = false;
public static boolean menu = true;
public static int speed = 200;
public void forLogic(){
for(int i = snakeLength; i > 1; i--){
if(snakeLength > 4 && snakex[0] == snakex[i] && snakey[0] == snakey[i]){
System.out.println("You Loose \n Your Score was: " + snakeLength);
ingame = false;
}
}
Movement();
if(snakex[0] >= 30*20){
snakex[0] = 0;
}
if(snakex[0] < 0){
snakex[0] = 29*20;
}
if(snakey[0] >= 25*20){
snakey[0] = 0;
}
if(snakey[0] < 0){
snakey[0] = 24*20;
}
if(snakex[0] == applex*20 && snakey[0] == appley*20) {
appleEaten = true;
snakeLength++;
//System.out.println(snakeLength);
}
if(appleEaten){
appleLocation();
appleEaten = false;
}
}
public void appleLocation(){
boolean goodToGo = false;
Random rand = new Random();
while(!goodToGo){
applex = rand.nextInt(30);
appley = rand.nextInt(25);
boolean checker = false;
for(int i = snakeLength; i > 0; i--) {
if (applex == snakex[i]||appley == snakey[i]) {
checker = true;
}
}
if(!checker){goodToGo = true;}
}
}
public void Movement(){
if(reset){
left = false;
right = false;
up = false;
down = false;
snakex[0] = 0;
snakey[0] = 0;
snakeLength = 1;
appleLocation();
reset = false;
}
if(right){
snakex[0] += 20;
}
if(left){
snakex[0] -= 20;
}
if(up){
snakey[0] -= 20;
}
if(down){
snakey[0] += 20;
}
}
public void mouseEntered(MouseEvent e){}
public void mouseExited(MouseEvent e){}
public void mousePressed(MouseEvent e){
int mouseX = e.getX();
int mouseY = e.getY();
if(mouseX > buttonX && mouseX < buttonX + 300 && mouseY > buttonY && mouseY < buttonY + 75){
ingame = true;
}
}
public void mouseReleased(MouseEvent e){}
public void mouseClicked(MouseEvent e){}
public void keyTyped(KeyEvent e) {}
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if(key == 39 && !left) {
right = true;
up = false;
down = false;
}
if(key == 37 && !right){
left = true;
up = false;
down = false;
}
if(key == 38 && !down){
up = true;
left = false;
right = false;
}
if(key == 40 && !up){
down = true;
left = false;
right = false;
}
if(key == 82){
reset = true;
}
}
public void keyReleased(KeyEvent e) {}
@SuppressWarnings("serial")
public void paint(Graphics g) {
super.paintComponent(g);
if(menu){
setBackground(Color.BLACK);
g.setColor(Color.green);
g.setFont(new Font("Courier New", Font.BOLD, 50));
g.drawString("Snake Game", 150, 50);
g.drawRect(buttonX, buttonY, 300, 75);
g.setFont(new Font("Courier New", Font.BOLD, 40));
g.drawString("PLAY", 250, 175);
}
if(ingame) {
setBackground(Color.WHITE);
int x = 0;
int y = 0;
for (x = 0; x < 30; x++) {
for (y = 0; y < 25; y++) {
g.setColor(Color.black);
g.fillRect(x * 20, y * 20, 19, 19);
}
}
g.setColor(Color.red);
g.fillOval(applex * 20, appley * 20, 19, 19);
forLogic();
g.setColor(Color.green);
for (int i = snakeLength; i > 0; i--) {
snakex[i] = snakex[(i - 1)];
snakey[i] = snakey[(i - 1)];
g.fillRect(snakex[i], snakey[i], 19, 19);
}
}
}
public static void main(String[] args) throws InterruptedException {
JFrame jframe = new JFrame("Snake Game");
Snake snake = new Snake();
jframe.add(snake);
snake.addMouseListener(snake);
snake.addKeyListener(snake);
jframe.setSize(615, 540);
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe.setFocusable(true);
jframe.setVisible(true);
snake.requestFocusInWindow();
jframe.setLocationRelativeTo(null);
while(true) {
if (!menu) {
ingame = true;
}
if (menu == ingame) {
ingame = false;
}
if (menu) {
snake.repaint();
}
if (ingame) {
while (true) {
Thread.sleep(200);
snake.repaint();
}
}
}
}
}
答案 0 :(得分:3)
我很抱歉直言不讳,但这段代码存在很多问题,很难知道从哪里开始。
setBackground(...)
,这可能会触发重绘,这通常不会成为问题...... while (true)
次循环和Thread.sleep(...)
次调用,如果Swing代码已启动(应该已完成),则代码可能会完全冻结您的GUI Swing事件线程。Thread.sleep(...)
个电话和while (true)
个圈。repaint();
。paintComponent
方法setBackground(...)
一次。
在绘画方法中拥有游戏逻辑。这表明使用第一原理重写是非常有益的:为游戏循环使用Swing Timer,在Swing代码中不使用其他延迟代码,覆盖paintComponent并在覆盖中调用相同的super方法,将绘画与逻辑分离GridPoint
网格上每个点的x和y位置ArrayList<GridPoint>
,其中包含蛇上点的 逻辑 位置。答案 1 :(得分:2)
public void paint(Graphics g) {
super.paintComponent(g);
不要覆盖paint()。自定义绘画是通过覆盖paintComponent()
来完成的。然后你仍然会调用super.paintComponent(g);
if(key == 39 && !left) {
不要使用魔术数字。 API将有变量供您使用。我猜你想要KeyEvent.VK_LEFT。
if(key == 82){
但我不知道这个神奇的数字是什么。
if(ingame) {
setBackground(Color.WHITE);
不要在绘画方法中更改组件的属性。绘画方法仅用于绘画。
也许你需要像setPlayingGame(Boolean)这样的方法。然后,如果为true,则设置玩游戏的属性。如果为false,则设置菜单属性。
或者更好的是你有两个面板。一个用于菜单,一个用于游戏。然后使用CardLayout并交换面板,具体取决于您是否要绘制菜单或游戏。
你有太多的游戏逻辑来调试可能是你的问题。
答案 2 :(得分:0)
蛇移动速度太快,因为“移动”蛇的方法太频繁了。你每200毫秒重新绘制一次,但程序的逻辑没有睡眠。你的Thread.sleep应该在程序的逻辑部分:
public void forLogic(){
for(int i = snakeLength; i > 1; i--){
if(snakeLength > 4 && snakex[0] == snakex[i] && snakey[0] == snakey[i]){
System.out.println("You Loose \n Your Score was: " + snakeLength);
ingame = false;
}
}
Movement();
if(snakex[0] >= 30*20){
snakex[0] = 0;
}
if(snakex[0] < 0){
snakex[0] = 29*20;
}
if(snakey[0] >= 25*20){
snakey[0] = 0;
}
if(snakey[0] < 0){
snakey[0] = 24*20;
}
if(snakex[0] == applex*20 && snakey[0] == appley*20) {
appleEaten = true;
snakeLength++;
//System.out.println(snakeLength);
}
if(appleEaten){
appleLocation();
appleEaten = false;
}
try {
Thread.sleep(speed);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}