规则:
使用方向键盘控制蛇头,如果与原来方向相同或相反, 则无法改变。
按空格可以再pause和continue之间切换。
玩一次就得运行一次。
文件结构:
运行截图:
速度可以调:
可以在githu边上下载
github传送门
完整代码:
SnakeGame.java
package snake_1_1;
import java.awt.EventQueue;
import javax.swing.JFrame;
/**
*
* @version 1.1 2019-5-11
*
*/
public class SnakeGame
{
public static void main(String[] args)
{
EventQueue.invokeLater(()->
{
SnakeFrame frame = new SnakeFrame();
frame.setTitle("贪吃蛇");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
});
}
}
Node.java
package snake_1_1;
class Node
{
public static final int W = 20;
public static final int H = 20;
int x;
int y;
public Node(int x, int y)
{
this.x = x;
this.y = y;
}
}
Snake.java
package snake_1_1;
import java.util.ArrayList;
class Snake
{
boolean isRun; //是否在运动
ArrayList<Node> body; //蛇体
Node food; //食物
int derection; //方向
int score; // 分数
int status; // 状态
int speed; // 速度
public static final int SLOW = 500;
public static final int MID = 300;
public static final int FAST = 100;
public static final int RUNNING = 1;
public static final int PAUSED = 2;
public static final int GAMEOVER = 3;
public static final int LEFT = 1;
public static final int UP = 2;
public static final int RIGHT = 3;
public static final int DOWN = 4;
public Snake()
{
speed = Snake.SLOW;
score = 0;
isRun = false;
status = Snake.PAUSED;
derection = Snake.RIGHT;
body = new ArrayList<Node>();
body.add(new Node(60,20));
body.add(new Node(40,20));
body.add(new Node(20,20));
makeFood();
}
//判断食物是否被蛇吃掉
//如果食物在蛇运行方向的正前方, 并且 与蛇头接触 ,则被吃掉
private boolean isEaten()
{
Node head = body.get(0);
if (derection == Snake.RIGHT && (head.x + Node.W) == food.x
&& head.y == food.y)
return true;
else if(derection == Snake.LEFT && (head.x - Node.W) == food.x
&& head.y == food.y)
return true;
else if(derection == Snake.UP && (head.y - Node.H) == food.y
&& head.x == food.x)
return true;
else if(derection == Snake.DOWN && (head.y + Node.H) == food.y
&& head.x == food.x)
return true;
else
return false;
}
//是否碰撞
public boolean isCollsion()
{
Node head = body.get(0);
//碰壁
if(derection == Snake.RIGHT && head.x == 280)
return true;
else if(derection == Snake.UP && head.y == 0)
return true;
else if(derection == Snake.LEFT && head.x == 0)
return true;
else if(derection == Snake.DOWN && head.y == 380)
return true;
//蛇头碰到身体
Node temp = null;
int i;
for(i =3; i < body.size(); i++)
{
temp = body.get(i);
if (temp.x == head.x && temp.y == head.y)
return true;
}
if(i < body.size())
return true;
return false;
}
//在随机的地方产生食物
public void makeFood()
{
boolean isInBody = true;
int ax = 0, ay = 0;
int X = 0, Y = 0;
while(isInBody)
{
isInBody = false;
ax = (int)(Math.random() * 15);
ay = (int)(Math.random() * 20);
X = ax*Node.W;
Y = ax*Node.H;
for(Node temp :body)
{
if(X== temp.x && Y == temp.y)
isInBody = true;
}
}
food = new Node( X, Y);
}
//改变运行方向
public void changeDerection(int newDer)
{
if(derection % 2 != newDer % 2) //如果与原来方向相同或相反, 则无法改变
{
derection = newDer;
}
}
public void move()
{
if(isEaten()) // 如果食物被吃掉
{
body.add(0,food); // 把食物当成蛇头成为新的蛇体
score += 10;
makeFood();
}
else if(isCollsion())
{
isRun = false;
status = Snake.GAMEOVER; //结束
}
else if(isRun) //正常运行 (不吃食物,不碰壁, 不碰到蛇身)
{
Node head = body.get(0);
int X = head.x;
int Y = head.y;
switch(derection)
{
case RIGHT:
X += Node.W;
break;
case LEFT:
X -= Node.W;
break;
case UP:
Y -= Node.H;
break;
case DOWN:
Y += Node.H;
break;
}
body.add(0,new Node(X,Y));
body.remove(body.size()-1); //去掉蛇尾
}
}
}
StatusRunnable.java
package snake_1_1;
import javax.swing.JLabel;
//记录状态的线程
class StatusRunnable implements Runnable
{
private JLabel statusLabel;
private JLabel scoreLabel;
private Snake snake;
public StatusRunnable(Snake snake, JLabel statusLabel, JLabel scoreLabel)
{
this.statusLabel = statusLabel;
this.scoreLabel = scoreLabel;
this.snake = snake;
}
public void run()
{
String sta = "";
String spe = "";
while(true)
{
switch(snake.status)
{
case Snake.RUNNING:
sta = "running";
break;
case Snake.PAUSED:
sta = "Paused";
break;
case Snake.GAMEOVER:
sta = "GameOver";
break;
}
statusLabel.setText(sta);
scoreLabel.setText("" + snake.score);
try {
Thread.sleep(100);
}catch(Exception e) {}
}
}
}
SnakeRunnable.java
package snake_1_1;
import javax.swing.JComponent;
//蛇运动以及记录分数的线程
class SnakeRunnable implements Runnable
{
private Snake snake;
private JComponent component;
int i = 0;
public SnakeRunnable(Snake snake, JComponent component)
{
this.snake = snake;
this.component = component;
}
public void run()
{
while(true)
{
try {
snake.move();
component.repaint();
Thread.sleep(snake.speed);
}catch(Exception e) {}
}
}
}
SnakePanel.java
package snake_1_1;
import javax.swing.JPanel;
import java.awt.Graphics;
import java.awt.Color;
//画板,蛇活动的地方
public class SnakePanel extends JPanel
{
Snake snake;
public SnakePanel(Snake snake)
{
this.snake = snake;
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
for(Node node : snake.body)
{
g.setColor(Color.BLACK);
g.fillRect(node.x, node.y, Node.W,Node.H);
}
Node food = snake.food;
g.setColor(Color.RED);
g.fillRect(food.x,food.y,Node.W, Node.H);
}
}
SnakeFrame.java
package snake_1_1;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
public class SnakeFrame extends JFrame
{
private JLabel statusLabel;
private JLabel speedLabel;
private JLabel scoreLabel;
private JPanel snakePanel;
private Snake snake;
private JMenuBar bar; //菜单栏
private JMenu gameMenu;
private JMenu helpMenu;
private JMenu speedMenu;
private JMenuItem newItem;
private JMenuItem pauseItem;
private JMenuItem beginItem;
private JMenuItem aboutItem; //没用上
private JMenuItem slowItem;
private JMenuItem midItem;
private JMenuItem fastItem;
public SnakeFrame()
{
init();
ActionListener actionListener = event ->
{
if(event.getSource() == pauseItem)
snake.isRun = false;
else if(event.getSource() == beginItem)
snake.isRun = true;
else if(event.getSource() == newItem)
newGame();
//菜单控制运行速度
else if(event.getSource() == slowItem)
{
snake.speed = Snake.SLOW;
speedLabel.setText("slow");
}
else if(event.getSource() == midItem)
{
snake.speed = Snake.MID;
speedLabel.setText("mid");
}
else if(event.getSource() == fastItem)
{
snake.speed = Snake.FAST;
speedLabel.setText("fast");
}
};
pauseItem.addActionListener(actionListener);
beginItem.addActionListener(actionListener);
newItem.addActionListener(actionListener);
slowItem.addActionListener(actionListener);
midItem.addActionListener(actionListener);
fastItem.addActionListener(actionListener);
aboutItem.addActionListener(actionListener);
addKeyListener(new KeyAdapter()
{
public void keyPressed(KeyEvent event)
{
switch(event.getKeyCode())
{
//方向键改变蛇运行的方向
case KeyEvent.VK_DOWN:
snake.changeDerection(Snake.DOWN);
break;
case KeyEvent.VK_UP:
snake.changeDerection(Snake.UP);
break;
case KeyEvent.VK_LEFT:
snake.changeDerection(Snake.LEFT);
break;
case KeyEvent.VK_RIGHT:
snake.changeDerection(Snake.RIGHT);
break;
case KeyEvent.VK_SPACE:
if(snake.isRun == true)
{
snake.isRun = false;
snake.status = Snake.PAUSED;
break;
}
else
{
snake.isRun = true;
snake.status = Snake.RUNNING;
break;
}
}
}
});
}
private void init()
{
snake = new Snake();
setSize(380,460);
setLayout(null); //清空布局管理器
this.setResizable(false);
bar = new JMenuBar();
gameMenu = new JMenu("Game");
gameMenu.add((newItem = new JMenuItem("New Game")));
gameMenu.add((pauseItem = new JMenuItem("Pause")));
gameMenu.add((beginItem = new JMenuItem("continue")));
helpMenu = new JMenu("help");
helpMenu.add((aboutItem = new JMenuItem("about")));
speedMenu = new JMenu("speed");
speedMenu.add(( slowItem = new JMenuItem("slow")));
speedMenu.add(( midItem = new JMenuItem("mid")));
speedMenu.add(( fastItem = new JMenuItem("fast")));
bar.add(gameMenu);
bar.add(helpMenu);
bar.add(speedMenu);
setJMenuBar(bar);
statusLabel = new JLabel();
speedLabel = new JLabel();
scoreLabel = new JLabel();
snakePanel = new JPanel();
snakePanel.setBounds(0, 0, 300, 400); // 从左上角(0,0)开始 ,大小 300 * 400
snakePanel.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY));
add(snakePanel);
statusLabel.setBounds(310,25,60,20);
add(statusLabel);
speedLabel.setBounds(310, 75, 60, 20);
add(speedLabel);
scoreLabel.setBounds(310, 125, 60, 20);
add(scoreLabel);
JLabel temp = new JLabel("状态");
temp.setBounds(310, 5, 60, 20);
add(temp);
temp = new JLabel("速度");
temp.setBounds(310,55,60,20);
add(temp);
temp = new JLabel("分数");
temp.setBounds(310, 105, 60, 20);
add(temp);
}
private void newGame()
{
this.remove(snakePanel);
this.remove(statusLabel);
this.remove(scoreLabel);
speedLabel.setText("slow");
statusLabel = new JLabel();
scoreLabel = new JLabel();
snakePanel = new SnakePanel(snake);
snakePanel.setBounds(0,0,300,400);
snakePanel.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY)); //加个边框
Runnable r1 = new SnakeRunnable(snake,snakePanel);
Runnable r2 = new StatusRunnable(snake,statusLabel,scoreLabel);
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
t2.start();
add(snakePanel);
statusLabel.setBounds(310,25,60,20);
add(statusLabel);
scoreLabel.setBounds(310,125,60,20);
add(scoreLabel);
}
}