美文网首页
【游戏系列】用js+html+css实现web端的2048小游戏

【游戏系列】用js+html+css实现web端的2048小游戏

作者: 凡繁烦 | 来源:发表于2021-04-29 11:14 被阅读0次

    1.html代码块

    overflow: hidden;此样式解决微信内置浏览器下拉问题

    <body style="overflow: hidden;">
        <div class="main">
            <div id="c00"></div>
            <div id="c01"></div>
            <div id="c02"></div>
            <div id="c03"></div>
    
            <div id="c10"></div>
            <div id="c11"></div>
            <div id="c12"></div>
            <div id="c13"></div>
    
            <div id="c20"></div>
            <div id="c21"></div>
            <div id="c22"> </div>
            <div id="c23"></div>
    
            <div id="c30"></div>
            <div id="c31"></div>
            <div id="c32"></div>
            <div id="c33"></div>
        </div>
        <div class="keymap">
            <div class="score">分数:<span id="score">0</span></div>
            <p><button onclick="game.reset()">重新开始</button></p>
        </div>
    </body>
    

    2.css样式

    使用flex弹性布局

    @media all and (max-device-width: 400px)解决响应式布局

    .main{
        width: 400px;
        height: 400px;
        display: flex;
        justify-content: space-between;
        flex-wrap: wrap;
        padding: 10px;
        background:#bbada0;
        border-radius: 6px;
        position: absolute;
        top: calc(50% - 200px);
        left: calc(50% - 200px);
    }
    .main div{
        width: 90px;
        height: 90px;
        border-radius: 6px;
        background-color: #ccc0b3;
        text-align: center;
        line-height: 90px;
    }
    @media all and (max-device-width: 400px){
        .main{
            width: 340px;
            height: 340px;
            border-right: 1px solid #e0e0e0;
            display: flex;
            justify-content: space-between;
            flex-wrap: wrap;
            padding: 10px;
            background:#bbada0;
            border-radius: 6px;
            position: absolute;
            top: calc(50% - 170px);
            left: calc(50% - 180px);
        }
    
        .main div{
            width: 80px;
            height: 80px;
        }
    }
    .keymap{
        margin: 0 auto;
        width: 300px;
        text-align: center;
    }
    .score{
        height: 40px;
        line-height: 40px;
        font-size: 30px;
        margin: 20px;
    }
    .btn-1,.btn-2,.btn-3,.btn-4{
        display: flex;
        flex-flow: row;
        justify-content: center;
        margin-top: 10px;
    }
    .btn-4{
        margin-top: 40px;
    }
    
    button{
        height: 50px;
        width: 80px;
        margin: 0 10px;
        cursor: pointer;
        border-width: 0;
        outline: none;
        background-color: #f59563;
        font-family: KaiTi;
        border-radius: 3px;
        font-size: 20px;
    }
    button:hover{/*鼠标移动时的颜色变化*/
        background-color: antiquewhite;
    }
    
    .n2{background-color:#eee3da !important}
    .n4{background-color:#ede0c8 !important}
    .n8{background-color:#f2b179 !important}
    .n16{background-color:#f59563 !important}
    .n32{background-color:#f67c5f !important}
    .n64{background-color:#f65e3b !important}
    .n128{background-color:#edcf72 !important}
    .n256{background-color:#edcc61 !important}
    .n512{background-color:#9c0 !important}
    .n1024{background-color:#33b5e5 !important}
    .n2048{background-color:#09c !important}
    .n4096{background-color:#a6c !important}
    .n8192{background-color:#93c !important }
    .n2,.n4{color:#776e65 !important}
    

    3.js逻辑处理

    3.1声明一个game对象

    let game = {
            score: 0,
            status: 0,
            data: [
                [],
                [],
                [],
                []
            ],
            start: function(){
                if(this.status == 1){
                    alert('游戏已开始');
                    return
                }
                this.status = 1;
                let data = localStorage.getItem('data');
                if(data){
                    let arr = data.split(',');
                    for(let i=0;i<arr.length;i++){
                        if(i<4){
                            this.data[0][i]=parseInt(arr[i]);
                        }else if(i<8){
                            this.data[1][i-4]=parseInt(arr[i]);
                        }else if(i<12){
                            this.data[2][i-8]=parseInt(arr[i]);
                        }else{
                            this.data[3][i-12]=parseInt(arr[i]);
                        }
                    }
                }else{
                    this.data = [
                        [0,0,0,0],
                        [0,0,0,0],
                        [0,0,0,0],
                        [0,0,0,0]
                    ];
                    this.randomData();
                }
                if(localStorage.getItem('score')){
                    this.score = parseInt(localStorage.getItem('score'))
                }
                this.renderView();
            },
            randomData: function(){
                for(;;){
                    let a = Math.floor(Math.random()*4);
                    let b = Math.floor(Math.random()*4);
                    if(this.data[a][b] == 0){
                        var num = Math.random()>0.3 ? 2:4;
                        this.data[a][b]=num;
                        break;
                    }
                }
            },
            //更新视图
            renderView: function(){
                for(let i = 0; i < this.data.length; i++){
                    let row = this.data[i];
                    for(let j = 0; j<row.length; j++){
                        let cell = row[j];
                        let dom = document.getElementById('c'+i+j);
                        if(cell != 0){
                            dom.innerText=cell;
                            dom.className='n'+cell;
                        }else{
                            dom.innerText='';
                            dom.className='';
                        }
                    }
                }
                localStorage.setItem('score',this.score);
                document.getElementById('score').innerText=this.score;
            },
            reset(){
                localStorage.clear();
                this.data = [
                    [0,0,0,0],
                    [0,0,0,0],
                    [0,0,0,0],
                    [0,0,0,0]
                ]
                this.score = 0;
                this.randomData();
                this.renderView();
            },
            checkGameOver: function(){
                for(let i = 0; i < this.data.length; i++){
                    let row = this.data[i];
                    for(let j = 0; j<row.length; j++){
                        let cell = row[j];
                        if(cell == 0){
                            return false;
                        }
                        if(i < this.data.length-1 && this.data[i][j]== this.data[i+1][j]){
                            return false;
                        }
                        if(j < this.data.length-1 && this.data[i][j]== this.data[i][j+1]){
                            return false;
                        }
                    }
                }
                return true;
            },
            moveLeft: function(){
                let before = String(this.data);
                //遍历行
                for(let a = 0; a < this.data.length; a++){
                    this.moveLeftInRow(a);
                }
                let after = String(this.data);
                if(before != after){
                    this.randomData();
                    this.renderView();
                    if(this.checkGameOver()){
                        alert('游戏结束')
                    }
                }
                localStorage.setItem('data',this.data.join(','))
            },
            moveLeftInRow: function(a){
                for(let b = 0; b < this.data.length - 1; b++){
                    let nextb = this.getNextInRow(a,b);
                    if(nextb != -1){
                        if(this.data[a][b] == 0){
                            this.data[a][b] = this.data[a][nextb];
                            this.data[a][nextb] = 0;
                            b--;   
                        }else if(this.data[a][b] == this.data[a][nextb]){
                            this.data[a][b] *= 2;
                            this.score += this.data[a][b]
                            this.data[a][nextb] = 0
                        }
                    }else{
                        break;
                    }
                }
            },
            getNextInRow: function(a,b){
                for(let i = b+1; i<this.data.length; i++){
                    if(this.data[a][i] != 0){
                        return i;
                    }
                }
                return -1;
            },
            moveRight: function(){
                let before = String(this.data);
                for(let a = 0; a < this.data.length; a++){
                    this.moveRightInRow(a);
                }
                let after = String(this.data);
                if(before != after){
                    this.randomData();
                    this.renderView();
                    if(this.checkGameOver()){
                        alert('游戏结束')
                    }
                }
                localStorage.setItem('data',this.data.join(','))
            },
            moveRightInRow: function(a){
                for(let b=this.data.length-1; b > 0; b--){
                    let nextb = this.moveNextRight(a,b);
                    if(nextb != -1){
                        if(this.data[a][b] == 0){
                            this.data[a][b] = this.data[a][nextb];
                            this.data[a][nextb] = 0;
                            b++;    
                        }else if(this.data[a][b] == this.data[a][nextb]){
                            this.data[a][b] *= 2;
                            this.score += this.data[a][b]
                            this.data[a][nextb] = 0
                        }
                    }else{
                        break;
                    }
                }
            },
            moveNextRight(a,b){
                for(var i = b-1; i >= 0; i--){
                    if(this.data[a][i] != 0){
                        return i;
                    }
                }
                return -1;
            },
            moveUp: function(){
                let before = String(this.data);
                for(let b=0; b < this.data.length; b++){
                    this.moveUpInRow(b);
                }
                let after = String(this.data);
                if(before != after){
                    this.randomData();
                    this.renderView();
                    if(this.checkGameOver()){
                        alert('游戏结束')
                    }
                }
                localStorage.setItem('data',this.data.join(','))
            },
            moveUpInRow(b){
                for(var a = 0; a < 3; a++){
                    let nexta = this.moveNextUp(a,b);
                    if(nexta != -1){
                        if(this.data[a][b] == 0){
                            this.data[a][b] = this.data[nexta][b];
                            this.data[nexta][b] = 0;
                            a--;    
                        }else if(this.data[a][b] == this.data[nexta][b]){
                            this.data[a][b] *= 2;
                            this.score += this.data[a][b]
                            this.data[nexta][b] = 0
                        }
                    }else{
                        break;
                    }
                }
            },
            moveNextUp(a,b){
                for(var i = a+1; i<4; i++){
                    if(this.data[i][b] != 0){
                        return i;
                    }
                }
                return -1;
            },
            moveDown: function(){
                let before = String(this.data);
                for(let b=0; b< this.data.length; b++){
                    this.moveDownInRow(b);
                }
                let after = String(this.data);
                if(before != after){
                    this.randomData();
                    this.renderView();
                    if(this.checkGameOver()){
                        alert('游戏结束')
                    }
                }
                localStorage.setItem('data',this.data.join(','))
            },
            moveDownInRow: function(b){
                for(var a=3; a>0; a--){
                    var nexta = this.moveNextDown(a,b)
                    if(nexta != -1){
                        if(this.data[a][b]==0){
                            this.data[a][b] = this.data[nexta][b];
                            this.data[nexta][b] = 0;
                            a++;  
                        }else if(this.data[a][b] == this.data[nexta][b]){
                            this.data[a][b] *= 2;
                            this.score += this.data[a][b]
                            this.data[nexta][b] = 0;
                        }
                    }else{
                        break;
                    }
                }
            },
            moveNextDown(a,b){
                for(var i = a-1;i >= 0;i--){
                    if(this.data[i][b] != 0){
                        return i;
                    }
                }
                return -1;
            }
        }
    

    3.2监听键盘上下左右按键

    document.addEventListener('keyup',function(e){
        if(event.keyCode==37)   //左
            game.moveLeft();
        if(event.keyCode==39)   //右
            game.moveRight();
        if(event.keyCode==38)   //上
            game.moveUp();
        if(event.keyCode==40)   //下
            game.moveDown();
    })
    

    3.3封装移动端滑动事件

    let eventUtil = {
            addHandler: function (element, type, handler) {
                if (element.addEventListener)
                    element.addEventListener(type, handler, false);
                else if (element.attachEvent)
                    element.attachEvent("on" + type, handler);
                else
                    element["on" + type] = handler;
            },
            removeHandler: function (element, type, handler) {
                if(element.removeEventListener)
                    element.removeEventListener(type, handler, false);
                else if(element.detachEvent)
                    element.detachEvent("on" + type, handler);
                else
                    element["on" + type] = handler;
            },
            /**
            * 监听触摸的方向
            * @param target            要绑定监听的目标元素
            * @param isPreventDefault  是否屏蔽掉触摸滑动的默认行为(例如页面的上下滚动,缩放等)
            * @param upCallback        向上滑动的监听回调(若不关心,可以不传,或传false)
            * @param rightCallback     向右滑动的监听回调(若不关心,可以不传,或传false)
            * @param downCallback      向下滑动的监听回调(若不关心,可以不传,或传false)
            * @param leftCallback      向左滑动的监听回调(若不关心,可以不传,或传false)
            */
            listenTouchDirection: function (target, isPreventDefault, upCallback, rightCallback, downCallback, leftCallback) {
                this.addHandler(target, "touchstart", handleTouchEvent);
                this.addHandler(target, "touchend", handleTouchEvent);
                this.addHandler(target, "touchmove", handleTouchEvent);
                var startX;
                var startY;
                function handleTouchEvent(event) {
                    switch (event.type){
                        case "touchstart":
                            startX = event.touches[0].pageX;
                            startY = event.touches[0].pageY;
                            break;
                        case "touchend":
                            var spanX = event.changedTouches[0].pageX - startX;
                            var spanY = event.changedTouches[0].pageY - startY;
    
                            if(Math.abs(spanX) > Math.abs(spanY)){      //认定为水平方向滑动
                                if(spanX > 30){         //向右
                                    if(rightCallback)
                                        rightCallback();
                                } else if(spanX < -30){ //向左
                                    if(leftCallback)
                                        leftCallback();
                                }
                            } else {                                    //认定为垂直方向滑动
                                if(spanY > 30){         //向下
                                    if(downCallback)
                                        downCallback();
                                } else if (spanY < -30) {//向上
                                    if(upCallback)
                                        upCallback();
                                }
                            }
    
                            break;
                        case "touchmove":
                            //阻止默认行为
                            if(isPreventDefault)
                                event.preventDefault();
                            break;
                    }
                }
            }
        }
    

    3.4 监听滑动

    eventUtil.listenTouchDirection(document.documentElement,true,
        ()=>{game.moveUp()},
        ()=>{game.moveRight()},
        ()=> {game.moveDown()},
        ()=>{game.moveLeft()})
    

    预览地址

    image.png

    相关文章

      网友评论

          本文标题:【游戏系列】用js+html+css实现web端的2048小游戏

          本文链接:https://www.haomeiwen.com/subject/jhoirltx.html