jQuery实践-网页版2048小游戏
▓▓▓▓▓▓ 大致介绍
看了一个实现网页版2048小游戏的视频,觉得能做出自己以前喜欢玩的小游戏很有意思便自己动手试了试,真正的验证了这句话-不要以为你以为的就是你以为的,看视频时觉得看懂了,会写了,但是自己实现起来会遇到各种问题。比如,在最后判断游戏是否结束的时候,我写的语句语法是对的,但就是不执行。最后通过对视频源码的分析对比,发现原作者写的一个setTimeout定时器有额外的意思,本来我以为它就是简单的一个延时动画,其实他是在等待另外一个函数执行完毕。-_-||。最后还是很高兴能写出来,也改进了一些源代码的不足。
jQuery在这个游戏中的应用并不多,如果对其中的jQuery语法有疑问,可以参考我写的jQuery学习之路(持续更新),里面有讲解
预览:2048网页版
这篇博客并不是详细的讲解,只是大致介绍函数的作用,其中实现的细节注释中有解释,网上的这个源码有点乱,如果想看比较整齐的源码或者视频的可以QQ联系我(免费)(找共同学习的伙伴)
▓▓▓▓▓▓ 思路
这个小游戏可以抽象化分为3层(我觉得这样能更好理解)
◆最底下的一层是基本的样式(可见的)
◆中间的层是最主要的,是一个4x4的二维数组,游戏中我们都是对这个二维数组进行操作(不可见的)
◆最上面的一层也是一个4x4的二维数组,它只是根据第二层数组的每个数显示样式(可见的)
我们通过最底下的一层显示最基本的16个小方格,通过键盘的按键或者手指在屏幕的滑动来操作中间层的数组,最后在通过最上面的一层显示出数字
▓▓▓▓▓▓ 基本结构与样式
基本的结构和样式都挺简单,直接看代码
结构:
<div id="test2048">
<div id="header">
<h1>2048</h1>
<a href="javascript:newgame()" >开始新的游戏</a>
<p>分数:<span id="score">0</span></p>
</div>
<div id="container">
<div class="cell" id="cell-0-0"></div>
<div class="cell" id="cell-0-1"></div>
<div class="cell" id="cell-0-2"></div>
<div class="cell" id="cell-0-3"></div>
<div class="cell" id="cell-1-0"></div>
<div class="cell" id="cell-1-1"></div>
<div class="cell" id="cell-1-2"></div>
<div class="cell" id="cell-1-3"></div>
<div class="cell" id="cell-2-0"></div>
<div class="cell" id="cell-2-1"></div>
<div class="cell" id="cell-2-2"></div>
<div class="cell" id="cell-2-3"></div>
<div class="cell" id="cell-3-0"></div>
<div class="cell" id="cell-3-1"></div>
<div class="cell" id="cell-3-2"></div>
<div class="cell" id="cell-3-3"></div>
</div>
</div>
样式:
*{
margin:;
padding:;
}
#test2048{
font-family: Arial;
margin: 0 auto;
text-align: center;
}
#header{
margin: 20px;
}
#header a{
font-family: Arial;
text-decoration: none;
display: block;
color: white;
margin: 20px auto;
width: 125px;
height: 35px;
text-align: center;
line-height: 40px;
background-color: #8f7a66;
border-radius: 10px;
font-size: 15px;
}
#header p{
font-family: Arial;
font-size: 20px;
}
#container{
width: 460px;
height: 460px;
background-color: #bbada0;
margin: 0 auto;
border-radius: 10px;
position: relative;
padding: 20px;
}
.cell{
width: 100px;
height: 100px;
border-radius: 6px;
background-color: #ccc0b3;
position: absolute;
}
CSS样式
从CSS样式可以看出,我们并没有对每个格子的位置进行设置,因为如果用CSS给每个格子设置样式代码量太大,而且他们的位置有一定的规律,所以我们可以用js循环来完成每个格子样式的设置
代码:
// 初始化棋盘格
function initialize(){
for(var i=0;i<4;i++){
for(var j=0;j<4;j++){
// 设置棋盘格的位置
var everyCell = $('#cell-'+ i +'-'+ j);
everyCell.css({top:getPos(i),left:getPos(j)});
}
}
}
// 获取位置
function getPos(num){
return 20 + num*120;
}
这样我们的第一层就好了
效果:
现在构造第二层,即构建一个4x4的值全部为0的数组,由于在构造第二层时,有两层循环,所以我们可以在构造第一层时也能构造第二层
第三层是用js生成16个格子,它和第一层的16个格子一一对应
代码:
// 数字格
function numFormat(){
for(var i=0;i<4;i++){
for(var j=0;j<4;j++){
$('#container').append('<div class="number" id="number-'+ i +'-'+ j +'"></div>') // 设置数字格的位置,样式
var everyNumber = $('#number-'+ i +'-'+ j);
if(checkerboard[i][j] == 0){
everyNumber.css({
width:'0px',
height:'0px',
top:getPos(i) + 50,
left:getPos(j) + 50
})
}else{
everyNumber.css({
width:'100px',
height:'100px',
top:getPos(i),
left:getPos(j),
backgroundColor:getBackgroundColor(checkerboard[i][j]),
color:getColor(checkerboard[i][j])
});
everyNumber.text(checkerboard[i][j]);
}
}
}
}
// 获取相应数字的背景颜色
function getBackgroundColor(number){ switch (number) {
case 2:return "#eee4da";break;
case 4:return "#ede0c8";break;
case 8:return "#f2b179";break;
case 16:return "#f59563";break;
case 32:return "#f67c5f";break;
case 64:return "#f65e3b";break;
case 128:return "#edcf72";break;
case 256:return "#edcc61";break;
case 512:return "#9c0";break;
case 1024:return "#33b5e5";break;
case 2048:return "#09c";break;
case 4096:return "#a6c";break;
case 8192:return "#93c";break;
}
}
// 设置相应数字的文字颜色
function getColor(number){
if (number <= 4) {
return "#776e65"
}
return "white";
}
▓▓▓▓▓▓ 初始化
在每次游戏重新开始时,都会在随机的位置出现两个随机的数字,我们写一个在随机位置出现一个随机数的函数,只要调用两次就可以实现了
代码:
// 随机的在一个位置上产生一个数字
function randomNum(){
// 随机产生一个坐标值
var randomX = Math.floor(Math.random() * 4);
var randomY = Math.floor(Math.random() * 4); // 随机产生一个数字(2或4)
var randomValue = Math.random() > 0.5 ? 2 : 4; // 在数字格不为0的地方生成一个随机数字
while(true){
if(checkerboard[randomX][randomY] == 0){
break;
}else{ var randomX = Math.floor(Math.random() * 4);
var randomY = Math.floor(Math.random() * 4);
}
} // 将随机产生的数字显示在随机的位置上
checkerboard[randomX][randomY] = randomValue; // 动画
randomNumAnimate(randomX,randomY,randomValue);
}
// 随机产生数字的动画
function randomNumAnimate(randomX,randomY,randomValue){
var randomnum = $('#number-'+ randomX +'-'+ randomY);
randomnum.css({
backgroundColor:getBackgroundColor(randomValue),
color:getColor(randomValue),
})
.text(randomValue)
.animate({
width:'100px',
height:'100px',
top:getPos(randomX),
left:getPos(randomY)
},50);
}
▓▓▓▓▓▓ 基本操作
我们通过switch循环,来根据用户不同的输入进行不同的操作
代码:
// 获取键盘事件,检测不同的按键进行不同的操作
$(document).keydown(function(event){
switch(event.keyCode){
case 37://左
if(canMoveLeft(checkerboard)){
// 如果可以向左移动 MoveLeft();
// 向左移动 setTimeout(function(){
randomNum();
},200);
// 随机产生一个数字
}
break;
case 38://上
if(canMoveUp(checkerboard)){
// 如果可以向上移动 MoveUp();
// 向上移动 setTimeout(function(){
randomNum();
},200);
// 随机产生一个数字
}
break;
case 39://右
if(canMoveRight(checkerboard)){
// 如果可以向右移动 MoveRight();
// 向右移动 setTimeout(function(){
randomNum();
},200);
// 随机产生一个数字
}
break;
case 40://下
if(canMoveDown(checkerboard)){
// 如果可以向下移动 MoveDown();
// 向下移动 setTimeout(function(){
randomNum();
},200);
// 随机产生一个数字
}
break;
default:
break;
}
});
由于数字格的移动只有左、上、右、下四种方式,并且他们都是大同小异的,所以就拿向左移动为例,
向左移动,我们首先需要判断它是否能向左移动,能向左移动有两种情况
第一种:当前格子的左边的格子是空的即值为0
第二种:当前格子的值和左边格子的值相同
由于向左移动,所以第一列的格子不可能向左移动,所以不需要判断
代码:
// 判断是否可以向左移动
function canMoveLeft(checkerboard){
for(var i=0;i<4;i++){
for(var j=1;j<4;j++){
if(checkerboard[i][j] != 0){
// 如果这个数字格它左边的数字格为空或者左边的数字格和它相等,则可以向左移动
if(checkerboard[i][j-1] == 0 || checkerboard[i][j] == checkerboard[i][j-1]){
return true;
}
}
}
}
return false;
}
判断能否向左移动后,我们就要对可以移动的格子进行移动,这里需要特别注意,向哪个方向移动就要先从哪个方向开始判断
代码:
// 向左移动
function MoveLeft(){
for(var i=0;i<4;i++){
for(var j=1;j<4;j++){
if(checkerboard[i][j] != 0){
for(var k=0;k<j;k++){
if(checkerboard[i][k] == 0 && noMiddleNumRow(i,k,j,checkerboard)){
moveAnimation(i,j,i,k);
checkerboard[i][k] = checkerboard[i][j];
checkerboard[i][j] = 0;
}else if(checkerboard[i][k] == checkerboard[i][j] && noMiddleNumRow(i,k,j,checkerboard) && !hasConflicted[i][k]){
moveAnimation(i,j,i,k);
checkerboard[i][k] += checkerboard[i][j];
checkerboard[i][j] = 0; }
}
}
}
}
// 设置刷新的时间是为了让运动的动画走完在进行更新数字格,否则数字格运动的动画将会被打断
setTimeout(function(){
numFormat();
},200);
}
// 判断中间的数字格是否为0(行)
function noMiddleNumRow(row,col1,col2,checkerboard){
for(var i=col1+1;i<col2;i++){
if(checkerboard[row][i] != 0){
return false;
}
}
return true;
}
将上、右、下四个方向写完以后,游戏基本的操作就已经完成了。
▓▓▓▓▓▓ 游戏分数和判断游戏结束
游戏的分数是每个相加的数的和,所以我们在每个数相加的时候更新分数就可以了
代码:
// 更新分数
score += checkerboard[k][j];
updateScore(score);
// 设置分数
function updateScore(num){
$('#score').text(num);
}
判断游戏是否结束很简单,用我们之前定义的方法就可以实现
代码:
// 判断游戏是否结束
function wheGameOver(checkerboard){
if(!canMoveLeft(checkerboard) && !canMoveUp(checkerboard) && !canMoveRight(checkerboard) && !canMoveDown(checkerboard) ){
showGameOver();
}
}
// 显示游戏结束
function showGameOver(){
$('#container').append("<div id='gameover'><p>最终得分</p><span>"+ score +"</span><a href='javascript:resert();'>重新开始游戏</a></div> ")
} // 重新开始游戏
function resert(){
$('#gameover').remove();
newgame();
}
▓▓▓▓▓▓ 最后优化
1、游戏中会出现一次移动,一个数会被累加很多次
在原游戏中,每个数在每次操作中只能累加一次,所以我们在定义一个4x4的值为false的数组,与中间层的数组一一对应,专门用来防止一个数的多次累加,如果是false则可以累加,并将值改为false,否则不可以累加
2、结束死循环
由于在设置随机数的时候用到了一个死循环,但是在游戏结束后,该循环还在,所以我们在死循环中在添加一个条件,如果游戏结束就跳出循环
3、最后的结束游戏提示不执行
case 37://左
if(canMoveLeft(checkerboard)){
// 如果可以向左移动 MoveLeft();
// 向左移动 setTimeout(function(){
wheGameOver(checkerboard)
},300);
// 判断游戏是否结束,这里设置延时是因为要等到随机产生数字后再进行判断,如果不加
// 延时,则最后一次的判断因为canMoveLeft(checkerboard)为false就不会再执行了 setTimeout(function(){
randomNum();
},200);
// 随机产生一个数字
}
break;
从代码中可以看出,判断游戏是否结束是在随机产生一个数字前执行的,所以在判断游戏结束时,总是有一个空的格子,所以代码执行后认为游戏没有结束,但是当这个随机数字产生后,所有的格子不能移动,当我们按键时,if条件不通过,判断游戏是否结束的函数不能执行。所以我们要给判断游戏结束的函数设置定时器,让他在随机产生一个数字后再进行判断
4、在移动端可以执行
由于原作者没有写有关移动端的操作,所以我在网上找的判断移动端触屏手机滑动位置的代码,加入了游戏的事件就可以执行了
//返回角度
function GetSlideAngle(dx, dy) {
return Math.atan2(dy, dx) * 180 / Math.PI;
} //根据起点和终点返回方向 1:向上,2:向下,3:向左,4:向右,0:未滑动
function GetSlideDirection(startX, startY, endX, endY) {
var dy = startY - endY;
var dx = endX - startX;
varresult = 0; //如果滑动距离太短
if(Math.abs(dx) < 2 && Math.abs(dy) < 2) {
returnresult;
} var angle = GetSlideAngle(dx, dy);
if(angle >= -45 && angle < 45) {
result = 4;
}else if (angle >= 45 && angle < 135) {
result = 1;
}else if (angle >= -135 && angle < -45) {
result = 2;
}
else if ((angle >= 135 && angle <= 180) || (angle >= -180 && angle < -135)) {
result = 3;
} return result;
} //滑动处理
var startX, startY;
document.addEventListener('touchstart',function (ev) {
startX = ev.touches[0].pageX;
startY = ev.touches[0].pageY;
}, false);
document.addEventListener('touchend',function (ev) {
var endX, endY;
endX = ev.changedTouches[0].pageX;
endY = ev.changedTouches[0].pageY;
var direction = GetSlideDirection(startX, startY, endX, endY);
switch(direction) {
case 0:
//没滑动
break;
case 1:
if(canMoveUp(checkerboard)){
// 如果可以向上移动 MoveUp();
// 向上移动 setTimeout(function(){
wheGameOver(checkerboard)
},300);
// 判断游戏是否结束 setTimeout(function(){
randomNum();
},200);
// 随机产生一个数字
}
break;
case 2:
if(canMoveDown(checkerboard)){
// 如果可以向下移动 MoveDown();
// 向下移动 setTimeout(function(){
wheGameOver(checkerboard)
},300);
// 判断游戏是否结束 setTimeout(function(){
randomNum();
},200);
// 随机产生一个数字
}
break;
case 3:
if(canMoveLeft(checkerboard)){
// 如果可以向左移动 MoveLeft();
// 向左移动 setTimeout(function(){
wheGameOver(checkerboard)
},300);
// 判断游戏是否结束,这里设置延时是因为要等到随机产生数字后再进行判断,如果不加
// 延时,则最后一次的判断因为canMoveLeft(checkerboard)为false就不会再执行了 setTimeout(function(){
randomNum();
},200);
// 随机产生一个数字
}
break;
case 4:
if(canMoveRight(checkerboard)){
// 如果可以向右移动 MoveRight();
// 向右移动 setTimeout(function(){
wheGameOver(checkerboard)
},300);
// 判断游戏是否结束 setTimeout(function(){
randomNum();
},200);
// 随机产生一个数字
}
break;
default:
}
}, false);
▓▓▓▓▓▓ 总结
总体来说这个游戏实现起来并不是太难,就是许多小的操作集合起来
如果想看视频或者源码请QQ联系我
jQuery实践-网页版2048小游戏的更多相关文章
- c#撸的控制台版2048小游戏
1.分析 最近心血来潮,突然想写一个2048小游戏.于是搜索了一个在线2048玩玩,熟悉熟悉规则. 只谈核心规则:(以左移为例) 1.1合并 以行为单位,忽略0位,每列依次向左进行合并,且每列只能合并 ...
- jQuery网页版五子棋小游戏源码下载
体验效果:http://hovertree.com/texiao/game/4/ 网页五子棋源代码: <!DOCTYPE html> <html> <head> & ...
- 基于jQuery的2048小游戏设计(网页版)
上周模仿一个2048小游戏,总结一下自己在编写代码的时候遇到的一些坑. 游戏规则:省略,我想大部分人都玩过,不写了 源码地址:https://github.com/xinhua6/2048game.g ...
- js、jQuery实现2048小游戏
2048小游戏 一.游戏简介: 2048是一款休闲益智类的数字叠加小游戏 二. 游戏玩法: 在4*4的16宫格中,您可以选择上.下.左.右四个方向进行操作,数字会按方向移动,相邻的两个数字相同就会合 ...
- 2048小游戏代码解析 C语言版
2048小游戏,也算是风靡一时的益智游戏.其背后实现的逻辑比较简单,代码量不算多,而且趣味性强,适合作为有语言基础的童鞋来加强编程训练.本篇分析2048小游戏的C语言实现代码. 前言 游戏截图: 游 ...
- .NET手撸2048小游戏
.NET手撸2048小游戏 2048是一款益智小游戏,得益于其规则简单,又和2的倍数有关,因此广为人知,特别是广受程序员的喜爱. 本文将再次使用我自制的"准游戏引擎"FlysEng ...
- Swift实战之2048小游戏
上周在图书馆借了一本Swift语言实战入门,入个门玩一玩^_^正好这本书的后面有一个2048小游戏的实例,笔者跟着实战了一把. 差不多一周的时间,到今天,游戏的基本功能已基本实现,细节我已不打算继续完 ...
- 如何在CentOS上安装一个2048小游戏
如何在centos上安装一个2048小游戏 最近在学习CentOS系统,就琢磨着玩点什么,然后我看到有人在玩2048小游戏,所有我就在想,为啥不装一个2048小游戏搞一下嘞,于是乎,我就开始工作啦 由 ...
- C# 开发2048小游戏
这应该是几个月前,闲的手痒,敲了一上午代码搞出来的,随之就把它丢弃了,当时让别人玩过,提过几条更改建议,但是时至今日,我也没有进行过优化和更改(本人只会作案,不会收场,嘎嘎),下面的建议要给代码爱好的 ...
随机推荐
- 【Machine Learning】KNN算法虹膜图片识别
K-近邻算法虹膜图片识别实战 作者:白宁超 2017年1月3日18:26:33 摘要:随着机器学习和深度学习的热潮,各种图书层出不穷.然而多数是基础理论知识介绍,缺乏实现的深入理解.本系列文章是作者结 ...
- VS项目中使用Nuget还原包后编译生产还一直报错?
Nuget官网下载Nuget项目包的命令地址:https://www.nuget.org/packages 今天就遇到一个比较奇葩的问题,折腾了很久终于搞定了: 问题是这样的:我的解决方案原本是好好的 ...
- spider RPC入门指南
本部分将介绍使用spider RPC开发分布式应用的客户端和服务端. spider RPC中间件基于J2SE 8开发,因此需要确保服务器上安装了JDK 8及以上版本,不依赖于任何额外需要独立安装和配置 ...
- BPM助力企业数字化转型
自九十年代末,流程管理开始引入国内,至今已经有20多年的历史了,由最初的部门级应用向企业级应用转变,大家的认知也经历了一系列的发展变化.不同阶段的信息化水平对企业的流程以及BPM平台也提出了不同的需求 ...
- Android快乐贪吃蛇游戏实战项目开发教程-06虚拟方向键(五)绘制方向键箭头
本系列教程概述与目录:http://www.cnblogs.com/chengyujia/p/5787111.html本系列教程项目源码GitHub地址:https://github.com/jack ...
- Spring Quartz实现任务调度
任务调度 在企业级应用中,经常会制定一些"计划任务",即在某个时间点做某件事情 核心是以时间为关注点,即在一个特定的时间点,系统执行指定的一个操作 任务调度涉及多线程并发.线程池维 ...
- 智能头盔 "Livall携全球首款智能骑行头盔亮相CES"
LIVALL是全球首创集音乐.通讯.智能灯光为一体的智能骑行头盔的研发者,日前Livall携旗下智能骑行头盔BH 100和BH 60参展CES 2017,这也是目前世全球首款智能骑行头盔类产品,同时亮 ...
- windows 部署 git 服务器报 Please make sure you have the correct access rights and the repository exists.错误
这两天在阿里云上弄windows 服务器,顺便部署了一个git服务.根据网上教程一步步操作下来,最后在 remote远程仓库的时候提示 fatal: 'yourpath/test.git' does ...
- [Xamarin] 透過Native Code呼叫 JavaScript function (转帖)
今天我們來聊聊關於如何使用WebView 中的Javascript 來呼叫 Native Code 的部分 首先,你得先來看看這篇[Xamarin] 使用Webview 來做APP因為這篇文章至少講解 ...
- JS中给正则表达式加变量
前不久同事询问我js里面怎么给正则中添加变量的问题,遂写篇博客记录下. 一.字面量 其实当我们定义一个字符串,一个数组,一个对象等等的时候,我们习惯用字面量来定义,例如: var s = &quo ...