javascript贪吃蛇游戏设计与实现


Posted in Javascript onSeptember 17, 2020

本文为大家分享了javascript实现贪吃蛇游戏的具体代码,供大家参考,具体内容如下

效果图

javascript贪吃蛇游戏设计与实现

设计

贪吃蛇游戏是一款休闲益智类游戏。既简单又耐玩。该游戏通过控制蛇头方向吃蛋,从而使得蛇变得越来越长。

玩法:

点击屏幕控制蛇的移动方向,寻找吃的东西,每吃一口就能得到一定的积分,而且蛇的身子会越吃越长,身子越长玩的难度就越大,不能咬到自己的身体,更不能咬自己的尾巴,等到了一定的分数,游戏胜利。

设计:

首先需要创建一个棋盘,然后需要生成一条贪吃蛇,接着随机生成食物。每当蛇吃到食物的时候,随机生成新的食物,蛇头吃到自己的身体的时候游戏结束。

棋盘设计:

元素 :行数,列数,基础细胞(可表现为空,食物,蛇身体);

属性 :创建棋盘,清空棋盘;

基础细胞设计:

属性 :重设颜色,重设大小;

食物:

需求 : 需要在棋盘剩余空白位置随机位置生成食物;

贪吃蛇:

元素 : 位置集合(数组),移动速率,移动方向

需求: 初始随机生成只有一节的贪吃蛇,定时器函数(根据移动方向求得下一个要移动到的位置,需要注意的是到达边界后进行特殊处理。判断下个位置是否为蛇本身,如果是蛇就吃到自己,游戏结束。接着将下个位置添加到蛇位置集合内,最后判断下个位置 是否与食物相同,如果相同,则重现生成新的食物,否则移除蛇尾)。

方向控制:

本游戏使用点击屏幕,控制蛇移动方向。

实现

cell.js

/*
 * @Author: ls
 * @Date: 2020-09-01 18:23:09
 * @LastEditTime: 2020-09-16 14:23:37
 * @LastEditors: Please set LastEditors
 * @Description: 基础细胞类
 * @FilePath: \snake\assets\cell.js
 */

cc.Class({
 extends: cc.Component,

 properties: {},

 onLoad() {},

 /**
 * @param {*} cellColor
 */
 setCellColor(cellColor = new cc.color(255, 255, 255, 255)) {
 this.node.getChildByName('color').color = cellColor;
 },

 /**
 * @param {*} cellSize
 */
 setCellPos(cellSize = new cc.v2(20, 20)) {
 this.node.width = cellSize.x;
 this.node.height = cellSize.y;
 },
});

guideCtrl.js

/*
 * @Author: ls
 * @Date: 2020-09-03 18:09:18
 * @LastEditTime: 2020-09-14 08:55:47
 * @LastEditors: Please set LastEditors
 * @Description: 引导类
 * @FilePath: \snake\assets\guideCtrl.js
 */

cc.Class({
 extends: cc.Component,

 properties: {
 step: [cc.Node],
 startToggle: cc.Toggle,
 },

 onLoad() {
 this.startGuide();
 this.startToggle.isChecked = false;
 },

 /**
 * 开始引导
 */
 startGuide() {
 if (!this.step.length) {
 this.node.destroy();
 return;
 }
 for (let index = 0, length = this.step.length; index < length; index++) {
 this.step[index].active = false;
 }
 this._step = 0;
 this.step[0].active = true;
 },

 /**
 * 下一个引导页面
 */
 nextGuide() {
 this._step++;
 if (this._step < this.step.length - 1) {
 this.step[this._step].active = true;
 this.step[this._step - 1].active = false;
 if (this._step === this.step.length - 2) {
 this.step[this._step + 1].active = true;
 }
 } else {
 this.node.active = false;
 }
 },

 callback: function (toggle) {
 cc.sys.localStorage.setItem('isStart', toggle.isChecked);
 },
});

gameCtrl.js

/*
 * @Author: ls
 * @Date: 2020-09-01 15:44:33
 * @LastEditTime: 2020-09-16 14:23:18
 * @LastEditors: Please set LastEditors
 * @Description: 游戏导演类
 * @FilePath: \snake\assets\gameController.js
 */

var noneColor = new cc.color(120, 120, 120, 255);
var foodColor = new cc.color(254, 168, 23, 255);
var snakeColor = new cc.color(243, 60, 66, 255);

cc.Class({
 extends: cc.Component,

 properties: {
 // 棋盘
 node_grid: cc.Node,
 // 分数
 lab_score: cc.Label,
 // 最好分数
 lab_best: cc.Label,

 // 开始
 node_start: cc.Node,
 // 新人引导
 node_guide: cc.Node,
 // 结束
 node_over: cc.Node,

 // 基础类
 cellPrefab: cc.Prefab,

 // 移动速度
 mSpeed: 5,
 // 列数
 colCount: 30,
 // 行数
 rowCount: 30,
 },

 onLoad() {
 // 初始化方向
 // 静止、上、下、左、右
 // (0,0)、(0,1)、(0,-1)、(-1,0)、(1,0)
 this._direction = { x: 0, y: 0 };
 // 初始化细胞大小
 this._cellSize = { x: 10, y: 10 };

 this._map = [];
 this.initCellPool();
 this.onCreateMap();
 // 显示开始游戏界面
 this.showStartGame();
 },

 /**
 * 初始化细胞对象池
 */
 initCellPool() {
 this.cellPool = new cc.NodePool();
 let initCount = this.rowCount * this.colCount;
 for (let i = 0; i < initCount; i++) {
 let cell = cc.instantiate(this.cellPrefab); // 创建节点
 this.cellPool.put(cell); // 通过 put 接口放入对象池
 }
 },

 /**
 * 创建地图
 */
 onCreateMap() {
 this._map = [];
 let node_bg = this.node_grid.getChildByName('background');
 this._cellSize = { x: node_bg.width / this.rowCount, y: node_bg.height / this.colCount };

 for (var y = 0; y < this.colCount; y++) {
 for (let x = 0; x < this.rowCount; x++) {
 var obj = {};
 obj.x = x;
 obj.y = y;
 obj.node = this.createCell(node_bg, x, y);

 this._map.push(obj);
 }
 }
 },

 /**
 * 从对象池请求对象
 * @param {*} parentNode
 */
 createCell: function (parentNode, x, y) {
 let cell = null;
 if (this.cellPool.size() > 0) {
 // 通过 size 接口判断对象池中是否有空闲的对象
 cell = this.cellPool.get();
 } else {
 // 如果没有空闲对象,也就是对象池中备用对象不够时,我们就用 cc.instantiate 重新创建
 cell = cc.instantiate(this.cellPrefab);
 }

 cell.getComponent('cell').setCellPos(this._cellSize);

 cell.x = this._cellSize.x * x;
 cell.y = this._cellSize.y * y;

 cell.parent = parentNode;
 return cell;
 },

 /**
 * 还原地图
 */
 clearMap() {
 for (let index = 0, length = this._map.length; index < length; index++) {
 this._map[index].node.getComponent('cell').setCellColor(noneColor);
 }
 },

 /**
 * 显示开始界面
 */
 showStartGame() {
 this.node_over.active = false;
 this.node_start.active = true;
 },

 /**
 * 显示结束界面
 */
 showOverGame() {
 this.node_start.active = false;
 this.node_over.active = true;
 },

 /**
 * 游戏开始
 */
 startGame() {
 this.node_guide.active = false;
 this.node_over.active = false;
 this.node_start.active = false;
 this.lab_score.node.active = true;
 this.lab_best.node.active = true;
 this.node_grid.active = true;
 // 是否首次进入界面
 if (!cc.sys.localStorage.getItem('isStart')) {
 this.node_guide.active = true;
 }

 this._score = 0;
 // 更新最高分数
 this.updateBest();

 this._canControl = true;
 this._direction = { x: 1, y: 0 };
 this._snakeGrid = [];
 this._foodGrid = {};

 // 初始化触摸事件
 this.openTouchEvent();

 this.clearMap();
 this.onCreateSnake();
 this.onCreateFood();

 // 开启移动
 this.schedule(this.move, 1 / this.mSpeed);
 },

 /**
 * 更新分数
 */
 updateBest() {
 this._best = cc.sys.localStorage.getItem('best');
 if (this._best) {
 if (this._best < this._score) {
 this._best = this._score;
 cc.sys.localStorage.setItem('best', this._best);
 }
 } else {
 this._best = this._score;
 cc.sys.localStorage.setItem('best', this._best);
 }

 this.lab_best.string = this._best;
 },

 /**
 * 游戏结束
 */
 gameOver() {
 // 是否能控制 蛇改变移动方向
 this._canControl = false;

 this.unschedule(this.move);
 this.closeTouchEvent();
 this.clearMap();
 this.showOverGame();
 },

 /**
 * 创建蛇
 */
 onCreateSnake() {
 let x = ~~(Math.random() * this.rowCount);
 let y = ~~(Math.random() * this.colCount);

 for (let index = 0, length = this._map.length; index < length; index++) {
 if (this._map[index].x === x && this._map[index].y === y) {
 this._map[index].node.getComponent('cell').setCellColor(snakeColor);
 this._snakeGrid.push(this._map[index]);
 }
 }
 },

 /**
 * 创建食物
 */
 onCreateFood() {
 if (this._map.length !== this._snakeGrid.length) {
 let r = ~~(Math.random() * (this._map.length - this._snakeGrid.length));

 let subGrid = [];
 for (let i = 0; i < this._map.length; i++) {
 subGrid.push(this._map[i]);
 }

 for (let m = 0; m < subGrid.length; m++) {
 for (let n = 0; n < this._snakeGrid.length; n++) {
  if (subGrid[m].x === this._snakeGrid[n].x && subGrid[m].y === this._snakeGrid[n].y) {
  subGrid.splice(m, 1);
  if (m > 0) {
  m--;
  }
  }
 }
 }

 for (let index = 0; index < subGrid.length; index++) {
 if (index === r) {
  this._foodGrid = subGrid[index];
  this._foodGrid.node.getComponent('cell').setCellColor(foodColor);

  // 增加分数
  this._score++;
  this.lab_score.string = this._score;
 }
 }
 }
 },

 /**
 * 打开触摸
 */
 openTouchEvent() {
 var self = this;
 this.node.on(
 cc.Node.EventType.TOUCH_START,
 function (touch) {
 if (self._canControl) {
  self._canControl = false;
  let touchPos = self.node.convertToNodeSpaceAR(touch.getLocation());
  self._direction = self.getTouchDirection(touchPos);

  this.scheduleOnce(function () {
  self._canControl = true;
  }, 1 / this.mSpeed);
 }
 },
 this
 );
 },

 /**
 * 关闭触摸
 */
 closeTouchEvent() {
 this.node.off(cc.Node.EventType.TOUCH_START, this);
 },

 /**
 * 获取选择的方向
 * @param {* 触摸位置} touchPos
 */
 getTouchDirection(touchPos) {
 // 获取向量长度
 function getABS(pos) {
 return Math.sqrt(pos.x * pos.x + pos.y * pos.y);
 }
 // 获取横向 方向
 function getLandscape(touchPos) {
 if (touchPos.x > 0) {
 cc.log('更改为 向 右 移动');
 return { x: 1, y: 0 };
 } else {
 cc.log('更改为 向 左 移动');
 return { x: -1, y: 0 };
 }
 }
 // 获取竖向 方向
 function getPortrait(touchPos) {
 if (touchPos.y > 0) {
 cc.log('更改为 向 上 移动');
 return { x: 0, y: 1 };
 } else {
 cc.log('更改为 向 下 移动');
 return { x: 0, y: -1 };
 }
 }

 if (getABS(this._direction) === 1) {
 cc.log('蛇 正在移动');
 if (this._direction.y === 1) {
 cc.log('蛇 正在向 上 移动');
 return getLandscape(touchPos);
 } else if (this._direction.y === -1) {
 cc.log('蛇 正在向 下 移动');
 return getLandscape(touchPos);
 } else if (this._direction.x === -1) {
 cc.log('蛇 正在向 左 移动');
 return getPortrait(touchPos);
 } else if (this._direction.x === 1) {
 cc.log('蛇 正在向 右 移动');
 return getPortrait(touchPos);
 }
 } else {
 cc.log('蛇 未开始 或 停止了移动。此时修改方向无效!');
 }
 },

 /**
 * 移动
 */
 move() {
 let nextGrid = {};
 nextGrid.x = this._snakeGrid[this._snakeGrid.length - 1].x + this._direction.x;
 nextGrid.y = this._snakeGrid[this._snakeGrid.length - 1].y + this._direction.y;

 if (this._direction.x === 1) {
 // 向右
 if (nextGrid.x > this.colCount - 1) {
 nextGrid.x = 0;
 }
 } else if (this._direction.x === -1) {
 // 向左
 if (nextGrid.x < 0) {
 nextGrid.x = this.colCount - 1;
 }
 } else if (this._direction.y === 1) {
 // 向上
 if (nextGrid.y > this.rowCount - 1) {
 nextGrid.y = 0;
 }
 } else if (this._direction.y === -1) {
 // 向下
 if (nextGrid.y < 0) {
 nextGrid.y = this.rowCount - 1;
 }
 }

 for (let m = 0, l = this._map.length; m < l; m++) {
 if (this._map[m].x === nextGrid.x && this._map[m].y === nextGrid.y) {
 nextGrid = this._map[m];
 }
 }

 for (let n = 0, length = this._snakeGrid.length; n < length; n++) {
 if (nextGrid.x === this._snakeGrid[n].x && nextGrid.y === this._snakeGrid[n].y) {
 this.gameOver();
 // return false;
 }
 }

 nextGrid.node.getComponent('cell').setCellColor(snakeColor);
 this._snakeGrid.push(nextGrid);

 if (nextGrid.x === this._foodGrid.x && nextGrid.y === this._foodGrid.y) {
 this.onCreateFood();
 } else {
 let startGrid = this._snakeGrid.shift();
 startGrid.node.getComponent('cell').setCellColor(noneColor);
 }
 },
});

完整代码:js贪吃蛇游戏

更多有趣的经典小游戏实现专题,分享给大家:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
js 获取中文拼音,Select自动匹配字母获取值的代码
Sep 23 Javascript
JavaScript 利用StringBuffer类提升+=拼接字符串效率
Nov 24 Javascript
javascript 清空form表单中某种元素的值
Dec 26 Javascript
ext combox 下拉框不出现自动提示,自动选中的解决方法
Feb 24 Javascript
Jquery中Ajax 缓存带来的影响的解决方法
May 19 Javascript
网页打开自动最大化的js代码
Aug 22 Javascript
JavaScript-RegExp对象只能使用一次问题解决方法
Jun 23 Javascript
js判断上传文件后缀名是否合法
Jan 28 Javascript
js实现适配不同的屏幕大小
Apr 10 Javascript
关于meta viewport中target-densitydpi属性详解(推荐)
Aug 18 Javascript
详解基于webpack2.x的vue2.x的多页面站点
Aug 21 Javascript
vue中使用腾讯云Im的示例
Oct 23 Javascript
js实现简单的随机点名器
Sep 17 #Javascript
谈谈JavaScript中的垃圾回收机制
Sep 17 #Javascript
js对象属性名驼峰式转下划线的实例代码
Sep 17 #Javascript
详细分析JavaScript中的深浅拷贝
Sep 17 #Javascript
js实现鼠标滑动到某个div禁止滚动
Sep 17 #Javascript
原生js+css实现tab切换功能
Sep 17 #Javascript
vue使用screenfull插件实现全屏功能
Sep 17 #Javascript
You might like
PHP如何将log信息写入服务器中的log文件
2015/07/29 PHP
SESSION存放在数据库用法实例
2015/08/08 PHP
laravel创建类似ThinPHP中functions.php的全局函数
2016/11/26 PHP
PHP simplexml_import_dom()函数讲解
2019/02/03 PHP
ThinkPHP5分页paginate代码实例解析
2020/11/10 PHP
基于jquery的多彩百分比 动态进度条 投票效果显示效果实现代码
2011/08/28 Javascript
给页面渲染时间加速 干掉Dom Level 0 Event
2012/12/19 Javascript
Extjs改变树节点的勾选状态点击按钮将复选框去掉
2013/11/14 Javascript
JavaScript+CSS实现仿天猫侧边网页菜单效果
2015/08/25 Javascript
基于JavaScript代码实现pc与手机之间的跳转
2015/12/23 Javascript
属于你的jQuery提示框(Tip)插件
2016/01/20 Javascript
JavaScript中push(),join() 函数 实例详解
2016/09/06 Javascript
不得不看之JavaScript构造函数及new运算符
2017/08/21 Javascript
mint-ui 时间插件使用及获取选择值的方法
2018/02/09 Javascript
JavaScript对象字面量和构造函数原理与用法详解
2020/04/18 Javascript
springboot+vue实现文件上传下载
2020/11/17 Vue.js
[42:35]2018DOTA2亚洲邀请赛3月30日 小组赛A组 VG VS OpTic
2018/03/31 DOTA
Python列表推导式的使用方法
2013/11/21 Python
python对字典进行排序实例
2014/09/25 Python
Python中多线程及程序锁浅析
2015/01/21 Python
浅析Python中的多重继承
2015/04/28 Python
Python使用turtule画五角星的方法
2015/07/09 Python
python3.4用函数操作mysql5.7数据库
2017/06/23 Python
Python应用库大全总结
2018/05/30 Python
Python实现的合并两个有序数组算法示例
2019/03/04 Python
Django ORM 查询管理器源码解析
2019/08/05 Python
马德里运动鞋商店:Nigra Mercato
2020/02/16 全球购物
POS解决方案:MUNBYN(热敏打印机、条形码扫描仪)
2020/06/09 全球购物
sealed修饰符是干什么的
2012/10/23 面试题
行政办公员自我评价分享
2013/12/14 职场文书
校园活动宣传方案
2014/03/28 职场文书
优秀乡村医生事迹材料
2014/05/28 职场文书
工地质量标语
2014/06/12 职场文书
职业生涯规划书之大学四年
2019/08/07 职场文书
mysql查询结果实现多列拼接查询
2022/04/03 MySQL
零基础学java之方法的定义与调用详解
2022/04/10 Java/Android