Web前端学习笔记——JavaScript之面向对象游戏案例:贪吃蛇
面向对象游戏案例:贪吃蛇
案例相关源码以上传到 GitHub :https://github.com/lipengzhou/new-snake
案例介绍
游戏演示
在线演示地址:贪吃蛇
案例目标
游戏的目的是用来体会js高级语法的使用 不需要具备抽象对象的能力,使用面向对象的方式分析问题,需要一个漫长的过程。
功能实现
搭建页面
放一个容器盛放游戏场景 div#map,设置样式
#map {width: 800px;height: 600px;background-color: #ccc;position: relative;
}
分析对象
- 游戏对象
- 蛇对象
- 食物对象
创建食物对象
Food
属性
- x
- y
- width
- height
- color
方法
- render 随机创建一个食物对象,并输出到map上
创建Food的构造函数,并设置属性
var position = 'absolute';
var elements = [];
function Food(x, y, width, height, color) {this.x = x || 0;this.y = y || 0;// 食物的宽度和高度(像素)this.width = width || 20;this.height = height || 20;// 食物的颜色this.color = color || 'green';
}
- 通过原型设置render方法,实现随机产生食物对象,并渲染到map上
Food.prototype.render = function (map) {// 随机食物的位置,map.宽度/food.宽度,总共有多少分food的宽度,随机一下。然后再乘以food的宽度this.x = parseInt(Math.random() * map.offsetWidth / this.width) * this.width;this.y = parseInt(Math.random() * map.offsetHeight / this.height) * this.height;// 动态创建食物对应的divvar div = document.createElement('div');map.appendChild(div);div.style.position = position;div.style.left = this.x + 'px';div.style.top = this.y + 'px';div.style.width = this.width + 'px';div.style.height = this.height + 'px';div.style.backgroundColor = this.color;elements.push(div);
}
- 通过自调用函数,进行封装,通过window暴露Food对象
window.Food = Food;
创建蛇对象
Snake
属性
- width 蛇节的宽度 默认20
- height 蛇节的高度 默认20
- body 数组,蛇的头部和身体,第一个位置是蛇头
- direction 蛇运动的方向 默认right 可以是 left top bottom
方法
- render 把蛇渲染到map上
Snake构造函数
var position = 'absolute';
var elements = [];
function Snake(width, height, direction) {// 设置每一个蛇节的宽度this.width = width || 20;this.height = height || 20;// 蛇的每一部分, 第一部分是蛇头this.body = [{x: 3, y: 2, color: 'red'},{x: 2, y: 2, color: 'red'},{x: 1, y: 2, color: 'red'}];this.direction = direction || 'right';
}
- render方法
Snake.prototype.render = function(map) {for(var i = 0; i < this.body.length; i++) {var obj = this.body[i];var div = document.createElement('div');map.appendChild(div);div.style.left = obj.x * this.width + 'px';div.style.top = obj.y * this.height + 'px';div.style.position = position;div.style.backgroundColor = obj.color;div.style.width = this.width + 'px';div.style.height = this.height + 'px';}
}
- 在自调用函数中暴露Snake对象
window.Snake = Snake;
创建游戏对象
游戏对象,用来管理游戏中的所有对象和开始游戏
Game
属性
food
snake
map
方法
- start 开始游戏(绘制所有游戏对象)
构造函数
function Game(map) {this.food = new Food();this.snake = new Snake();this.map = map;
}
- 开始游戏,渲染食物对象和蛇对象
Game.prototype.start = function () {this.food.render(this.map);this.snake.render(this.map);
}
游戏的逻辑
写蛇的move方法
- 在蛇对象(snake.js)中,在Snake的原型上新增move方法
- 让蛇移动起来,把蛇身体的每一部分往前移动一下
- 蛇头部分根据不同的方向决定 往哪里移动
Snake.prototype.move = function (food, map) {// 让蛇身体的每一部分往前移动一下var i = this.body.length - 1;for(; i > 0; i--) {this.body[i].x = this.body[i - 1].x;this.body[i].y = this.body[i - 1].y;}// 根据移动的方向,决定蛇头如何处理switch(this.direction) {case 'left': this.body[0].x -= 1;break;case 'right':this.body[0].x += 1;break;case 'top':this.body[0].y -= 1;break;case 'bottom':this.body[0].y += 1;break;}
}
- 在game中测试
this.snake.move(this.food, this.map);
this.snake.render(this.map);
让蛇自己动起来
私有方法
什么是私有方法?不能被外部访问的方法 如何创建私有方法?使用自调用函数包裹
在game.js中 添加runSnake的私有方法,开启定时器调用蛇的move和render方法,让蛇动起来
判断蛇是否撞墙
function runSnake() {var timerId = setInterval(function() {this.snake.move(this.food, this.map);// 在渲染前,删除之前的蛇this.snake.render(this.map);// 判断蛇是否撞墙var maxX = this.map.offsetWidth / this.snake.width;var maxY = this.map.offsetHeight / this.snake.height;var headX = this.snake.body[0].x;var headY = this.snake.body[0].y;if (headX < 0 || headX >= maxX) {clearInterval(timerId);alert('Game Over');}if (headY < 0 || headY >= maxY) {clearInterval(timerId);alert('Game Over');}}.bind(that), 150);
}
- 在snake中添加删除蛇的私有方法,在render中调用
function remove() {// 删除渲染的蛇var i = elements.length - 1;for(; i >= 0; i--) {// 删除页面上渲染的蛇elements[i].parentNode.removeChild(elements[i]);// 删除elements数组中的元素elements.splice(i, 1);}
}
- 在game中通过键盘控制蛇的移动方向
function bindKey() {document.addEventListener('keydown', function(e) {switch (e.keyCode) {case 37:// leftthis.snake.direction = 'left';break;case 38:// topthis.snake.direction = 'top';break;case 39:// rightthis.snake.direction = 'right';break;case 40:// bottomthis.snake.direction = 'bottom';break;}}.bind(that), false);
}
- 在start方法中调用
bindKey();
判断蛇是否吃到食物
// 在Snake的move方法中// 在移动的过程中判断蛇是否吃到食物
// 如果蛇头和食物的位置重合代表吃到食物
// 食物的坐标是像素,蛇的坐标是几个宽度,进行转换
var headX = this.body[0].x * this.width;
var headY = this.body[0].y * this.height;
if (headX === food.x && headY === food.y) {// 吃到食物,往蛇节的最后加一节var last = this.body[this.body.length - 1];this.body.push({x: last.x,y: last.y,color: last.color})// 把现在的食物对象删除,并重新随机渲染一个食物对象food.render(map);
}
其它处理
把html中的js代码放到index.js中
避免html中出现js代码
自调用函数的参数
(function (window, undefined) {var document = window.document;}(window, undefined))
- 传入window对象
将来代码压缩的时候,可以吧 function (window) 压缩成 function (w)
- 传入undefined
在将来会看到别人写的代码中会把undefined作为函数的参数(当前案例没有使用)
因为在有的老版本的浏览器中 undefined可以被重新赋值,防止undefined 被重新赋值
整理代码
现在的代码结构清晰,谁出问题就找到对应的js文件即可。
通过自调用函数,已经防止了变量命名污染的问题
但是,由于js文件数较多,需要在页面上引用,会产生文件依赖的问题(先引入那个js,再引入哪个js)
将来通过工具把js文件合并并压缩。现在手工合并js文件演示
- 问题1
// 如果存在多个自调用函数要用分号分割,否则语法错误
// 下面代码会报错
(function () {}())(function () {}())
// 所以代码规范中会建议在自调用函数之前加上分号
// 下面代码没有问题
;(function () {}());(function () {}())
- 问题2
// 当自调用函数 前面有函数声明时,会把自调用函数作为参数
// 所以建议自调用函数前,加上;
var a = function () {alert('11');
}(function () {alert('22');
}())
Web前端学习笔记——JavaScript之面向对象游戏案例:贪吃蛇相关推荐
- Web前端学习笔记——JavaScript之WEBAPI、BOM、DOM及获取页面元素
Web API介绍 API的概念 API(Application Programming Interface,应用程序编程接口)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访 ...
- Web前端学习笔记——JavaScript之数组、函数、作用域
数组 为什么要学习数组 之前学习的数据类型,只能存储一个值(比如:Number/String.我们想存储班级中所有学生的姓名,此时该如何存储? 数组的概念 所谓数组,就是将多个元素(通常是同一类型)按 ...
- Web前端学习笔记——AngularJS之豆瓣电影案例
step-01 构建项目结构 克隆项目骨架 bash $ git clone --depth=1 https://github.com/Micua/angular-boilerplate.git mo ...
- web前端学习笔记(最新)
web前端学习笔记 大家好,我是链表哥,新的学期,新的学习,我会为您展示我的学习进程. 一:什么是WEB前端? 所谓的Web前端指的是用户所能接触到的,并服务于用户的前沿端口,经我们程序员编辑修饰后展 ...
- 零基础web前端学习之JavaScript 和css 阻塞
web前端学习之JavaScript 和css 阻塞,JavaScript 是客户端和服务器端的脚本语言,可以插入HTML 页函中, 并且是目前较热门的Web 开发语言.同时, JavaScript ...
- web前端学习笔记之JavaScript
文章目录 1 JavaScript简介 2 JS基础 3 JS代码编写位置 3.1 行内式 3.2 内嵌式 3.3 外联式 4 基本语法 5 字面量和变量 5.1 字面量 5.2 变量 6 标识符 7 ...
- 前端学习笔记——JavaScript进阶
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一.JavaScript 面向对象 1. 面向对象编程介绍 1.1 两大编程思想 1.2 面向过程编程 1.3 面向对 ...
- Web前端学习笔记(1)
文章目录 一.第一部分 1.1内容一 Web前端导入 二.第二部分 2.1内容一 HTML和CSS的定义 三.第三部分 3.1内容一 宇宙第一编译器Vs Code 3.2内容二 快捷键的使用 四.第四 ...
- 重学前端-学习笔记-JavaScript对象
说明 重学前端是程劭非(winter)在极客时间开的一个专栏,在此主要整理我的学习笔记.如有侵权,请联系我,谢谢. javascript对象特征 对象具有唯一标识性:完全相同的两个对象,也不是同一个对 ...
最新文章
- 2021-07-27查看图像像素值类别
- MySql按周,按月,按日分组统计数据
- (六)观察者模式详解(包含观察者模式JDK的漏洞以及事件驱动模型)决了当时的问题,那时LZ接触JAVA刚几个月,比葫芦画瓢的用了观察者模式。...
- matlab中如何求零极点,Matlab中绘制零极点
- python实现logistic_用Python实现机器学习算法—Logistic 回归算法
- cmd查看python安装路径-从cmd如何查找python的安装路径?
- java 打印一棵树_java编程题之从上往下打印出二叉树
- SQL_CALC_FOUND_ROWS的用法
- el-table 树形表格 自定义展开图标_实践一个树形组件
- uva 674 Coin Change 换钱币【完全背包】
- 社区团购还是两看,从消极这个角度
- 常用Docker 镜像命令(二)
- [ACNOI2021]OEIS yyds
- mac制作ubuntu 18.04 U盘启动盘
- excel粘贴时出现故障_你必将碰到的巨崩溃的问题,Excel复制粘贴时,突然提示“不同单元格格式太多“,我快疯了......
- 亚马逊Dash永久下架:智能购物按钮究竟犯了什么错?
- js中将从ajax获得的时间戳数字串转换成理解的时间格式
- 官方解释:Windows Vista和OpenGL
- Java数组实现:一群人围成一圈从123报数 如果报到3就退出该圈中 直到最后一个人留下来!问其位置
- 计算机网络自顶向下方法笔记02
热门文章
- python 数字运算及格式化_Python基础教程(3)Python数据类型、运算与格式化
- 文件被占用无法删除,解决办法
- [css] css 3d 动画,跟随鼠标移动做球形旋转
- 数据传输性能与安全不能兼顾?Rambus安全方案“动静”两相宜
- html框架自动居中,html 宽度固定并布局居中模板框架
- 解决ubuntu18.04打不开网易云音乐(亲测可行!
- android开发中磁场传感器,Android开发获取传感器数据的方法示例【加速度传感器,磁场传感器,光线传感器,方向传感器】...
- 红米手机5获取Root超级权限的步骤
- win10配置Sublime Text 3作为latex的编辑器
- Qgis的下载安装(Qgis3.16.12)