效果预览
项目架构
一、草地类
Grass.java
package beans;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
/**
* Created by IntelliJ IDEA.
* Author: Rich
* Date: 2021/7/29 21:41
* Description: 草地类
*/
public class Grass extends Frame {
public static final int ROWS=50;//草地行数
public static final int COLS=50;//草地列数
public static final int BOX_SIZE=15;//每个小格的大小
private static final Color GRASS_COLOR=Color.BLACK;//草地的颜色
private int score=0;//初始分数
private boolean isOver=false;
private PaintThread paintThread=new PaintThread();
private Snake snake=new Snake(this);
private Food food=new Food();
/**
* 运行草地
*/
public void execute(){
setSize(COLS*BOX_SIZE,ROWS*BOX_SIZE);
setLocation(200,200);
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
setVisible(false);
System.exit(0);
}
});
addKeyListener(new MyKeyListener());
setVisible(true);
new Thread(paintThread).start();
}
/**
* 画出草地
* @param g
*/
@Override
public void paint(Graphics g) {
Color color = g.getColor();
g.setColor(GRASS_COLOR);
g.fillRect(0,0,COLS*BOX_SIZE,ROWS*BOX_SIZE);
//画出横线
g.setColor(Color.black);
for(int i=1;i<ROWS;i++){
g.drawLine(0,i*BOX_SIZE,COLS*BOX_SIZE,i*BOX_SIZE);
}
for(int i=1;i<COLS;i++){
g.drawLine(i*BOX_SIZE,0,BOX_SIZE*i,ROWS*BOX_SIZE);
}
//画蛇
snake.drawSnake(g);
//画苹果
food.drawApple(g);
//吃苹果
snake.eatFood(food);
//分值
g.setColor(Color.white);
g.drawString("当前分数:"+score+" 分",30,60);
if(isOver){
g.setFont(new Font("宋体",Font.BOLD,30));
g.setColor(Color.YELLOW);
g.drawString("游戏结束 ! \n 按F2重玩",200,300);
}
g.setColor(color);
}
/**游戏结束*/
public void stop(){
isOver=true;
paintThread.setOff();
}
/**
* 重画草地的线程
*/
private class PaintThread implements Runnable{
private boolean flag=true;
@Override
public void run() {
try {
while (flag){
Thread.sleep(100);
repaint();
}
}catch (Exception e){
System.out.println("【重画线程异常】");
e.printStackTrace();
}
}
public void setOff(){
this.flag=false;
}
public void setOn(){
this.flag=true;
}
}
/**
* 键盘事件
*/
private class MyKeyListener extends KeyAdapter {
@Override
public void keyPressed(KeyEvent e) {
snake.changeSnake(e);
if(isOver){
if(KeyEvent.VK_F2==e.getKeyCode())
restart();
}
}
}
/**
* 重新开始
*/
private void restart() {
isOver=false;
snake=new Snake(this);
paintThread.setOn();
new Thread(paintThread).start();
}
/**
* 双缓冲技术
*/
Image offScreenImage = null;
public void update(Graphics g) {
if(offScreenImage == null) {
offScreenImage = this.createImage(COLS*BOX_SIZE,ROWS*BOX_SIZE);
}
Graphics gOffScreen = offScreenImage.getGraphics();
Color c = gOffScreen.getColor();
gOffScreen.setColor(Color.GREEN);
gOffScreen.fillRect(0, 0,COLS*BOX_SIZE,ROWS*BOX_SIZE);
gOffScreen.setColor(c);
paint(gOffScreen);
g.drawImage(offScreenImage, 0, 0, null);
}
public int getScore(){
return score;
}
public void setScore(int score){
this.score=score;
}
public static void main(String[] args){
new Grass().execute();
}
}
二、食物类
Food.java
package beans;
import java.awt.*;
import java.util.Random;
/**
* Created by IntelliJ IDEA.
* Author: Rich
* Date: 2021/7/29 21:37
* Description: 贪吃蛇的食物
*/
public class Food {
private static Color FOOD_COLOR = Color.RED;//食物的颜色
private int rows,cols;//出现的位置
private int w=Grass.BOX_SIZE;
private int h=Grass.BOX_SIZE;
private Random random = new Random();
public Food(){
this.rows = random.nextInt(Grass.ROWS-5)+5;
this.cols=random.nextInt(Grass.COLS-5)+5;
}
/**
* 画苹果
* @param g
*/
public void drawApple(Graphics g){
Color color = g.getColor();
g.setColor(FOOD_COLOR);
g.fillOval(rows*Grass.BOX_SIZE,cols*Grass.BOX_SIZE,w,h);
g.setColor(color);
}
/**
* 获取碰撞检测点
* @return
*/
public Rectangle getRectangle(){
return new Rectangle(rows*Grass.BOX_SIZE,cols*Grass.BOX_SIZE,w,h);
}
/**
* 更新食物的位置
*/
public void updateAppleLocation(){
this.rows=random.nextInt(Grass.ROWS-5)+5;
this.cols=random.nextInt(Grass.COLS-5)+5;
}
}
三、贪吃蛇
Snake.java
package beans;
import enums.Direction;
import test.Node;
import java.awt.*;
import java.awt.event.KeyEvent;
/**
* Created by IntelliJ IDEA.
* Author: Rich
* Date: 2021/7/29 21:43
* Description: 蛇类
*/
public class Snake {
private Node head=null;//蛇头
private Node tail=null;//蛇尾
private int size;//蛇长
private Grass grass;
private static Color SNAKE_COLOR=Color.GREEN;//小蛇的颜色
/*初始为一节节点**/
private Node node=new Node(15,5,Direction.UP);
public Snake(Node node){
head=node;
tail=node;
size=0;
}
public Snake(Grass grass){
head=this.node;
tail=this.node;
size=1;
this.grass=grass;
}
/*向蛇尾添加一节**/
public void addToTail(){
Node node=null;
switch (tail.direction){
case UP:
node=new Node(tail.rows-1,tail.cols,tail.direction);
break;
case DOWN:
node=new Node(tail.rows-1,tail.cols,tail.direction);
break;
case LEFT:
node=new Node(tail.rows,tail.cols+1,tail.direction);
break;
case RIGHT:
node=new Node(tail.rows,tail.cols-1,tail.direction);
break;
}
tail.next=node;
node.pre=tail;
tail=node;
size++;
}
/*向蛇头添加一节**/
public void addToHead(){
Node node=null;
switch (head.direction){
case UP:
node=new Node(head.rows-1,head.cols,head.direction);
break;
case DOWN:
node=new Node(head.rows+1,head.cols,head.direction);
break;
case LEFT:
node=new Node(head.rows,head.cols-1,head.direction);
break;
case RIGHT:
node=new Node(head.rows,head.cols+1,head.direction);
break;
}
node.next=head;
head.pre=node;
head=node;
size++;
}
/*画蛇*/
public void drawSnake(Graphics g){
Color color = g.getColor();
for(Node h=head;h!=null;h=h.next){
h.drawNode(g);
}
g.setColor(color);
move();
checkIsDeath();
}
/*判断蛇是否死亡*/
private void checkIsDeath() {
if(head.rows<0||head.rows>Grass.ROWS||head.cols<0||head.cols>Grass.COLS){
grass.stop();
}
for(Node h=head.next;h!=null;h=h.next){
if(head.rows==h.rows&&head.cols==h.cols){
grass.stop();
}
}
}
/**蛇移动:掐头去尾*/
private void move() {
addToHead();
cutTail();
}
/**剪出尾巴*/
private void cutTail() {
if(size==0)return ;
tail=tail.pre;
tail.next=null;
}
/*蛇改变方向**/
public void changeSnake(KeyEvent e) {
int keyCode = e.getKeyCode();
switch (keyCode){
case KeyEvent.VK_UP:
if(head.direction!=Direction.DOWN)
head.direction=Direction.UP;
break;
case KeyEvent.VK_DOWN:
if(head.direction!=Direction.UP)
head.direction=Direction.DOWN;
break;
case KeyEvent.VK_LEFT:
if(head.direction!=Direction.RIGHT)
head.direction=Direction.LEFT;
break;
case KeyEvent.VK_RIGHT:
if(head.direction!=Direction.LEFT)
head.direction=Direction.RIGHT;
break;
}
}
/*蛇吃苹果**/
public void eatFood(Food food) {
if(this.getRectangle().intersects(food.getRectangle())){
addToHead();
food.updateAppleLocation();
grass.setScore(grass.getScore()+5);
}
}
/*获取蛇的碰撞点**/
private Rectangle getRectangle(){
return new Rectangle(head.cols*Grass.BOX_SIZE,head.rows*Grass.BOX_SIZE,head.w,head.h);
}
private class Node{
private int rows,cols;//行列
private int w=Grass.BOX_SIZE;//节宽
private int h=Grass.BOX_SIZE;//节高
private Node next;//下一个节点
private Node pre;//上一个节点
private Direction direction;//默认方向:左
public Node(int rows,int cols,Direction direction){
this.rows=rows;
this.cols=cols;
this.direction=direction;
}
/*画出小蛇的一节**/
public void drawNode(Graphics graphics){
Color color = graphics.getColor();
graphics.setColor(SNAKE_COLOR);
graphics.fillRect(cols*Grass.BOX_SIZE,rows*Grass.BOX_SIZE,w,h);
graphics.setColor(color);
}
}
}
四、枚举方向
Direction.java
package enums;
/**
* Created by IntelliJ IDEA.
* Author: Rich
* Date: 2021/7/29 21:44
* Description: 方向
*/
public enum Direction {
LEFT,RIGHT,UP,DOWN;
}