导语
本次将会从头到尾讲一个2048游戏的制作过程,中间也会穿插自己的理解
一.项目结构
除了html和css文件外,分了main.js,support.js,showanimation.js,以及引入jquery。
html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!--手机屏幕兼容预处理-->
<meta name="viewport" content="
width=device-width,
height=device-height,
initial-scale=1.0,
minimum-scale=1.0,
maximum-scale=1.0,
user-scalable=no">
<title>2048</title>
<link rel="stylesheet" type="text/css" href="2048.css">
</head>
<body>
<header>
<h1 class="title">我的2048</h1>
<a href="javascript:newGame();" id="newGameBtn">NewGame</a>
<p>score:<span id="score">0</span></p>
<!--<div class="scores-container">
<div class="score-container">0</div>
<div class="best-container">0</div>
</div>-->
</header>
<div id="grid-container">
<div class="grid-cell" id="grid-cell-0-0"></div>
<div class="grid-cell" id="grid-cell-0-1"></div>
<div class="grid-cell" id="grid-cell-0-2"></div>
<div class="grid-cell" id="grid-cell-0-3"></div>
<div class="grid-cell" id="grid-cell-1-0"></div>
<div class="grid-cell" id="grid-cell-1-1"></div>
<div class="grid-cell" id="grid-cell-1-2"></div>
<div class="grid-cell" id="grid-cell-1-3"></div>
<div class="grid-cell" id="grid-cell-2-0"></div>
<div class="grid-cell" id="grid-cell-2-1"></div>
<div class="grid-cell" id="grid-cell-2-2"></div>
<div class="grid-cell" id="grid-cell-2-3"></div>
<div class="grid-cell" id="grid-cell-3-0"></div>
<div class="grid-cell" id="grid-cell-3-1"></div>
<div class="grid-cell" id="grid-cell-3-2"></div>
<div class="grid-cell" id="grid-cell-3-3"></div>
</div>
<script type="text/javascript" src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script type="text/javascript" src="support2048.js"></script>
<script type="text/javascript" src="showanimation.js"></script>
<script type="text/javascript" src="main2048.js"></script>
</body>
</html>
css文件
html, body, div, span, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
abbr, address, cite, code,
del, dfn, em, img, ins, kbd, q, samp,
small, strong, sub, sup, var,
b, i,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, figcaption, figure,
footer, header, hgroup, menu, nav, section, summary,
time, mark, audio, video {
margin:0;
padding:0;
border:0;
outline:0;
font-size:100%;
vertical-align:baseline;
background:transparent;
}
body {
font-size:12px;
line-height:120%;
text-align:center;
color:#333;
padding:20px;
font:12px/1.5 '微软雅黑',tahoma,arial,'Hiragino Sans GB',宋体,sans-serif;
}
table{ border-collapse:collapse;
border-spacing:0;
}
fieldset,img{border:0;}
address,caption,cite,code,dfn,em,strong,th,var{
font-style:normal;
font-weight:normal;
}
img{border:none;}
ol,ul{list-style:none;}
input, select,textarea{
vertical-align:middle;
outline:none;
}
textarea{resize:none;}
a{
color:#333;
text-decoration:none;
}
a:hover{
text-decoration:underline;
}
/*清浮*/
.clearfix:after{
content:"";
display:block;
clear:both;
}
.clearfix{zoom:1}
/********************************************/
body{
background:#978E81;
}
header{
display:block;
margin:0 auto;
width:100%; /*为了兼容移动端*/
text-align:center;
}
header h1{
font-family:Arial;
font-size:30px;
font-weight:bold;
}
header #newGameBtn{
display: block;
margin:10px auto;
width:100px;
padding:5px 10px;
background-color:#8f7a66;
font-family:Arial;
color:white;
border-radius:10px;
text-decoration:none;
}
header #newGameBtn:hover{
background-color:#9f8b77;
}
header p{
font-family:Arial;
font-size:25px;
margin:10px auto;
}
#grid-container{
width:460px;
height:460px;
padding:20px;
margin:30px auto;
background-color: #bbada0;
border-radius:10px;
position:relative;
}
.grid-cell{
width:100px;
height:100px;
border-radius:12px;
background-color:#ccc0b3;
position:absolute;
}
.number-cell{
border-radius:4px;
font-family:Arial;
font-weight:bold;
font-size:60px;
line-height:100px;
text-align:center;
position:absolute;
}
二.游戏逻辑循序渐进,初始化
首先毫无疑问,需要先初始化游戏,渲染方块之类的。
我们声明两个变量。
var board=new Array(); //存储游戏的数据
var score=0; //得分
然后定义一个newGame函数,并且等document加载完后调用它
$(document).ready(function(){
newGame();
})
function newGame(){
//为移动端初始化宽度
prepareForMobile();
//初始化棋盘格
init();
//在随机两个格子生成数字
generateOneNumber();
generateOneNumber();
}
先忽略那个兼容移动端的,我们根据游戏的逻辑,在newGame里面写了两件事,一个是初始化,一个是随机在格子中生成一个数字,一开始要有两个,所以这个方法调用两遍。下面是init里的内容
function init(){
//有数字的小方块
for(var i=0;i<4;i++){
for(var j=0;j<4;j++){
var gridCell=$("#grid-cell-"+i+"-"+j);
gridCell.css({
"top":getPosTop(i,j),
"left":getPosLeft(i,j)
});
}
}
//初始化board数组
for(var i=0;i<4;i++){
board[i]=new Array();
for(var j=0;j<4;j++){
board[i][j]=0;
}
}
//有操作,更新界面
updateBoardView();
score=0;
$("#score").text(score);
}
在init初始化里面,我们先做的是给16个背景小方块,因为在css文件里面我们只写了定位方式absolute。
通过遍历得到每个格子,css()方法给他们设置定位。我们将getPosTop,getPosLeft两个方法写在support.js中
//20是格子之间的距离,100是一个小格子的宽度
function getPosTop(i,j){
var top=20+i*(100+20);
return top;
}
function getPosLeft(i,j){
var left=20+j*(100+20);
return left;
}
定位完成后我们进行的是board数组的初始化,初始化为一个4*4的二维数组,值为false。board初始化完成后我们则根据board来将游戏界面更新。因为后续我们会经常使用到根据board数组更新游戏画面,所以将其写成一个updateBoardView()方便调用
updateBoardView()函数
因为有注释,所以简单说一下。我们是动态加载有数字的方块的,每次更新先将所有的数字方块全部移除,在弄个循环创建它们,并且创建的同时用css设置样式。设置样式时先判断这个位置的board是不是0,为零的话则将宽高设置为0,并将它们的top,left设置在背景方格的中间(这里是为了后面的animate动画是从中间变化)。对于board中有值的,则需要多设置他们的background-color和color。最后将值显示在html中,即theNumberCell.text(board[i][j])
//更新棋盘上显示的方块
function updateBoardView(){
//如果有number-cell后先删除
$(".number-cell").remove();
//遍历格子,改变样式
for(var i=0;i<4;i++){
for(var j=0;j<4;j++){
$("#grid-container").append('<div class="number-cell" id="number-cell-'+i+'-'+j+'"></div>')
var theNumberCell=$("#number-cell-"+i+"-"+j);
if(board[i][j]==0){
theNumberCell.css({
"width":"0px",
"height":"0px",
"top":getPosTop(i,j)+50,/*这里是为了把它放中间,动画才好看*/
"left":getPosLeft(i,j)+50
});
}else{
theNumberCell.css({
"width":100+'px',
"height":100+'px,
"top":getPosTop(i,j),
"left":getPosLeft(i,j),
"background-color":getNumberBackgroundColor(board[i][j]),
"color":getNumberColor(board[i][j])
});
theNumberCell.text(board[i][j]);
}
}
$('.number-cell').css({
'line-height':cellSideLength+'px',
'font-size':0.6*cellSideLength+'px'
})
}
}
数字方块的背景色与前景色的获取
我们将这两个函数写在support.js中,就使用了一个switch,简单明了,不多解释
function getNumberBackgroundColor(number){
var color="black";
switch(number){
case 2:
color='#eee4da';
break;
case 4:
color="#ede0c8";
break;
case 8:
color='#f2b179';
break;
case 16:
color="#f59563";
break;
case 32:
color='#f67c5f';
break;
case 64:
color="#f65e3b";
break;
case 128:
color='#edcf72';
break;
case 256:
color="#edcc61";
break;
case 512:
color='#9c0';
break;
case 1024:
color="#33b5e5";
break;
case 2048:
color='#09c';
break;
}
return color;
}
function getNumberColor(number){
if(number<=4){
return "#776e50";
}
return "white";
}
三.初始化最后一步:generateOneNumber()
要想在格子上随机生成一个数字,首先我们需要先确定还有空格子可以生成,没有的话直接返回,所以先判断
//先看有无空格
if(nospace(board)){
return false;
}
将nospace(board)写在support.js中
function nospace(board){
for(var i=0;i<4;i++){
for(var j=0;j<4;j++){
if(board[i][j]==0){
return false;
}
}
}
return true;
}
接着要随机生成一个坐标,并且判断这个点是不是为空,不为空则继续随机生成。实在是找不到了,就遍历格子,选第一个为空的格子
//随机生成一个位置
var randx=parseInt(Math.floor(Math.random()*4));
var randy=parseInt(Math.floor(Math.random()*4));
//看是不是空格,优化随机
var times=0;
while(times<50){
if(board[randx][randy]==0){
break;
}
//重复
var randx=parseInt(Math.floor(Math.random()*4));
var randy=parseInt(Math.floor(Math.random()*4));
times++;
}
if(times==50){
for(var i=0;i<4;i++){
for(var j=0;j<4;j++){
if(board[i][j]==0){
randx=i;
randy=j;
}
}
}
}
然后随机生成个2或4 var randNumber=Math.random()<0.65?2:4;
最后将这个数字格子用动画表现出来,并更新board数组
showNumberWithAnimation(randx,randy,randNumber);
board[randx][randy]=randNumber;
最后,我们将showNumberWithAnimation()写在showanimation.js中。
主要是通过jq的animate实现动画效果。
function showNumberWithAnimation(i,j,randNumber){
var numberCell=$("#number-cell-"+i+"-"+j);
numberCell.css({
'background-color':getNumberBackgroundColor(randNumber),
'color':getNumberColor(randNumber)
});
numberCell.animate({
width:100,
height:100,
top:getPosTop(i,j),
left:getPosLeft(i,j)
},50);
numberCell.text(randNumber);
}
至此,我们的游戏的初始化就完成了,在浏览器里运行一下吧
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。