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 相关文章推荐
Mootools 1.2教程 选项卡效果(Tabs)
Sep 15 Javascript
javascript (用setTimeout而非setInterval)
Dec 28 Javascript
Javascript数组的排序 sort()方法和reverse()方法
Jun 04 Javascript
JavaScript基础知识之数据类型
Aug 06 Javascript
JavaScript中几个重要的属性(this、constructor、prototype)介绍
May 19 Javascript
Javascript中的call()方法介绍
Mar 15 Javascript
jQuery内容折叠效果插件用法实例分析(附demo源码)
Apr 28 Javascript
JQuery点击行tr实现checkBox选中的简单实例
May 26 Javascript
AngularJs中Bootstrap3 datetimepicker使用实例
Dec 13 Javascript
小程序调用微信支付的方法
Sep 26 Javascript
vue实现用户长时间不操作自动退出登录功能的实现代码
Jul 23 Javascript
详解JavaScript中分解数字的三种方法
Jan 05 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
使用网络地址转换实现多服务器负载均衡
2006/10/09 PHP
php zend解密软件绿色版测试可用
2008/04/14 PHP
深入php list()函数的详解
2013/06/05 PHP
探讨捕获php错误信息方法的详解
2013/06/09 PHP
PHP使用GIFEncoder类生成的GIF动态图片验证码
2014/07/01 PHP
PHP采用curl模仿用户登陆新浪微博发微博的方法
2014/11/07 PHP
php获取当前月与上个月月初及月末时间戳的方法
2016/12/05 PHP
用户注册常用javascript代码
2009/08/29 Javascript
腾讯的ip接口 方便获取当前用户的ip地理位置
2010/11/25 Javascript
JS中数组Array的用法示例介绍
2014/02/20 Javascript
JavaScript限定图片显示大小的方法
2015/03/11 Javascript
一种新的javascript对象创建方式Object.create()
2015/12/28 Javascript
javascript另类方法实现htmlencode()与htmldecode()函数实例分析
2016/11/17 Javascript
jQuery中的siblings()是什么意思(推荐)
2016/12/29 Javascript
JS实现含有中文字符串的友好截取功能分析
2017/03/13 Javascript
详解Node全局变量global模块
2017/09/28 Javascript
基于Vue自定义指令实现按钮级权限控制思路详解
2018/05/23 Javascript
vue采用EventBus实现跨组件通信及注意事项小结
2018/06/14 Javascript
Vue.js点击切换按钮改变内容的实例讲解
2018/08/22 Javascript
vue项目出现页面空白的解决方案
2019/10/31 Javascript
Python实现高效求解素数代码实例
2015/06/30 Python
python 3.5下xadmin的使用及修复源码bug
2017/05/10 Python
flask中使用蓝图将路由分开写在不同文件实例解析
2018/01/19 Python
Django数据库表反向生成实例解析
2018/02/06 Python
如何通过python的fabric包完成代码上传部署
2019/07/29 Python
详解numpy.meshgrid()方法使用
2019/08/01 Python
通过实例解析Python调用json模块
2019/12/11 Python
使用python把xmind转换成excel测试用例的实现代码
2020/10/12 Python
Python在centos7.6上安装python3.9的详细教程(默认python版本为2.7.5)
2020/10/15 Python
Python基于Serializer实现字段验证及序列化
2020/11/04 Python
基于css3 animate制作绚丽的动画效果
2015/11/24 HTML / CSS
整理HTML5移动端开发的常用触摸事件
2016/04/15 HTML / CSS
SQL Server提供的3种恢复模型都是什么? 有什么区别?
2012/05/13 面试题
装饰活动策划方案
2014/02/11 职场文书
临床专业自荐信
2014/06/22 职场文书
2014大学校园光棍节活动策划书
2014/09/29 职场文书