Java贪吃蛇

Java贪吃蛇,第1张

Java贪吃蛇

 Java贪吃蛇,粘贴应该就能运行,不过要java环境就是了。

做这个项目的时候天天挂着浏览器,查了不少资料,甚至直接cv工程师上线,下面是一个比我做得好的,我也是一大半都从那抄来,不过,说全抄不会真信吧,如果真新,那就是我的注释不够详细了。。。

Java实例代码实现一个简单的贪吃蛇小游戏 | w3c笔记 (w3cschool.cn)

package game;//包名,包名出错会报错

import java.awt.Color;//颜色
import java.awt.Font;//后面设置游戏界面绘制文字字体用的
import java.awt.Graphics;//绘制游戏界面用的
import java.awt.event.KeyEvent;//按键事件
import java.awt.event.KeyListener;//键盘监听,贪吃蛇项目需要监听玩家按下的方向键 
import javax.swing.Jframe;//窗口控件,窗口里可以放置组件
import javax.swing.JPanel;//组件,用于充当绘制游戏界面的画板
import java.util.Random;//随机数
import java.util.Timer;//定时用的
import java.util.TimerTask;//定时任务类

public class Demo extends JPanel implements KeyListener {// 用java语言翻译成汉语就是:Demo类继承了JPanel并实现了KeyListener接口
	
	private static final long serialVersionUID = 1L;// 不知道干啥的反正没加的时候编辑器就提醒加,加不加却都能运行

	// 以下都是全局变量与局部方法内定义的变量不同,全局变量可以在类中的任意方法中被调用,但局部变量不可以

	public int snakeX[] = new int[100];// 新建一个数组,用于存储蛇的每一节身体在x轴上的坐标,最多100个

	public int snakeY[] = new int[100];// y轴坐标,同上

	public int length;// 蛇有长度,用一个整数变量存储这个长度,后续蛇吃到食物这个长度会增加

	public String direction;// 蛇走的时候有方向,所以用一个全局变量储存

	public int food[] = new int[2];// 食物只有一个,所以要记录食物的坐标只需要两个整数变量,干脆一个长度为2的数组(food[0]是x坐标,food[1]是y坐标)

	public boolean isStart;// 是否开始游戏,按空格键开始

	public boolean isFail;// 你输了吗,我怎么可能会输呢,是游戏bug了

	public int score;// 游戏得分,现在给它赋值多少,你就能以多少分起步了,作弊模式,开启

	Random r = new Random();//食物的出现是随机的所以需要生成随机数,Random里有一个在给定范围内生成整数的方法,调用方法:对象.nextInt();前提是要实例化Random类为对象

	// 下面的Demo方法和类名重合,并且不符合构成方法头必要的三个条件(1.访问权限,例如public公开的或者private私有的 2.返回值类型例如String,表示返回的值是字符串形的,void表示没有返回值 3.方法名)
	public Demo() {// 所以这不是普通的函数或方法,而是构造方法,在实例化这个类(new
					// 类名())的时候会自动调用这个函数,有时候用这个方法代替“初始化"方法是真方便,但这次好像不能,所以需要额外再写一个
		this.setBackground(Color.white);// java语:设置游戏背景为白色,默认灰色
		this.setFocusable(true);// java语:让游戏界面成为焦点,焦点:当你的桌面上有很多界面的时候,比如说记事本和java编辑器,焦点在编辑器上的时候可以正常输入,但是此时打开记事本,焦点就会转移,把字打在记事本上,再点击一次编辑器,编辑器界面就能获得焦点,再次编辑
		this.addKeyListener(this);// 给游戏界面绑定一个键盘输入监听器,第一个this表示游戏界面,第二个表示监听器,详情请百度搜索java 继承和addKeyListener
		init();
	}

	public void init() {// 初始化方法,定义一个蛇,包括头长度为3,头和身体连起来占据三个相邻坐标,同时蛇的方向向右
		length = 3;

		snakeX[0] = 40;// 头(第一节)x坐标
		snakeY[0] = 0;// y

		snakeX[1] = 20;// 第二节
		snakeY[1] = 0;

		snakeX[2] = 0;// 三
		snakeY[2] = 0;

		direction = "R";// Right的缩写
		
		score = 0;//初始化后分数清零
		
		isStart = false;//先将游戏定义为未开始状态,后面加入一个按空格开始游戏的 *** 作
		
		isFail = false;//没死之前就是没失败,对就这样定义
		
		refreshFood();//这个函数就一个刷新食物的作用
	}

	@Override // 重写标志 www.bai.com 关键词:@Override
	public void paint(Graphics g) {// JPanel类里的构造函数,好像和Graphics有点关系,什么关系呢,不懂。。。
		super.paint(g);// 调用父辈的paint方法 www.bai.com 关键词:重写,继承,这里的作用好像是调用这个能清空画板
		g.setColor(Color.green);// 设置画笔颜色为绿色,为什么是绿色呢,问就是不知道
		g.setFont(new Font("幼圆",Font.BOLD,20));//设置字体,后面会有直接在游戏界面显示文字的代码
		g.drawString("Score:"+score, 520, 20);//时刻显示玩家的得分情况
		if(isFail) {
			g.setFont(new Font("幼圆",Font.BOLD,50));//准备偷笑
			g.drawString("你把自己的脑子给吃了", 50, 100);//哈哈
		}
		if(!isStart) {//java语:如果游戏是未开始状态,为什么没开始呢,三种情况,一是刚打开游戏,二是结束游戏,三是pause暂停
			g.setFont(new Font("幼圆",Font.BOLD,50));//字号调大点,准备画大大的文字
			if(isFail) {//java语:如果失败了
				g.drawString("按下空格键重新开始游戏", 20, 220);//就画个“再战一轮”
			}else {//否则呢,就是说如果没有失败的话
				g.drawString("按下空格键开始游戏", 80, 220);//就表示你需要继续游戏
			}
		}
		g.fillRect(food[0], food[1], 20, 20);
		for (int i = 0; i < length; i++) {// 0~整数length,但不包括length,意为循环length次
			g.fillRect(snakeX[i], snakeY[i], 20, 20);// 画矩形,i=[0~3)所以是遍历蛇的每一节,然后画
		}
	}

	public static void main(String[] args) {// 主方法,没有主方法你试试
		Jframe jf = new Jframe("Snake");// 实例化Jframe,相当于新建一个窗口,()里的字符串是窗口的title,不知道title是什么意思下载有道词典去
		jf.setBounds(500, 300, 640, 480);// 设置窗口范围,四个参数依次是(离屏幕左边有多远,离上面有多远,窗口多宽,多高)
		jf.setResizable(false);// java语:可以被用户拉伸或者压缩窗口吗?不可以!
		Demo d = new Demo();//
		jf.add(d);// 画板固定到窗口里 画板(游戏界面)
		jf.setVisible(true);// java语:要显示窗口吗。显示,不然不让你看见
		d.doLoop();
	}
	//接下来是刷新食物的方法,食物呢要随机,而且,不能刷在蛇身上
	public void refreshFood() {
		boolean f = true;//谜之定义
		while(f) {//哈哈,不是谜之循环,上面一句的定义是为了进入while循环,顺便定义个布尔类型的变量,作用之后再说
			food[0] = 20*r.nextInt(31);//nextInt()里的是随机数范围的最大值,最小值是零,乘20是为了让它在蛇能吃到的地方,蛇能走到的坐标是20的倍数
			food[1] = 20*r.nextInt(23);//刚刚是x坐标,这是y
			f = false;//这个布尔值是刚刚使while循环被执行的条件,现在设置成false不管的话会只执行现在这一次
			for (int i = 0; i < length; i++) {//for循环,i的范围是零到length-1,执行次数的是length次
				if(food[0] == snakeX[i] && food[1] == snakeY[i]) {//其实就是遍历蛇的每一节身体所在的坐标,看看有没有和食物重合的,如果重合了,该怎么办啊T_T
					f = true;//如果重合,怎么是这样啊,这个f看起来不太可靠啊,能行吗
				}
			}
		}//如果重合的话,将无法跳出循环,再次执行循环体,刷新食物坐标,直到不再重合
	}
	// 下面是3个重写大礼包
	@Override // 重写标志 www.bai.com 关键词:@Override
	public void keyPressed(KeyEvent e) {// 按下键的时候调用这个函数,属于用keyListener接口必须要实现的方法
		int keycode = e.getKeyCode();//java语,定义一个整形变量用来接受用户按下方向键的键码值
		if(keycode == KeyEvent.VK_SPACE) {//java语,如果按下去的键的键码值等于空格的键码值,其实意思就是如果按了空格键
			if(isStart) {//就判断游戏是不是开始状态
				isStart = false;//是的话,就宣布,游戏暂停了,当然不是真的暂停,而是后面执行蛇移动的程序看到isSart不是true就不再让蛇的坐标移动了,但是会依然画,哪怕画从动态到禁止的东西就像是突然不画了,就定格了
			}else{//如果游戏本来就是没开始的,就让它继续,跑起来!!!
				if(isFail) {//或许不是游戏没开始,而是游戏早就结束了,没关系,判断一下
					init();//结束的话就清零现在的成绩,带着之前的成绩就是作弊了
				}
				isStart = true;//重新开始
			}
		}else if(keycode == KeyEvent.VK_RIGHT) {//如果按下右方向键
			if(direction != "l") {//就直接转头向右,不是吧,要区分情况啊,如果蛇现在向左的话是不能180°大回头的
				direction = "R";//只要不是向左,其他方向都可以直接转到右
			}
		}else if(keycode == KeyEvent.VK_LEFT) {//按下左
			if(direction != "R") {//只要不是原先向右
				direction = "L";//就可以转
			}
		}else if(keycode == KeyEvent.VK_UP) {//同上
			if(direction != "D") {
				direction = "U";
			}
		}else if(keycode == KeyEvent.VK_DOWN) {//同理
			if(direction != "U") {
				direction = "D";
			}
		}
		
	}

	@Override // 重写标志 www.bai.com 关键词:@Override
	public void keyReleased(KeyEvent e) {// 按键按下后弹起时调用,同上
		// 可是要做的都在keyPressed()方法里做完了,就空着,因为必须要实现T_T
	}

	@Override // 重写标志 www.bai.com 关键词:@Override
	public void keyTyped(KeyEvent e) {// 输入文本后调用,
		// 同上T_T
	}

	public void doLoop() {//来说说游戏动态画面的本质吧,就是静态的画面连续播放,所以执行一次是不够的,要重复循环
		Timer timer = new Timer();//Timer类有个函数
		timer.schedule(new TimerTask() {//函数里有个参数是一个抽象类
			public void run() {//要用这个抽象类就要重写它的构造函数,构造函数是什么,就比如说,你有一个杯子,你能拿他喝可乐,或者咖啡,但决定性的不是这些,
				//重要的是,你现在杯子里有什么?没错,抽象类就是一个什么都能装的杯子,但你能从中喝到什么就取决与它里面装的构造函数是什么
				//那么这个里面装的是啥,是写好任务的记事本,有人会隔一段时间就执行一次这个任务,你写的任务是做饭他就是你的厨师,是开车载你就是你的司机,任务就是这个人的构造函数
		        repaint();//这个函数是JPanel里有的,它会再次调用paint这个绘图方法
		        if(isStart&&!isFail){//java语,如果游戏是开始的(没错121行发出的信号就是它接受的)而且你现在还没吃掉自己
		            for (int i = length-1; i > 0 ; i--) {//就代表你是可以跑的,怎么跑呢,倒一占了前面倒二的位置,倒二占了前面倒三的位置。。。。。直到有人占了第一的位置,那么第一呢
		                snakeX[i] = snakeX[i-1];
		                snakeY[i] = snakeY[i-1];
		            }
		            //第一自己跑了。。。
		            if(direction=="R"){//以屏幕左上角为坐标系原点新建坐标系,求老师让我玩游戏^o^
		            	 snakeX[0] += 20;//如果蛇头方向向右,就x轴正半轴方向跑
		                if(snakeX[0]>620){//跑出界咋办
		                    snakeX[0] = 0;//让它从另一边出来
		                }
		            }
		            else  if(direction=="L"){
		                snakeX[0] -= 20;
		                if(snakeX[0]<0){
		                    snakeX[0] = 620;
		                }
		            }
		            else  if(direction=="U"){
		                snakeY[0] -= 20;
		                if(snakeY[0]<0){
		                    snakeY[0] = 440;
		                }
		            }
		            else  if(direction=="D"){
		                snakeY[0] += 20;
		                if(snakeY[0]>440){
		                    snakeY[0] = 0;
		                }
		            }
		            if(snakeX[0]==food[0]&&snakeY[0]==food[1]){//蛇头坐标如果和食物重合
		                length++;//蛇吃长一节
		                score++;//你得一分
		                refreshFood();//然后食物还得再长出来
		            }
		            for (int i = 1; i < length; i++) {//遍历除蛇头以为外的蛇身部分
		                if(snakeX[0]==snakeX[i]&&snakeY[0]==snakeY[i]){//如果蛇头和蛇身某一处重合,
		                    isFail = true;//就把自己吃掉了
		                    isStart = false;//gameover                        
		                }
		            }
				}
			}
		}, 0, 100);//这两个参数一个是等待多久开始执行,另一个是间隔多久执行一次
	}
}

莫扎特让我们奔赴旅程

今后会遇到什么

现在还不得而知

但是

我们依然会选择向前迈步

我们依然在路上

————《四月は君の嘘》

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5715546.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-18
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存