重温游戏经典——给对象写一个贪吃蛇的游戏(Java实现)

效果预览
请添加图片描述

项目架构
在这里插入图片描述

一、草地类

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;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王菜鸟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值