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中 用户登录系统的解决办法
Apr 15 Javascript
JS控制图片翻转示例代码(兼容firefox,ie,chrome)
Dec 19 Javascript
指定区域的图片自动按比例缩小的js代码(防止页面被图片撑破)
Feb 21 Javascript
javascript对象的使用和属性操作示例详解
Mar 02 Javascript
jQuery中:empty选择器用法实例
Dec 30 Javascript
JS实现在页面随时自定义背景颜色的方法
Feb 27 Javascript
Vue.js开发环境搭建
Nov 10 Javascript
微信小程序的动画效果详解
Jan 18 Javascript
setTimeout函数的神奇使用
Feb 26 Javascript
Vue封装Axios请求和拦截器的步骤
Sep 16 Javascript
10分钟学会js处理json的常用方法
Dec 06 Javascript
原生JavaScript实现购物车
Jan 10 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
关于Blog顶部的滚动导航条代码
2006/09/25 Javascript
学习ExtJS accordion布局
2009/10/08 Javascript
jquery一句话全选/取消全选
2011/03/01 Javascript
jQuery学习笔记之jQuery.extend(),jQuery.fn.extend()分析
2014/06/09 Javascript
Javascript技术难点之apply,call与this之间的衔接
2015/12/04 Javascript
Node.js中JavaScript操作MySQL的常用方法整理
2016/03/01 Javascript
一起学写js Calender日历控件
2016/04/14 Javascript
Validform表单验证总结篇
2016/10/31 Javascript
js判断手机系统是android还是ios
2017/03/07 Javascript
原生js实现移动端触摸轮播的示例代码
2017/12/22 Javascript
理解 JavaScript EventEmitter
2018/03/29 Javascript
微信小程序自定义组件封装及父子间组件传值的方法
2018/08/28 Javascript
如何优雅地在vue中添加权限控制示例详解
2019/03/07 Javascript
微信小程序实现拍照画布指定区域生成图片
2019/07/18 Javascript
JS桶排序的简单理解与实现方法示例
2019/11/25 Javascript
[56:47]Ti4 循环赛第三日 iG vs Liquid
2014/07/12 DOTA
Python内置的HTTP协议服务器SimpleHTTPServer使用指南
2016/03/30 Python
centos6.4下python3.6.1安装教程
2017/07/21 Python
对python函数签名的方法详解
2019/01/22 Python
python3.6实现学生信息管理系统
2019/02/21 Python
如何用C代码给Python写扩展库(Cython)
2019/05/17 Python
Python selenium的基本使用方法分析
2019/12/21 Python
python每5分钟从kafka中提取数据的例子
2019/12/23 Python
基于Python的自媒体小助手---登录页面的实现代码
2020/06/29 Python
使用ITK-SNAP进行抠图操作并保存mask的实例
2020/07/01 Python
HTML高亮关键字的实现代码
2018/10/22 HTML / CSS
大学毕业的自我鉴定
2013/10/08 职场文书
开会迟到检讨书
2014/02/03 职场文书
产品质量保证书
2014/04/29 职场文书
团支部推优材料
2014/05/21 职场文书
司法所长先进事迹
2014/06/02 职场文书
“四风”问题自我剖析材料思想汇报
2014/09/23 职场文书
2014年医药代表工作总结
2014/11/22 职场文书
工程部文员岗位职责
2015/02/04 职场文书
小班下学期个人总结
2015/02/12 职场文书
电影雨中的树观后感
2015/06/15 职场文书