前言

为什么闲着没事要做一个2048呢?还不是360前端星计划(2018春招实习生)要我做的。然后就花了几天时间做了一个2048小游戏,兼容到pc端和部分移动端(设备有限,有的移动浏览器真的没兼容到或者是真的不想做兼容了)。仅供大家看看就好哈。

在线预览:http://47.94.199.75/index.html (这个网址暂时有效。。以后点进去不知道又是我的什么实验作品。)

游戏介绍

我做完给朋友看之后发现不是每个人都玩过这个游戏。简单介绍一下游戏内容好了。

获胜条件: 拼凑出一个2048方块

失败条件: 当前没有可用方块,并且所有方块都不可以和临近方块合并

代码结构

index.html:

游戏失败

再来一局

#bg为背景图,也就是空的灰色方块,因为方块移动的时候不能露出底下的空白

#main为实体,也就是游戏中我们看见的包含数字的方块

#alert为提示框,一开始display:none,当游戏胜利或者结束的时候,display:block

#alert span 失败消息或者胜利消息

css的话,主要是关于动画元素的设置:

base.css

#main .item {

transition: all .3s ease-out;

-moz-transition: all .3s ease-out; /* Firefox 4 */

-webkit-transition: all .3s ease-out; /* Safari 和 Chrome */

-o-transition: all .3s ease-out; /* Opera */

left: 0px;

top: 0px;

}

js的话主要是两块,util.js负责了一些外围函数(重要的是关于移动端滑动事件的封装)的处理,2048.js就是页面整体逻辑

util.js // 关于移动端滑动事件的封装

const touchManager = (function () {

let start = []

let end = []

let timeStamp = 0

let manager = {}

manager.touchstart = function (event) { // 记录下开始位置

event.stopPropagation()

timeStamp = event.timeStamp // 获取点击时的时间

let target = event.targetTouches[0]

start = [target.pageX, target.pageY]

end = [target.pageX, target.pageY]

console.log('start')

}

manager.touchmove = function (event) { // 记录下移动位置

event.stopPropagation()

event.preventDefault()

let target = event.targetTouches[0]

end = [target.pageX, target.pageY]

console.log('move')

}

manager.touchend = function (event) { // 处理开始位置和移动位置给出滑动方向

event.stopPropagation()

event.preventDefault()

const abs = Math.abs

let time = event.timeStamp - timeStamp // 获取滑动操作使用的时间

let moveX = end[0] - start[0]

let moveY = end[1] - start[1]

if (time > 500 || (abs(moveX) < 50 && abs(moveY) < 50)) { // 移动距离不够或时间太长就不认为是滑动

return false

} else {

if (abs(moveX) >= abs(moveY)) { // 横向移动距离较长

console.log(moveX)

return moveX > 0 ? 'right' : 'left'

} else { // 纵向移动距离较长

console.log(moveY)

return moveY > 0 ? 'down' : 'up'

}

}

}

return manager

})()

2048.js 主要由以下几个数据结构和函数构成:

数据结构:

let data = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]] // 初始化

let emptyList = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] // 当前没有元素的格子

const container = document.querySelector('#main') // 操作实体

const bg = document.querySelector('#bg') // 背景板

const alert = document.querySelector('#alert') // 提醒框

const alertText = alert.querySelector('span') // 提醒框里的文字容器

const baseSize = parseInt(getDomStyle(container).width) // 基础画板的size

let gameOver = false // 标志游戏是否结束

const animateTime = 300 // 单位ms, 动画时长

这个地方保存了大量dom元素的引用,为了以后操作的时候减少获取dom的性能消耗

另外还有以下几个函数:

main // 主程序

resize(el) // 调整元素宽高一致

createElement() // 在emptyList里找1-2个下标出来,给data添加新的元素,取值为{2, 4}

paint(el, data) // 用data在el里画出每一个格子

animate(move, arrow) // 传入一个移动队列,和移动方向‘left’代表横向,‘top’代表纵向

isWin(data) isLost(data, emptyList) // 判断游戏胜负

win() lost() // 显示胜负消息

replay() // 再来一局

moveHandle = {...} // 封装了计算移动结果的函数

然后再从主程序看函数的流程:

function main () { // 主程序

// 调整背景和实体宽高

resize(container)

resize(bg)

// 初始化背景和实体元素

paint(bg, data)

// 创建1-2个初始元素

createNewElement()

paint(container, data)

// 绑定事件监听器

addEvent(window, 'keydown', function (event) { // 按键监听

if (gameOver) {

return

}

let arrow = keyCodeMap[event.keyCode]

switch (arrow) {

case 'left':

case 'up':

case 'right':

case 'down': {

moveHandle.move(arrow)

break

}

}

})

addEvent(alert.querySelector('button'), 'click', replay) // 再玩一次

addEvent(container, 'touchstart', touchManager.touchstart)

addEvent(container, 'touchmove', touchManager.touchmove)

addEvent(container, 'touchend', function (event) {

let arrow = touchManager.touchend(event)

if (arrow) {

moveHandle.move(arrow)

}

})

}

也即是:1.初始化 2. 绑定事件监听

然后就是如何计算出移动结果,以下用一个左滑计算(moveHandle.moveleft)为例子

moveleft: function () { // 向左移动

// 计算移动后的data

// 要移动的元素的移动坐标

// 没有元素的格子

let newData = copy(data) // 获取当前数据的一个copy

let move = [] // 方块移动队列

emptyList = []

for (let i = 0; i < 4; i++) { // 一行行处理

let newList = [] // 新行

let oldList = data[i]

for (let j = 0; j < 4; j++) { // 找到所有非0单元

let value = newData[i][j]

if (value !== 0) {

newList.push(value)

}

}

if (newList.length > 1) { // 合并同类项

for (let j = 0, len = newList.length; j < len - 1; j++) {

if (newList[j] === newList[j + 1]) {

newList[j] *= 2

newList[j + 1] = 0

j++

}

}

newList = newList.filter(item => item !== 0) // 过滤掉上一步产生的0

}

for (let j = newList.length; j < 4; j++) { // 补全数列尾部的0

emptyList.push(i * 4 + j)

newList.push(0)

}

newData[i] = newList

// 产生每位元素移动的坐标

for (let j = 0, k = 0,tag = false; j < 4; j++) { // j为旧元素位置,k为移动到的位置

if (newList[k] === 0) { // 如果没有要移动的位置了

break

} else if (oldList[j] === newList[k]) { // j移动到k位置

if (j !== k) {

move.push({

start: [i, j],

end: [i, k]

})

}

k++

} else if (oldList[j] === newList[k] / 2) { // 两个元素合成k位置的元素

move.push({

start: [i, j],

end: [i, k]

})

if (tag) {

k++

}

tag = !tag

}

}

}

return {

newData: newData,

move: move

}

}

这个函数最后产出的是 newData 计算后的 data, move 方块的移动队列,形如[{start: [x1, y1], end: [x2, y2]}, ... ]

然后怎么利用这个计算结果呢,看moveHandle.move.(moveHandle中有三个私有变量,moving锁定句柄,防止动画过程中用户再次滑动,win是否胜利,lost时候失败)

move: function (arrow) { // arrow = 移动方向

if (this.moving) { // 如果正在进行动画,返回移动失败

return false

}

let result = this['move' + arrow]() // 获取移动计算后的结果

let newData = result.newData // 移动后的数据矩阵

let move = result.move // 移动元素列表

// 根据移动元素列表判断该操作是否有效

if (move.length === 0) { // 没有可以移动的元素,则无效

console.log('本次移动无效')

return false

}

// 进行0.3秒动画

data = newData // 修改全局数据矩阵

createNewElement() // 创造新元素

// 判断游戏胜负

this.win = isWin(newData)

if (!this.win) {

this.lost = isLost(newData, emptyList)

}

this.moving = true // 锁定该事件句柄

setTimeout((function (self) {

animate(move, arrow)

return function () {

// 足够时间后

self.moving = false // 终止动画

paint(container, data) // 重绘视图

// 判断游戏胜负

if (self.win) { // 赢得了游戏

win()

} else if (self.lost) {

lost()

}

}

})(this), animateTime)

}

我自认为我的注释内容还是挺多的,应该还是能看懂。这次分享就到这了。欢迎评论区留言讨论。发现有什么bug也尽可能跟我说把。

BUG

目前已知的是:

1.微信内置浏览器的转码问题:

这个因为我懒得整一个域名,所以它为了安全就会进行转码,没法游戏。也就不修复了。。只是个小玩具。

2.ios长按会选取文字而且无法取消:

这个问题我已经做了一定的修复,但是我没复现这个问题的方法,也没再处理

3.夸克浏览器自带手势导致左滑右滑会进行系统行为:

没想到办法,如果有人有办法请告诉我,谢谢。

2048+html源码之家,前端纯原生代码实现2048相关推荐

  1. java2048小游戏源码及解析_200行java代码实现2048小游戏

    本文实例为大家分享了java实现2048小游戏的具体代码,供大家参考,具体内容如下 效果图: 游戏介绍: 1.2048是一款益智类小游戏,刚开始随机出现两个数字,可以上下左右控制数字的移动. 2.当选 ...

  2. Unity初级教程2048附带源码及插件(400行代码1个脚本UI实现)

    * 完整代码传送门 此次用到的Unity插件地址Unity3dAsyncAwaitUtil GitHub,如果使用async-await时仍然报错,请把.net standard 2.0转换为.net ...

  3. 源码之家(源代码下载分享)

    优秀网站源码.编程源码下载网站大集中 1.51源码:51Aspx源码服务专家|- 51Aspx.com 2.源码之家:源码之家_网页源码|网站源码|ASP源码|PHP源码|JSP源码|HTML源码|网 ...

  4. 个人免费可访问网页制作【GitHub】及其二维码制作(需要有网页源码)——论前端的浪漫

    个人免费可访问网页制作[GitHub]及其二维码制作(需要有网页源码)--论前端的浪漫 创建GitHub仓库 上传网页源码资源 更改repository 名字 二维码制作 源码修改 结尾 今天发现一个 ...

  5. 单片机 stm32 差分升级 增量升级算法源码,提供移植 纯c编写跨平因为是程序源码

    单片机 stm32 差分升级 增量升级算法源码,提供移植 纯c编写跨平因为是程序源码 IAP升级 OTA升级 物联网 车联网 适用 YID:83500653978935134Deflag

  6. 文案微信小程序源码独立版+前端

    文案微信小程序源码文案+头像+背景图 api接口是别人的,毕竟自己采集资源比较难 后台程序没有首页,只需要安装即用 后台账户:admin/123456 小程序源码下载地址: 文案微信小程序源码独立版+ ...

  7. 源码之家(很多源代码下载)

    优秀网站源码.编程源码下载网站大集中 1.51源码:http://www.51aspx.com/ 2.源码之家:http://www.codejia.com/ 3.源码网:http://www.cod ...

  8. (已更新)文案微信小程序源码独立版+前端

    文案威信小程序源码文案+头像+背景图 api接口是别人的,毕竟自己采集资源比较难 后台程序没有首页,只需要安装即用 后台账户:admin/123456 小程序源码下载地址:(已更新)文案微信小程序源码 ...

  9. 最新版基于TP开发的9国语言海外多语言抢单源码+9色前端UI

    demo软件园每日更新资源,请看到最后就能获取你想要的: 1.最新版基于TP开发的9国语言海外多语言抢单源码+9色前端UI 今天没事测试了一下这套源码,基本没什么大问题,只是需要自己设置一下伪静态和选 ...

  10. Thinkphp开发微信商城小程序源码拼团小程序源码带后台+前端小程序拼团源码仿拼多多

    码说明:Thinkphp开发微信商城小程序源码拼团小程序源码带后台+前端小程序拼团源码仿拼多多 其它说明: 基于小程序的拼团应用,用户可通过拼团,随时发起拼团活动并分享给好友 拼团是商品营销和售卖的一 ...

最新文章

  1. python 装饰器 参数-python函数装饰器之带参数的函数和带参数的装饰器用法示例...
  2. TypePerf收集服务器性能
  3. 洛谷 4364 [九省联考2018]IIIDX——“预留”的思路
  4. The Preliminary Contest for ICPC Asia Nanjing 2019 B. super_log (广义欧拉降幂)
  5. HttpServletRequest中getAttribute()和getParameter()的区别
  6. c语言实现图片卷积_卷积神经网络(CNN)Python的底层实现——以LeNet为例
  7. Adobe Indesign怎么让图片衬于文字下方?
  8. 转Java 开发环境配置
  9. 宗成庆统计自然语言处理第二版第13章读书笔记-文本分类与情感分类
  10. Android小程序白屏,微信小程序web-view跳转h5 安卓白屏
  11. 小米android11账号补丁,小米10 MIUI11 解账户锁 可登小米账号 永不反锁 完美ROOT 解锁包...
  12. 基于模块化多电平换流器(MMC)的柔性直流输电系统simulink仿真模型开发
  13. CC2540蓝牙开发一BLE例程
  14. 如何使用PDF编辑器中文版删除PDF页码
  15. C# Excel绘制组合图
  16. c++ 的interface
  17. 【良心推荐】国内适合中小企业、团队的十大协同办公系统
  18. Oracle数据库表的字段添加注释和向现有表添加字段
  19. MapReduce论文中文版--The Google File System
  20. C++ accumulate函数介绍、具体案例

热门文章

  1. dosbox运行C语言,DOSBox-DOS模拟器-DOSBox下载 v0.74官方版-完美下载
  2. python短期电力预测——基于LSTM神经网络
  3. 【macOS】Desktop桌面文件突然消失不见解决办法
  4. KALI应用篇(一)压力测试
  5. Java的API帮助文档
  6. gmssl java api_关于GmSSL Java API编译
  7. Chrome浏览器去广告插件 —— (Adblock Plus)
  8. 大数据技术原理与应用-林子雨课后(部分习题答案)
  9. UVC协议学习2--UVC请求格式分析
  10. 做计算机二级的技巧,2016全国计算机二级考试应试技巧