五分钟了解2048canvas小游戏制作过程

2018年2月14日20:50:31 发表评论 88

2048这个小游戏我起初是看一个同学玩的,自己也玩过,比较休闲,有点意思,但是没想到至今我可以自己把这个小游戏做出来,我参考了一些大神的代码,然后自己手写一遍,现在仅有一两个点的代码还没弄清楚,但是这丝毫不影响我介绍这个2048小游戏的制作过程。

五分钟了解2048canvas小游戏制作过程

看呐~,国外的大牛原生JS写的2048的小游戏,点我试玩!2048就是他发明的,起初这个项目也是在github上流传的,点击直达github2048作者主页,也欢迎各位朋友看我做的这个这个BUG多多有点原型的2048小游戏,点我试玩,当然这可不是我的最终代码,我会把项目上传到我的github上面,点我下载源码,有时间再慢慢完善这个2048小游戏的代码。

那我们就开始吧,一起来看看我写的游戏思路:

一.游戏初始化

变量

  1. 地图数组
  2. 小方块颜色数组
  3. 方块数字大小
  4. 方块数字偏移量
  5. 上下左右事件信息
  6. 剩余方块数
  7. 当前分数

函数

  1. 定义一个循环函数
  2. 随机生成方块函数

根据剩余的方块生成一个随机数

循环判断地图数组是否等于0

等于0再判断当前随机数是否等于k

不等于k,k就+1再循环

不等于0再循环

循环结束后当前剩余的方块数就-1

3. 绘制圆角矩形小方块地图,数字

循环绘制矩形数组,包括里面的数字
更新当前分数

二.方块移动

事件监听

1. PC按键监听
* 监听onkeydown事件
2. 手机端滑动监听
* 监听ontouchend事件
* 禁止默认的滑动事件

移动函数

  1. 调整不同方向的遍历方式
  2. 根据移动方向,判断是否合并
  3. 如果剩余方块为0,就结束游戏

三.2048小游戏代码

HTML代码

<style>

canvas{
display: block;
margin: 0 auto;
border-radius: 10px;
background-color: #bbada0;
}
</style>
<center id="score" style="font: bold 25px Arial,Microsoft Yahei;"></center>
<canvas id="canvas" width="500" height="500"></canvas> 
<script src="2048.js"></script>

2048.js

var c = document.getElementById('canvas');
var ctx = c.getContext("2d");
c.width = 550;
c.height = 550;


// 初始化
//地图
var map = [[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]];
//不同数字的颜色信息
var num_color = {0:"#ccc0b3",2:"#eee4da",4:"#ede0c8",8:"#f2b179",16:"#f59563",32:"#f67c5f",64:"#ec6544",128:"#e44d29",256:"#edcf72",512:"#c8a145",1024:"#a8832b",2048:"#86aa9c"};
//不同数字的大小信息        
var num_size = {0:"60",2:"60",4:"60",8:"60",16:"60",32:"60",64:"60",128:"50",256:"50",512:"50",1024:"40",2048:"40"};
//不同数字的偏移量(为了将数字画在方块中心)        
var offsetx = {0:65,2:65,4:65,8:65,16:40,32:40,64:40,128:15,256:15,512:15,1024:-10,2048:-10};
//上下左右键的code对应的方向信息        
var keycom = {'38':[0,-1],'40':[0,1],'37':[-1,0],'39':[1,0]}
//space表示当前剩余的空格块数,score表示当前的分数
var space=16,score=0;


var draw = {
    loop: function (func){
    for(var i=0;i<4;i++)
        for(var j=0;j<4;j++){
            func(i,j);
        }
    },

    // 随机生成方块
    produce: function (){
    var cot = ~~(Math.random()*space);
    var k = 0;
    draw.loop(function(i,j){
        if(map[i][j]==0){
            if(cot==k){
                map[i][j]=2;
                    draw.block();
            }
            k+=1;
         }
    });
        space-=1;
    },


    // 绘制地图,更新分数
    block: function (){
        draw.loop(function(i,j){
            var num = map[i][j];
            color = num_color[num];
            draw.roundRect(j*130+30,i*130+30,color);
            if(num!=0){
                 ctx.font = "bold "+num_size[num]+"px Arial,Microsoft Yahei";
                 ctx.fillStyle = (num<=4)?"#776e65":"white"; ctx.fillText(String(map[i][j]),j*132+offsetx[num],i*132+80+num_size[num]/3); } }); document.getElementById("score").innerText="Score: "+String(score); }, // 绘制圆角矩形 roundRect: function (x,y,c){ var box_width = ctx.canvas.width*0.8*0.25; var margin_width = ctx.canvas.width*0.2*0.20; console.log(box_width,margin_width); ctx.beginPath(); ctx.fillStyle=c; ctx.moveTo(x,y); ctx.arcTo(x+box_width,y,x+box_width,y+1,margin_width*0.7); ctx.arcTo(x+box_width,y+box_width,x+box_width-1,y+box_width,margin_width*0.7); ctx.arcTo(x,y+box_width,x,y+box_width-1,margin_width*0.7); ctx.arcTo(x,y,x+1,y,margin_width*0.7); ctx.fill(); }, } var game = { init: function() { draw.produce(); draw.produce(); }, move: function (dir){ //用来调整不同方向的遍历方式 function modify(x,y){ tx=x,ty=y; if(dir[0]==0)tx=[ty,ty=tx][0]; if(dir[1]>0)tx=3-tx;
                if(dir[0]>0)ty=3-ty;
                return [tx,ty];
            }
            //根据移动的方向,将地图中对应行/列中的数字一个个压入栈中,如果第一次遇到栈顶数字和待入栈数字相等,则栈顶数字乘2,最后用栈中数字更新地图中的对应行/列
            for(var i=0;i<4;i++){
                var tmp = Array();
                var isadd = false;
                for(var j=0;j<4;j++){
                    var ti=modify(i,j)[0],tj=modify(i,j)[1];
                    if(map[ti][tj]!=0){
                        if(!isadd&&map[ti][tj]==tmp[tmp.length-1])score+=(tmp[tmp.length-1]*=2),isadd=true,space+=1;
                        else tmp.push(map[ti][tj]);
                    }
                }
                for(var j=0;j<4;j++){
                    var ti=modify(i,j)[0],tj=modify(i,j)[1];
                    map[ti][tj] = isNaN(tmp[j])?0:tmp[j];
                }
            }
            draw.produce();
            if(space==0)alert("game over");
            draw.block();
        }

}


// 事件监听
document.onkeydown=function(e){
    dir = keycom[(e?e:event).keyCode];
    game.move(dir);
};

var sx,sy,dx,dy,ex,ey;
canvas.ontouchstart=function(event){
    var touch = event.touches[0];
    sx=touch.clientX,sy=touch.clientY;
}
canvas.ontouchmove=function(event){
    var touch = event.touches[0];
    ex=touch.clientX,ey=touch.clientY;
    dx=ex-sx,dy=ey-sy;
    //禁止默认的滑动事件
    event.preventDefault();
}
canvas.ontouchend=function(event){
    //根据横纵坐标位移判断滑动方向
    if(dy<-50&&Math.abs(dy/dx)>2)game.move([0,-1]);
    if(dy>50&&Math.abs(dy/dx)>2)game.move([0,1]);
    if(dx<-50&&Math.abs(dx/dy)>2)game.move([-1,0]);
    if(dx>50&&Math.abs(dx/dy)>2)game.move([1,0]);
}

game.init();

我做的这个canvas2048小游戏有太多需要完善的地方,比如历史最高分,这个有了就是一个亮点,还有字体大小的bug,如四位数的数字排版的话,肯定会超出到方块外面,不美观,可现在的我没有太多时间去看代码,等有时间再加以完善,明天就是除夕了,祝大家新年快乐!

猿梦

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: