贪吃蛇游戏是一款经典的休闲游戏,许多人童年时都在各种电子设备上玩过。随着Web技术的发展,我们可以在浏览器中实现这个游戏。通过HTML和JavaScript,我们可以创建一个简单但功能齐全的贪吃蛇游戏。本文将详细介绍如何使用HTML和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贪吃蛇游戏
总结
在本文中,我们详细介绍了如何使用HTML和JavaScript实现贪吃蛇游戏。通过创建游戏界面、定义蛇的移动逻辑、处理用户输入以及添加食物和得分机制,我们成功地实现了一个基本的贪吃蛇游戏。希望这段代码和讲解能够帮助你理解如何在浏览器中创建和控制游戏元素,同时也激发你对Web开发的兴趣。无论是改进现有功能还是添加新功能,这个游戏都是一个很好的起点。快来试试吧!
本文来源于#CSDN,由@战地网 整理发布。如若内容造成侵权/违法违规/事实不符,请联系本站客服处理!
该文章观点仅代表作者本人,不代表本站立场。本站不承担相关法律责任。
如若转载,请注明出处:https://www.zhanid.com/biancheng/1348.html