1.进行窗口的创建
package cn.sf.snakegame;
import javax.swing.*;
import javax.swing.JFrame;
import java.awt.*;
public class Main {
//游戏的入口
public static void main(String[] args){
//创建窗口对象,对象名window
JFrame window = new JFrame("贪吃蛇游戏:");
//设置窗口可见
window.setVisible(true);
//设置窗口的宽和高
window.setSize(690,710);
//设置窗口中显示
window.setLocationRelativeTo(null);
//设置默认关闭操作
window.setDefaultCloseOperation(3);
//创建面板对象
SnakePanel panel = new SnakePanel();
//窗口中添加面板
window.add(panel);
//键盘焦点
panel.requestFocus();
}
}
2.蛇面板
package cn.sf.snakegame;
import javafx.event.ActionEvent;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.IOException;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
/**
* 这是蛇面板类
*/
public class SnakePanel extends JPanel {
//声明食物
Cell food;
//声明蛇数组
Cell[] snake;
//声明格子
Cell chessboard;
//声明障碍物
Cell barrier;
//默认向右移动
private Direction direction = Direction.RIGHT;
//定时器,在规定时间内调用蛇移动的方法
private Timer timer;
//默认蛇是活着的
private boolean isliving=true;
//分数
public static int score = 0;
//图片素材
private Image bodyImage;
private Image foodImage;
private Image downImage;
private Image upImage;
private Image rightImage;
private Image leftImage;
private Image background;
private Image barrierImage;
//暂停
private boolean isPaused = false; // 游戏是否暂停的标志
/**
* 构造方法:专门给属性赋初始值
* 在本游戏中,用构造方法给食物和蛇赋初始坐标值
* 语法:构造方法与类名一致
* 类名(){
* 赋值过程
* }
*/
SnakePanel() {
//创建格子对象,赋值给food
food = new Cell();
//创建随机数对象
Random ran = new Random();
//给食物的x和y赋值
food.x = ran.nextInt(32) * 15;
food.y = ran.nextInt(32) * 15;
//创建初始的蛇
snake = new Cell[3];
int snakeLength = snake.length;
for (int i = 0; i < snakeLength; i++) {
snake[i] = new Cell();
snake[i].x = 270 - i * 15;
snake[i].y = 270;
}
//创建障碍物
barrier = new Cell();
barrier.x = ran.nextInt(32)*15;
barrier.y = ran.nextInt(32)*15;
//初始化定时器
initTimer();
//设置建盘焦点
this.setFocusable(true);
//设置建盘监听,让蛇随着上下左右方向移动
setKeyListener();
//绑定空格键的监听器
getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "togglePause");
getActionMap().put("togglePause", new AbstractAction() {
@Override
public void actionPerformed(java.awt.event.ActionEvent e) {
}
});
//图片素材
try {
bodyImage = ImageIO.read(getClass().getResourceAsStream("body.png"));
foodImage = ImageIO.read(getClass().getResourceAsStream("food.png"));
downImage = ImageIO.read(getClass().getResourceAsStream("down.png"));
upImage = ImageIO.read(getClass().getResourceAsStream("up.png"));
leftImage = ImageIO.read(getClass().getResourceAsStream("left.png"));
rightImage = ImageIO.read(getClass().getResourceAsStream("right.png"));
background = ImageIO.read(getClass().getResourceAsStream("background.png"));
barrierImage = ImageIO.read((getClass().getResourceAsStream("barrier.png")));
} catch (IOException ex) {
ex.printStackTrace();
}
}
private void initTimer() {
if (isPaused) {
return;
}
timer = new Timer();
//初始化定时任务
TimerTask timerTask = new TimerTask() {
@Override
public void run() {
move();
repaint();
}
};
//定时器间隔
if(snake.length>=3&&snake.length<=5) {
timer.scheduleAtFixedRate(timerTask, 0, 200);
}else if(snake.length>5&&snake.length<=10){
timer.scheduleAtFixedRate(timerTask,100,200);
}else {
timer.scheduleAtFixedRate(timerTask,50,100);
}
}
//设置建盘监听
private void setKeyListener(){
addKeyListener(new KeyAdapter() {
//当建盘按下时,会自动调用此方法
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_SPACE) {
isPaused = !isPaused;
} else {
switch (e.getKeyCode()){
case KeyEvent.VK_UP://向上
if (direction != Direction.DOWN) {
direction = Direction.UP;
}
break;
case KeyEvent.VK_DOWN:
if (direction != Direction.UP) {
direction = Direction.DOWN;
}
break;
case KeyEvent.VK_LEFT:
if (direction != Direction.RIGHT) {
direction = Direction.LEFT;
}
break;
case KeyEvent.VK_RIGHT:
if (direction != Direction.LEFT) {
direction = Direction.RIGHT;
}
break;
}
}
}
});
}
//蛇会沿着蛇头的方向移动
//控制蛇的移动,在蛇头的方向添加一个节点,然后将蛇尾的节点删除
public void move() {
if (isPaused) {
return;
}
if (isliving) {
//获取蛇头
Cell head = new Cell();
head.x = snake[0].x;
head.y = snake[0].y;
switch (direction) {
//在蛇头的上边添加一个节点
case UP:
head.y -= 15;
break;
case DOWN:
head.y += 15;
break;
case RIGHT:
head.x += 15;
break;
case LEFT:
head.x -= 15;
break;
}
//移动蛇的身.除了蛇头
for (int i = snake.length - 1; i > 0; i--) {
snake[i].x = snake[i - 1].x;
snake[i].y = snake[i - 1].y;
}
//更新蛇头位置
snake[0] = head;
}
//判断蛇是否撞墙
Cell head = new Cell();
head.x = snake[0].x;
head.y = snake[0].y;
if (head.x < 0 || head.y < 0 || head.x > 465 || head.y > 465) {
isliving = false;
}
//判断蛇是否碰到自己的身体
for (int i = 1; i < snake.length; i++) {
if (head.x == snake[i].x && head.y == snake[i].y) {
isliving = false;
}
}
//判断食物是否和食物重合
if(head.x==food.x&&head.y==food.y){
//更新食物的位置
Random ran = new Random();
food.x = ran.nextInt(32) * 15;
food.y = ran.nextInt(32) * 15;
barrier = new Cell();
barrier.x = ran.nextInt(32) * 15;
barrier.y = ran.nextInt(32) * 15;
//在蛇的尾部添加一个新的节点
Cell[] newSnake = new Cell[snake.length + 1];
for (int i = 0; i < snake.length; i++) {
newSnake[i] = snake[i];
}
newSnake[snake.length] = new Cell();
newSnake[snake.length].x = snake[snake.length - 1].x;
newSnake[snake.length].y = snake[snake.length - 1].y;
snake = newSnake;
score++;
}
//判断障碍物是否和蛇头重合,重合就死
if (head.x == barrier.x && head.y == barrier.y) {
Random ran = new Random();
isliving = false;
}
}
/**
* paint方法:专门画画的方法
*
* @param g:画笔
*/
public void paint(Graphics g) {
//清空面板
g.clearRect(0,0,getWidth(),getHeight());
//背景
g.drawImage(background,0,0,getWidth(),getHeight(),null);
//使用画笔画出游戏范围,坐标(0,0),宽 高 480
g.drawRect(0, 0, 480, 480);
//画障碍物
g.drawImage(barrierImage,barrier.x,barrier.y,barrier.width,barrier.height,null);
//画食物
g.drawImage(foodImage,food.x,food.y,food.width,food.height,null);
//画蛇
int snakeLength = snake.length;
for (int i = 0; i < snakeLength; i++) {
g.drawImage(bodyImage,snake[i].x,snake[i].y,snake[i].width,snake[i].height,null);
}
switch (direction) {
case UP:
g.drawImage(upImage, snake[0].x, snake[0].y, snake[0].width, snake[0].height, null);
break;
case DOWN:
g.drawImage(downImage, snake[0].x, snake[0].y, snake[0].width, snake[0].height, null);
break;
case LEFT:
g.drawImage(leftImage, snake[0].x, snake[0].y, snake[0].width, snake[0].height, null);
break;
case RIGHT:
g.drawImage(rightImage, snake[0].x, snake[0].y, snake[0].width, snake[0].height, null);
break;
}
//格子
for (int i = 0; i < 33; i++) {
g.drawLine(0, i * 15, 480, i * 15);
g.drawLine(i * 15, 0, i * 15, 480);
}
//分数
g.setColor(Color.gray);
g.drawRect(490,10,170,100);
g.setColor(Color.gray);
g.setFont(new Font("宋体", Font.BOLD, 25));
g.drawString("分数:"+score,500,100);
g.drawString("蛇的长度:"+snakeLength,500,50);
// 判断蛇是否死亡
if (!isliving) {
// 停止定时器
timer.cancel();
// 使用画笔绘制 "Game over"
g.setColor(Color.red);
g.setFont(new Font("Arial", Font.BOLD, 40));
g.drawString("Game Over", getWidth() / 2 - 200, getHeight()/2-70);
}
if (isPaused) {
g.setColor(Color.gray);
g.setFont(new Font("Arial", Font.BOLD, 40));
g.drawString("PAUSED", getWidth() / 2 - 200, getHeight() / 2-70);
}
}
}
3.枚举Direction
package cn.sf.snakegame;
/**
* 枚举:就是用几个固定的单词表示一些常量
*/
public enum Direction {
UP,DOWN,LEFT,RIGHT;
}
4.格子
package cn.sf.snakegame;
/**
* 格子:用于创建食物和蛇
*/
public class Cell {
//格子的宽
int width=15;
//格子的高
int height=15;
//格子的x坐标
int x;
//格子的y坐标
int y;
}