在设计该游戏时,首先是做出一个主界面 即SnakeUI 类,在该类中要对主界面的修饰,蛇的初始化,食物的初始化,键盘的监听事件,

<>1,SnakeUI类
import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import
java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.event.KeyEvent;
import java.awt.event.KeyListener; import java.awt.image.BufferedImage; import
javax.swing.JFrame; import javax.swing.JOptionPane; public class SnakeUI
extends JFrame implements KeyListener { private BufferedImage uiImg = new
BufferedImage(Constant.JFRAME_WIDTH, Constant.JFRAME_HEIGHT,
BufferedImage.TYPE_3BYTE_BGR); private Rectangle rec; private SNode food;
private Snake snake; // 定义蛇对象 private static int SPEED = Constant.SNAKE_NORMAL;
public SnakeUI() { this.rec = Constant.rec; this.food = new SNode(Color.BLUE);
this.snake = new Snake(this);// 初始化蛇对象 this.launchFrame(); } // 获得当前界面的食物
public SNode getFood() { return food; } private void launchFrame() {
this.setTitle("贪吃蛇V0.1"); this.setBounds(200, 100, Constant.JFRAME_WIDTH,
Constant.JFRAME_HEIGHT); this.setVisible(true); this.setResizable(false);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); new Thread(new
UIUpdate()).start(); // 启动更新线程 this.addKeyListener(this); // 监听键盘事件 } public
void paint(Graphics g) { // 1.直接画入图形。g.drawRect画入闪烁效果[不可取] //
2.将图形画入到缓存图片,再讲图片画入到Frame中,避免闪烁效果 // 设置矩形的颜色,并绘入到uiImg图片,将此图片直接写入到内存 Graphics2D
g2d = (Graphics2D) uiImg.getGraphics(); // 在缓存图片画白色背景
g2d.setColor(Color.WHITE); g2d.fillRect(0, 0, this.getWidth(),
this.getHeight()); // 设置边框颜色 g2d.setColor(Color.BLACK); g2d.drawRect((int)
this.rec.getX(), (int) this.rec.getY(), (int) this.rec.getWidth(), (int)
this.rec.getHeight()); // 设置中间方格 g2d.setColor(Color.CYAN); int startx = (int)
this.rec.getX(); int starty = (int) this.rec.getY(); for (int i = 0; i < 35;
i++) { for (int j = 0; j < 50; j++) { g2d.drawRect(startx + j *
Constant.FOOD_WIDTH, starty + i * Constant.FOOD_HEIGHT, Constant.FOOD_WIDTH,
Constant.FOOD_HEIGHT); } } // 设置版本文字 g2d.setColor(Color.RED); g2d.setFont(new
Font("宋体", Font.ITALIC, 16));// 设置字体 g2d.drawString("版本文字 2019", 580, 530); //
画食物,食物paint方法在SNode类定义,在UI界面中的paint方法被调用 this.food.paint(g2d); // 画蛇
this.snake.paint(g2d); // 蛇吃食物绘制:蛇已经在吃食物,食物被吃完后重新定义一个食物对象,并与蛇的身体做重叠判断 if
(this.snake.eat(this.food)) { this.food = new SNode(Color.BLUE); while
(this.snake.hit(this.food)) { this.food = new SNode(Color.BLUE); } }
g.drawImage(uiImg, 0, 0, null); // 写入到内存 } public static void main(String[]
args) { new SnakeUI(); } @Override public void keyTyped(KeyEvent e) { // TODO
Auto-generated method stub } @Override // 按压键盘主要目的更改蛇运动方向 public void
keyPressed(KeyEvent e) { int key = e.getKeyCode(); switch (key) { case
KeyEvent.VK_LEFT: snake.setDir(Constant.L); System.out.println("dddl"); break;
case KeyEvent.VK_RIGHT: snake.setDir(Constant.R); System.out.println("dddr");
break; case KeyEvent.VK_UP: snake.setDir(Constant.U);
System.out.println("dddu"); break; case KeyEvent.VK_DOWN:
snake.setDir(Constant.D); break; case KeyEvent.VK_W: SPEED =
Constant.SNAKE_ADD; break; case KeyEvent.VK_D: SPEED = Constant.SNAKE_NORMAL;
break; case KeyEvent.VK_S: SPEED = Constant.SNAKE_SUB; break; case
KeyEvent.VK_T: SPEED = Constant.SNAKE_SUPER; break; } } @Override public void
keyReleased(KeyEvent e) { SPEED = Constant.SNAKE_NORMAL; } // 不断刷新界面的线程 class
UIUpdate implements Runnable { @Override public void run() { while
(SnakeUI.this.snake.isLive()) { System.out.println("..............thread....");
SnakeUI.this.repaint(); // 为了减缓更新的速度,设定每一次绘制之后停顿1秒。 try { Thread.sleep(SPEED);
} catch (InterruptedException e) { // TODO Auto-generated catch block
e.printStackTrace(); } } JOptionPane.showMessageDialog(SnakeUI.this, "游戏越界,game
over."); } } }
<>2,Snake 蛇类

实例化蛇这个类,使用的是一个list集合对蛇的各个部分进行存储以及显示,
import java.awt.Color; import java.awt.Graphics2D; import java.util.ArrayList;
import java.util.List; import javax.swing.JOptionPane; public class Snake {
private SNode snakeHead; // 蛇头结点 private int startx, starty; // 蛇头的坐标 private
List<SNode> nodes = new ArrayList<SNode>(); // 整条蛇,由SNode结点组成: // 线性表List
private int dir; // 方位 private boolean isLive = true; // 蛇处于运行状态
//给蛇添加运行速度,每一次运行走3个像素 private int speed = 3; // getter.setter蛇的方向 public int
getDir() { return dir; } public void setDir(int dir) { this.dir = dir; } //
传入蛇所在的界面,通过界面获得当前的食物对象 public Snake(SnakeUI ui) { this.dir = Constant.U;
this.noOverride(ui.getFood()); } // 随机产生蛇头的坐标与食物不重复 public void
noOverride(SNode food) { this.generateSnake(); while (this.hit(food)) { //
蛇与食物重叠 this.generateSnake(); } } private void generateSnake() { int x =
SNode.generate(50); // [0,49) int y = SNode.generate(35); if (x == 0) { x += 1;
} else if (x == 49) { x -= 1; } if (y == 0) { y += 1; } else if (y == 34) { y
-= 1; } this.startx = ((int) Constant.rec.getX() + x * Constant.FOOD_WIDTH);
this.starty = ((int) Constant.rec.getY() + y * Constant.FOOD_HEIGHT);
this.snakeHead = new SNode(this.startx, this.starty, Color.GREEN);
nodes.add(snakeHead); this.addNode(); // 默认是2个结点,需再添加1个结点 } //
判定蛇是否与食物是否重叠:true:重叠 ,false:不重叠 public boolean hit(SNode food) { boolean result
= false; for (SNode snode : nodes) { boolean res =
snode.getRec().intersects(food.getRec()); if (res) { result = true; break; } }
return result; } // 吃食物 public boolean eat(SNode food) { boolean result =
false; for (SNode snode : nodes) { boolean res =
snode.getRec().intersects(food.getRec()); if (res) { result = true; if
(nodes.size() >= 2) { // 1.初始相遇,2.在移动中相遇 this.addNode(); // 蛇的身体增长1 } break; }
} return result; } // 给蛇的尾部添加一个结点,与蛇方位有关 private void addNode() { int size =
nodes.size(); switch (dir) { case Constant.L: // 向左走,则右边添加第2个结点,且没有碰壁 if (size
== 1) { // 蛇静止,需要添加一个结点到蛇尾 int x = this.startx + Constant.FOOD_WIDTH; int y =
this.starty; SNode snode = new SNode(x, y, Color.GREEN); nodes.add(snode); //
添加到集合末尾 } else { int x = this.startx - Constant.FOOD_WIDTH; int y =
this.starty; SNode snode = new SNode(x, y, Color.GREEN); nodes.add(0, snode);
this.snakeHead = snode; this.startx = x; this.starty = y; // 判断蛇头左越界 if
(this.startx < Constant.rec.getX()) { this.isLive = false; } } break; case
Constant.R: if (size == 1) { // 蛇静止,需要添加一个结点到蛇尾 int x = this.startx -
Constant.FOOD_WIDTH; int y = this.starty; SNode snode = new SNode(x, y,
Color.GREEN); nodes.add(snode); // 添加到集合末尾 } else { int x = this.startx +
Constant.FOOD_WIDTH; int y = this.starty; SNode snode = new SNode(x, y,
Color.GREEN); nodes.add(0, snode); this.snakeHead = snode; this.startx = x;
this.starty = y; //判断蛇头右越界 if (this.startx > Constant.GAME_WIDTH) { this.isLive
= false; } } break; case Constant.U: if (size == 1) { // 蛇静止,需要添加一个结点到蛇尾 int x
= this.startx; int y = this.starty + Constant.FOOD_HEIGHT; SNode snode = new
SNode(x, y, Color.GREEN); nodes.add(snode); // 添加到集合末尾 } else { int x =
this.startx; int y = this.starty - Constant.FOOD_HEIGHT; SNode snode = new
SNode(x, y, Color.GREEN); nodes.add(0, snode); this.snakeHead = snode;
this.startx = x; this.starty = y; // 判断蛇头上越界 if (this.starty <
Constant.rec.getY()) { this.isLive = false; } } break; case Constant.D: if
(size == 1) { // 蛇静止,需要添加一个结点到蛇尾 int x = this.startx; int y = this.starty -
Constant.FOOD_HEIGHT; SNode snode = new SNode(x, y, Color.GREEN);
nodes.add(snode); // 添加到集合末尾 } else { int x = this.startx; int y = this.starty
+ Constant.FOOD_HEIGHT; // int y = this.starty + this.speed; SNode snode = new
SNode(x, y, Color.GREEN); nodes.add(0, snode); this.snakeHead = snode;
this.startx = x; this.starty = y; //判断蛇头下越界 if (this.starty >
((int)Constant.rec.getY()+ Constant.GAME_HEIGHT-Constant.FOOD_HEIGHT)) {
this.isLive = false; } } break; } } public boolean isLive() { return isLive; }
// 蛇的移动,不断变换蛇头,删除蛇尾 private void move() { this.addNode(); // 再添加一个新结点,删除末尾结点
int len = nodes.size(); nodes.remove(len - 1); } // 画蛇及蛇的移动 public void
paint(Graphics2D g2d) { // 对nodes结点依次绘制
g2d.setColor(this.snakeHead.getColor()); // 对蛇的身体进行绘制 for (SNode snode : nodes)
{ g2d.fillRect(snode.getX(), snode.getY(), Constant.FOOD_WIDTH,
Constant.FOOD_HEIGHT); } this.move(); } }
<>3,SNode食物类

设计食物类也可以说是对蛇类的一个简化
import java.awt.Color; import java.awt.Graphics2D; import java.awt.Rectangle;
//食物类的定义: public class SNode { private int x,y; //食物的起始坐标,与游戏的起始点关联 private
Color color; //食物的颜色 private Rectangle rec; //食物的矩形区域 public Color getColor() {
return color; } public int getX() { //读取数据 return x; } public void setX(int x)
{ this.x = x; } public int getY() { return y; } public void setY(int y) {
this.y = y; } public Rectangle getRec() { return rec; } public void
setRec(Rectangle rec) { this.rec = rec; } //随机产生某个位置的食物 public SNode(Color
color) { this.x =
(int)Constant.rec.getX()+this.generate(50)*Constant.FOOD_WIDTH; this.y =
(int)Constant.rec.getY()+this.generate(35)*Constant.FOOD_HEIGHT; this.rec = new
Rectangle(this.x, this.y, Constant.FOOD_WIDTH, Constant.FOOD_HEIGHT);
this.color = color; } //生成固定位置的结点,用于产生蛇头 public SNode(int x,int y,Color color)
{ this.x = x; this.y = y; this.color = color; this.rec = new Rectangle(this.x,
this.y, Constant.FOOD_WIDTH, Constant.FOOD_HEIGHT); } //随机产生数字 public static
int generate(int number) { //[0,numbder) int x = 0; x =
(int)(Math.random()*number); return x; } //定义画食物的方法:基于图形缓存画法Graphics2D public
void paint(Graphics2D g2d) { g2d.setColor(this.color); g2d.fillRect(this.x,
this.y, Constant.FOOD_WIDTH, Constant.FOOD_HEIGHT); } public static void
main(String[] args) { } }
<>4,Constant常量类

对需要使用到的常量保存下来,方便对整个界面的修改
import java.awt.Rectangle; public class Constant { public static final int
FOOD_WIDTH = 15; // 食物的宽度和高度 public static final int FOOD_HEIGHT = 15; public
static final int GAME_WIDTH = FOOD_WIDTH*50; public static final int
GAME_HEIGHT = FOOD_HEIGHT*35; public static final int JFRAME_WIDTH =
FOOD_WIDTH*52; public static final int JFRAME_HEIGHT = FOOD_HEIGHT*38+6; public
static final int L=1,R=2,U=3,D=4; public static final int SNAKE_NORMAL = 500;
public static final int SNAKE_ADD = 180; public static final int SNAKE_SUPER =
50; public static final int SNAKE_SUB = 850; //游戏方格区域 public static final
Rectangle rec = new Rectangle(FOOD_WIDTH, FOOD_HEIGHT*2+6, GAME_WIDTH,
GAME_HEIGHT); }

技术
©2019-2020 Toolsou All rights reserved,
数字滚动抽奖小程序VaR - 风险价值 - 蒙特卡罗法 - Python百度网盘偷偷更新,终于实现免费不限速了! Chrome OS,对程序员和Windows意味着什么?,互联网营销华为Mate 40 Pro+ 5G曝光:徕卡电影镜头、陶瓷机身Qt学习2——.pro文件和.h文件介绍python:将一个文件转换为二进制文件(binary)第十一届蓝桥杯C/C++ 大学 B 组大赛软件类省赛网站手机号码抓取方式蚂蚁集团香港IPO获得中国证监会批准