java swing最简单贪吃蛇原理及源码

本文详细介绍了如何使用Java绘制并实现贪吃蛇游戏的基本功能,包括蛇身绘制、蛇移动原理、键盘控制方向、食物检测及碰撞处理。通过代码实例,深入解析了游戏中的关键技术和实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

找了好多案例,发现都是贴图的,要么就是代码无法运行的,好不容易找到一个,结果代码粘贴的辣眼睛。

我的笔记中其中两篇详细介绍原理

参考:https://blog.csdn.net/lengyuhong/article/details/4926776

  • 主要是参考本链接代码来写的,他这个代码可以直接跑通,但是界面和其他冗余代码有一点,就改了下,附上自己的理解发上来

接下来就是整个贪吃蛇,包结构        

贪吃蛇这个原理:

  • 蛇身打印,利用矩形填充打印方块,几个方块存储在数组中,按顺序打印出来。数组存储的数据时按键方向判断之后对相应方向、比如上或者下加上高度或者宽度。
  • 蛇移动,就是不停刷新界面,重新绘制方块。方块的绘制上面连接里面有,刷新方块上面连接也有。
  • 键盘控制方向,键盘是new一个键盘监视器,把他给SnakeClient,然后new SnakeClient时候就可以调用。每个按键都有自己的代码,用getKeyCode返回按键值,然后用一个case给方向Direction赋值。其中方向,用了一个枚举类型来存储四个方向,不用枚举应该也可以,使用字符串常量,或者一个变量给四个值来判断方向,我还没有尝试,大家有兴趣可以自己试试。
  • 吃食物,用一个矩形区域检测,这个是java自带的,直接调用Rectangle中的这个检测函数。把food的矩形和蛇头的矩形区域比较。比较之后再次重新调用food的set函数设置food下次出现位置。
  • this涉及的比较多,函数重写有一点,就是paint,还有repaint调用。学会这个对对象和类有挺大帮助。

代码缺点:

  1. 还没实现蛇身碰撞检测,这会加大代码量,本代码力求最简单
  2. 还没实现边界检测,蛇会跑到界面外
  3. 还没实现计分板功能,虽然这个需求比较简单,但是我们的目标是尽量少的代码,让初学者能看懂

第一个是显示界面,运用线程启动,用刷新来重新绘制图形

package cn.led.snake;


import java.awt.*;
import java.awt.event.*;

public class SnakeClient extends Frame{	
	Snake mySnake = new Snake(this);
	Food food = new Food(this);

	public void lanch(){
		this.setBounds(200,100, 700,700); //设置窗体大小和位置
		this.setTitle("我是贪吃蛇");
		this.setVisible(true); //使用该属性才能显示窗体
		this.setBackground(Color.black);
		//实现程序运行关闭的功能
		this.addWindowListener(new WindowAdapter(){
			public void windowClosing(WindowEvent e){
				System.exit(-1);
			}
		});
		this.addKeyListener(new KeyMointer());//调用键盘,不启用这个无法开启键盘控制
		new Thread(new PaintThread()).start();//开启线程
	}

	//画图函数,这个是重写paint,貌似是Frame类的内置函数
	public void paint(Graphics g){
		mySnake.paint(g);
		food.paint(g);
	}

	class PaintThread implements Runnable{
		public void run() {
			//while(true)保持蛇能一直运行
			while(true){
				repaint();
				try {
					//物体运行太快,肉眼无法追踪,这是减慢速度,使得肉眼能跟上刷新速度
					Thread.sleep(250);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}				
			}
		}
	}

	//键盘控制
	class KeyMointer extends KeyAdapter{
		public void keyPressed(KeyEvent e){
			mySnake.keyPress(e);
		}
	}

	public static void main(String[] args){
		SnakeClient snakeClient = new SnakeClient();
		snakeClient.lanch();
	}
}



第二个是蛇的绘制

package cn.led.snake;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;


public class Snake {
	final static int WIDTH = 20;//蛇身的宽
	final static int HEIGHT = 20;//蛇身的高
	final static int maxLong = 900;//蛇最多节数	
	enum Direction{Left,Up,Right,Down};//方向枚举

	int number = 5;//蛇身初始化节数

	int[] x = new int[maxLong];//蛇身x轴位置
	int[] y = new int[maxLong]; //蛇身y轴位置
	Direction snakeDirection ; 
	SnakeClient sc;

	public Snake(SnakeClient sn) {
		this.number = 5;
		//初始化蛇身,不初始化可能会随机出现在界面外
		for(int i=0;i<=number;i++){
			x[i] = 100;
			y[i] = 100;
		}
		//初始方向
		this.snakeDirection = Direction.Right;
		this.sc = sn;
	}

	public void move() {
		if(this.snakeDirection==Direction.Down) {
			for (int i = 0; i < number; i++) {
				x[i] = x[i+1];
				y[i] = y[i+1];
			}
			y[number] = y[number]+HEIGHT;
		}
		else if(this.snakeDirection==Direction.Right) {
			for (int i = 0; i < number; i++) {
				x[i] = x[i+1];
				y[i] = y[i+1];
			}
			x[number] = x[number]+WIDTH;
		}
		else if(this.snakeDirection==Direction.Up) {
			for (int i = 0; i < number; i++) {
				x[i] = x[i+1];
				y[i] = y[i+1];
			}
			y[number] = y[number]-HEIGHT;
		}
		if(this.snakeDirection==Direction.Left){
			for (int i = 0; i < number; i++) {
				x[i] = x[i+1];
				y[i] = y[i+1];
			}
			x[number] -= WIDTH;
		}
	}

	//方向键对蛇的控制
	public void keyPress(KeyEvent e){
		int press = e.getKeyCode();
		switch(press){
		case KeyEvent.VK_LEFT:
			this.snakeDirection = Direction.Left;
			break;
		case KeyEvent.VK_UP:
			this.snakeDirection = Direction.Up;
			break;
		case KeyEvent.VK_RIGHT:
			this.snakeDirection = Direction.Right;
			break;
		case KeyEvent.VK_DOWN:
			this.snakeDirection = Direction.Down;
			break;
		}
	}

	public void paint(Graphics g){
		Color c = g.getColor();
		g.setColor(Color.blue);  //设置颜色为蓝色
		for (int i = 0; i <=number; i++) { //最后一个画出的是蛇头
			if (i==number) {
				g.setColor(Color.yellow);
				g.fillRect(x[number], y[number], 20, 20); //蛇头设置成黄色
			}
			g.fillRect(x[i], y[i], 20, 20); //填充矩形
		}
		g.setColor(c);
		move();
		eatFood(this.sc.food);
	}


	//蛇吃食物
	public void eatFood(Food food){
		//判断是否产生碰撞,返回true则刷新食物
		if(this.getRec().intersects(food.getRec())){ 
			number++; //吃到食物蛇长度+1
			x[number] = sc.food.getX();
			y[number] = sc.food.getY();
			this.sc.food.setX(((int)(Math.random()*29))*Snake.WIDTH);
			this.sc.food.setY((int)(Math.random()*29+1)*Snake.HEIGHT);
		}
	}

	public Rectangle getRec(){
		return new Rectangle(x[number],y[number],WIDTH,HEIGHT);
	}


}

第三个是食物绘制代码

package cn.led.snake;

import java.awt.*;



public class Food {
	public static int WIDTH = 20;
	public static int HEIGHT = 20;
	private boolean isLive = true;//判断食物是否还在
	int x ,y;//初始化食物出现地点
	SnakeClient ms;
	
	
	public Food(SnakeClient ms){
		x = ((int)(Math.random()*50))*SnakeClient.WIDTH;
		y = (int)(Math.random()*50)*SnakeClient.HEIGHT;
		isLive = true;
		this.ms = ms;
	}
	
	public boolean isLive() {
		return isLive;
	}

	public void setLive(boolean isLive) {
		this.isLive = isLive;
	}

	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 void paint(Graphics g){
		if(isLive==true){
			Color c = g.getColor();
			g.setColor(Color.red);
			g.fillRect(x, y, WIDTH, HEIGHT);
		}
	}
	
	public Rectangle getRec(){
		return new Rectangle(x,y,WIDTH,HEIGHT);
	}
}

 

运行效果图---------动图-----------

 

CJds_snakeView类 Struct list { int x; int y; }; 点结构,x表示横坐标,y表示纵坐标。 成员变量: int start;start=1开始游戏,start=0停止游戏。 int difficulty;表示游戏难度,等于10表示容易,等于6表示普通,等于3表示困难,等于2表示特困。 int last_aspect;表示蛇之前前进的方向,用于判断防止蛇逆行的。 int can_new;表示是否添加新食物。等于1表示产生新的食物,等于0表示产生之后不不要再产生食物。 int count;表示蛇的节数; CRect rct;表示矩形方格; list a[100];保存蛇的长度; list b;用来保存蛇头的坐标位置; int aspect;表示蛇前进的方向 等于0表示蛇向右前进; 等于1表示蛇向下前进; 等于2表示蛇向左前进; 等于3表示蛇向上前进; int xx;表示食物的x坐标; int yy;表示食物的y坐标; 成员函数: void Init();初始化蛇的节数,并确定了节数的坐标位置。首先初始化蛇的前进方向aspect=0是向右前进的,last_aspect=0用来保存蛇当前前进的方向。并且初始化蛇的节数为4节,并指明了它们的坐标位置。can_new=1表示产生一个新的食物。 void aliveordie();判断蛇是死还是活着。有两种情况,一种是蛇自己撞到自己,表示死了,start=0从新开始游戏,另一种是超出了界面(20,20,420,420)撞到了墙start=0也从新开始游戏。 double random(double start,double end);在start和end坐标之间产生随即数; 消息处理事件: (1)void onTimer(UINT nIDEvent);在OnCreate()创建计时器SetTimer(),来触发OnTimer事件,所以要首先销毁时间计时器,然后调用aliveordie()函数判断蛇的生死情况,CString str_count; str_count.Format("分数:%d",count-4)显示蛇的节数,TextOut()指出坐标输出文本,创建设备上下文,和创建位图。然后把位图选择到设备上下文上,填充颜色为白色。 在位图上绘制两个矩形线框: Rectangle(CRect(10,10,440,440)); Rectangle(CRect(20,20,430,430)); 显示位图(BitBlt(0,0,1000,1000,&MenDC,0,0,SRCCOPY)); 判断如果游戏开始(start==1),b.x=a[0].x用b.x来保存蛇头的横坐标;b.y=a[0].y用b.y来保存蛇头的纵坐标。如果aspect==0表示蛇向右前进,aspect=1表示蛇向下前进,aspect==2表示蛇向左前进,aspect==3表示蛇向上前进,a[1].x=b.x;a[1].y=b.y;把蛇头的坐标付给了a[1],说明蛇头改变了前进的方向。绘制蛇头矩形方格,并且设置蛇头的颜色为红色,蛇身是三个黄色的矩形方格。if (a[0].x==xx && a[0].y==yy)判断蛇头的位置与食物的关系,现在的情况说明蛇吃了食物,蛇的节数加一,各个节数的坐标向前进一位。调用random()函数产生随即的食物,然后判断食物随即产生的位置与蛇的位置,如果产生的食物在蛇身体上,要从新调用random()函数随即再产生食物。产生的食物颜色为绿色。int m_timer=SetTimer(1,difficulty*30,NULL);计时间隔,计时间隔的快慢是根据难易程度的不而确定的。销毁位图、销毁设备上下文。 (2)OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);判断蛇当前前进的方向,当aspect返回0,表示蛇前进的方向是向右,当aspect返回1,表示蛇前进的方向是下,当aspect返回2,表示蛇前进的方向是向左,当aspect返回3,表示蛇前进的方向是向上。 (3)点击菜单按钮调用以下函数: OnDifficultyEasy();OnDifficultyHard();OnDifficultyNormal();OnDifficultyVeryhard();OnButtonStart();
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值