js 语法糖class应用 贪吃蛇

用js做个简易的贪吃蛇游戏
在这里插入图片描述
代码结构:
在这里插入图片描述
主要思路:
1:将草地(蛇运动容器)分成一个个网格

// 生成网格
buildGid () {
    let col = Math.floor(this.options.grasswidth / this.options.snodesize); // 列数
    let row = Math.floor(this.options.grassheight / this.options.snodesize); // 行数
    for (let i = 0; i < row; i++) {
        for(let j = 0; j < col; j++) {
            this.grassgrid.x.push(i * this.options.snodesize); // 加入每个小格子
            this.grassgrid.y.push(j * this.options.snodesize); // 加入每个小格子
            this.grassgrid.el.push((i * this.options.snodesize) + '_' + (j * this.options.snodesize)); // 加入每个小格子
        }
    }
}

2:随机生成食物,食物位置为随机蛇没有占据的网格

// 随机出现食物
addfood (){
    // 获取蛇的网格
    this.getSnakeGrid()
    let arr = { x: [], y: [], el: [] };
    arr.el = this.grassgrid.el.filter((item, index) => {
        if (!this.snakegrid.el.includes(item)) {
            arr.x.push(this.grassgrid.x[index])
            arr.y.push(this.grassgrid.y[index])
            return true
        }
        return false
    });
    if (arr.x.length) {
        let index = Math.floor(Math.random() * arr.x.length);
        if (this.food) {
            this.food.style.left = arr.x[index] + 'px';
            this.food.style.top = arr.y[index] + 'px';
        } else {
            let foodel = document.createElement('div');
            foodel.style.left = arr.x[index] + 'px';
            foodel.style.top = arr.y[index] + 'px';
            foodel.className = 'food'
            this.food = this.grassel.appendChild(foodel);
        }
    }
}

3:蛇爬动,蛇snake为连续的一小格一小格,每次爬一小格,蛇头(第一小格)根据当前方向cudire设置移动位置,蛇身体(除第一个小格)移动位置为上一个小格的位置

// 蛇爬动
snakeClimb () {
    this.crossBorder(); // 判断蛇头是否碰壁
    this.crossSelf(); // 判断蛇头是否碰到身体
    if (!this.gameover && !this.isplaying) { // 如果游戏没有结束且蛇没有在爬动
        this.isplaying = true
        let snakenode = this.grassel.querySelectorAll('.snake-node'); // 蛇的所有关节小格
        let preposition = { x: 0, y: 0 }; // 记录上一个蛇关节的位置
        for (let i = 0; i < snakenode.length; i++) {
            let item = snakenode[i]
            if (i == 0) { //  如果是蛇头
                switch(this.cudire) {
                    case 'r': // 如果向右移动,则蛇头小格left增加一小格宽度
                        item.style.left = (item.offsetLeft + this.options.snodesize) + 'px';
                        break;
                    case 'l': // 如果向左移动,则蛇头小格left减少一小格宽度
                        item.style.left = (item.offsetLeft - this.options.snodesize) + 'px';
                        break;
                    case 't': // 如果向上移动,则蛇头小格top减少一小格宽度
                        item.style.top = (item.offsetTop - this.options.snodesize) + 'px';
                        break;
                    case 'b': // 如果向下移动,则蛇头小格top增加一小格宽度
                        item.style.top = (item.offsetTop + this.options.snodesize) + 'px';
                        break;
                }
            } else { //  蛇身体关节小格移动位置为上一个关节小格的位置
                item.style.left = preposition.x + 'px';
                item.style.top = preposition.y + 'px';
            }
            preposition = { x: item.offsetLeft, y: item.offsetTop }
        }
    }
}

4:修改蛇爬动方向,监听鼠标点击草地位置,通过判断当前蛇爬行方向、蛇头位置和鼠标位置比较判断蛇改变的方向:如果是水平方向移动,则方向只能改为上下方向;如果是垂直方向移动,则方向只能是左右方向

// 转变方向
snakeTurn () {
    this.grassel.addEventListener('click', function (e) {
        let selnode = this.grassel.querySelector('.snake-node');
        let x = e.offsetX; // 鼠标x坐标
        let y = e.offsetY; // 鼠标y坐标
        // 如果是水平方向移动,则方向只能改为上下方向;如果是垂直方向移动,则方向只能是左右方向
        if ((this.cudire == 'r' || this.cudire == 'l') && (selnode.offsetTop >= y || selnode.offsetTop + this.options.snodesize <= y)) {
            if (y > selnode.offsetTop) {
                this.cudire = 'b'
            } else {
                this.cudire = 't'
            }
        } else if ((this.cudire == 't' || this.cudire == 'b') && (selnode.offsetLeft >= x || selnode.offsetLeft + this.options.snodesize <= x)) {
            if (x > selnode.offsetLeft) {
                this.cudire = 'r'
            } else {
                this.cudire = 'l'
            }
        }
        if (this.gamestart && !this.isplaying) {
            this.snakeClimb();
        }
    }.bind(this), false)
}

4:蛇吃食物,判断蛇头和食物的位置相同,为碰到食物,食物修改位置,在蛇尾处增加一小关节小格

// 判断是否碰到食物
getFood () {
    let sel = this.grassel.querySelector('.snake-node');
    if (sel.offsetLeft == this.food.offsetLeft && sel.offsetTop == this.food.offsetTop) {
        return true
    } else {
        return false
    }
}
// 吃东西
eatfood () {
    this.addSnakeNodes(); // 增加蛇关节
    this.addfood(); // 改变食物位置
}

最后完整代码

<!DOCTYPE html>
<html>
    <head>
        <title>贪吃蛇</title>
    </head>
    <body>
        <script>
            class RetroSnaker {
                constructor (options) {
                    let defoptions = {
                        container: document.body,
                        grasswidth: 300,
                        grassheight: 300,
                        snodesize: 50,
                        speed: 0.3
                    }
                    options || (options = {});
                    this.options = Object.assign({}, defoptions, options); // 基础配置
                    this.grassgrid = { x: [], y: [], el: [] }; // 草地网格
                    this.snakegrid = { x: [], y: [], el: [] }; // 蛇的网格
                    this.cudire = 'r'; // 方向 r:向右;l:向左;t:向上;b:向下。
                    this.isplaying = false; // 是否在运动中
                    this.gameover = false; // 游戏是否结束
                    this.gamestart = false; // 游戏是否开始
                    this.grassel = null; // 草地
                    this.snake = null; // 蛇
                    this.startbtn = null; // 开始游戏按钮
                    this.food = null; // 食物
                    this.tipcon = null; // 提示框
                    this.init();
                }
                init () {
                    this.buildGrass();
                    this.addSnakeNodes();
                    this.buildGid();
                    this.addfood();
                    this.startbtn.addEventListener('click', function () {
                        this.startbtn.innerText = "重新开始";
                        if (this.gamestart) {
                            this.reStart();
                        }
                        this.play();
                    }.bind(this), false)
                    this.snakeTurn ();
                }
                // 创建元素
                buildGrass () {
                    if (!document.querySelector('head style#style-retrosnaker')) {
                        let styleel = document.createElement('style');
                        styleel.innerHTML = `
                            .grass{
                                position: relative;
                                width: ${this.options.grasswidth}px;
                                height: ${this.options.grassheight}px;
                                background: green;
                                margin: 0px auto;
                                overflow: hidden;
                            }
                            .snake{

                            }
                            .snake-node{
                                left: 0px;
                                top: 0px;
                                transition: all ${this.options.speed}s;
                                transition-timing-function: linear;
                            }
                            .snake-node,
                            .food{
                                position: absolute;
                                width: ${this.options.snodesize}px;
                                height: ${this.options.snodesize}px;
                                background: red;
                                pointer-events: none;
                            }
                            .food{
                                background: yellow;
                            }
                            .opbtns-box{
                                position: relative;
                                margin-top: 20px;
                                display: flex;
                                justify-content: center;
                            }
                            .opbtns-start{
                                position: relative;
                                font-size: 24px;
                            }
                            .tipcon{
                                position: absolute;
                                width: 100%;
                                height: 100%;
                                background: rgba(0, 0, 0, .6);
                                display: none;
                                font-size: 24px;
                                justify-content: center;
                                align-items: center;
                                color: #fff;
                                letter-spacing: .2em;
                                font-weight: bold;
                                z-index: 1;
                            }
                        `;
                        styleel.id = 'style-retrosnaker';
                        document.querySelector('head').appendChild(styleel);
                    }
                    let gel = document.createElement('div');
                    gel.className = 'grass'
                    this.grassel = this.options.container.appendChild(gel);
                    let sel = document.createElement('div');
                    sel.className = 'snake';
                    this.snake = this.grassel.appendChild(sel);
                    let btns = document.createElement('div');
                    btns.className = "opbtns-box";
                    btns = this.options.container.appendChild(btns)
                    let startbtn = document.createElement('button');
                    startbtn.className = "opbtns-start";
                    startbtn.innerText = "开始游戏";
                    this.startbtn = btns.appendChild(startbtn);
                    let tipcon = document.createElement('div');
                    tipcon.className = 'tipcon';
                    this.tipcon = this.grassel.appendChild(tipcon)
                }
                // 生成蛇节点
                addSnakeNodes () {
                    this.grassel || this.buildGrass();
                    let selnodes = this.grassel.querySelectorAll('.snake-node');
                    let x = 0;
                    let y = 0;
                    if (selnodes && selnodes.length) {
                        let lastnode = selnodes[selnodes.length - 1];
                        x = lastnode.offsetLeft;
                        y = lastnode.offsetTop;
                        switch(this.cudire) {
                            case 'r':
                                x -= this.options.snodesize;
                                break;
                            case 'l':
                                x += this.options.snodesize;
                                break;
                            case 't':
                                y += this.options.snodesize;
                                break;
                            case 'b':
                                y -= this.options.snodesize;
                                break;
                        }
                    }
                    let snakenode = document.createElement('div');
                    snakenode.className = 'snake-node';
                    snakenode.setAttribute('style', `left: ${x}px; top: ${y}px;`)
                    this.snake.appendChild(snakenode);
                }
                // 生成网格
                buildGid () {
                    let col = Math.floor(this.options.grasswidth / this.options.snodesize); // 列数
                    let row = Math.floor(this.options.grassheight / this.options.snodesize); // 行数
                    for (let i = 0; i < row; i++) {
                        for(let j = 0; j < col; j++) {
                            this.grassgrid.x.push(i * this.options.snodesize); // 加入每个小格子
                            this.grassgrid.y.push(j * this.options.snodesize); // 加入每个小格子
                            this.grassgrid.el.push((i * this.options.snodesize) + '_' + (j * this.options.snodesize)); // 加入每个小格子
                        }
                    }
                }
                // 获取蛇的网格
                getSnakeGrid () {
                    let els = this.grassel.querySelectorAll('.snake-node');
                    let obj= { x: [], y: [], el: [] }
                    els.forEach(item => {
                        obj.x.push(item.offsetLeft); // 加入每个小格子
                        obj.y.push(item.offsetTop); // 加入每个小格子
                        obj.el.push(item.offsetLeft + '_' + item.offsetTop); // 加入每个小格子
                    })
                    this.snakegrid = obj;
                }
                // 随机出现食物
                addfood (){
                    // 获取蛇的网格
                    this.getSnakeGrid()
                    let arr = { x: [], y: [], el: [] };
                    arr.el = this.grassgrid.el.filter((item, index) => {
                        if (!this.snakegrid.el.includes(item)) {
                            arr.x.push(this.grassgrid.x[index])
                            arr.y.push(this.grassgrid.y[index])
                            return true
                        }
                        return false
                    });
                    if (arr.x.length) {
                        let index = Math.floor(Math.random() * arr.x.length);
                        if (this.food) {
                            this.food.style.left = arr.x[index] + 'px';
                            this.food.style.top = arr.y[index] + 'px';
                        } else {
                            let foodel = document.createElement('div');
                            foodel.style.left = arr.x[index] + 'px';
                            foodel.style.top = arr.y[index] + 'px';
                            foodel.className = 'food'
                            this.food = this.grassel.appendChild(foodel);
                        }
                    }
                }
                // 判断是否碰壁
                crossBorder () {
                    if (this.grassgrid.el.length && (this.grassgrid.el.length == this.snakegrid.el.length)) {
                        this.gameover = true;
                        console.log('游戏胜利');
                        this.showTip('游戏胜利');
                        return
                    }
                    let dir = this.cudire
                    let el = this.grassel.querySelector('.snake-node')
                    if (dir == 'r' && el.offsetLeft >= this.grassgrid.x[this.grassgrid.x.length - 1] || 
                        dir == 'l' && el.offsetLeft <= 0 || 
                        dir == 'b' && el.offsetTop >= this.grassgrid.y[this.grassgrid.y.length - 1] || 
                        dir == 't' && el.offsetTop <= 0
                        ) {
                            this.gameover = true
                            this.showTip('游戏结束');
                            console.log('游戏结束')
                    }
                }
                // 判断是否碰到身体
                crossSelf () {
                    this.getSnakeGrid();
                    for (let i = 1; i < this.snakegrid.el.length; i++) {
                        if (this.snakegrid.el[i] == this.snakegrid.el[0]) {
                            this.gameover = true
                            console.log('游戏结束')
                            this.showTip('游戏结束');
                            break
                        }
                    }
                }
                // 蛇爬动
                snakeClimb () {
                    this.crossBorder(); // 判断蛇头是否碰壁
                    this.crossSelf(); // 判断蛇头是否碰到身体
                    if (!this.gameover && !this.isplaying) { // 如果游戏没有结束且蛇没有在爬动
                        this.isplaying = true
                        let snakenode = this.grassel.querySelectorAll('.snake-node'); // 蛇的所有关节小格
                        let preposition = { x: 0, y: 0 }; // 记录上一个蛇关节的位置
                        for (let i = 0; i < snakenode.length; i++) {
                            let item = snakenode[i]
                            if (i == 0) { //  如果是蛇头
                                switch(this.cudire) {
                                    case 'r': // 如果向右移动,则蛇头小格left增加一小格宽度
                                        item.style.left = (item.offsetLeft + this.options.snodesize) + 'px';
                                        break;
                                    case 'l': // 如果向左移动,则蛇头小格left减少一小格宽度
                                        item.style.left = (item.offsetLeft - this.options.snodesize) + 'px';
                                        break;
                                    case 't': // 如果向上移动,则蛇头小格top减少一小格宽度
                                        item.style.top = (item.offsetTop - this.options.snodesize) + 'px';
                                        break;
                                    case 'b': // 如果向下移动,则蛇头小格top增加一小格宽度
                                        item.style.top = (item.offsetTop + this.options.snodesize) + 'px';
                                        break;
                                }
                            } else { //  蛇身体关节小格移动位置为上一个关节小格的位置
                                item.style.left = preposition.x + 'px';
                                item.style.top = preposition.y + 'px';
                            }
                            preposition = { x: item.offsetLeft, y: item.offsetTop }
                        }
                    }
                }
                // 转变方向
                snakeTurn () {
                    this.grassel.addEventListener('click', function (e) {
                        let selnode = this.grassel.querySelector('.snake-node');
                        let x = e.offsetX; // 鼠标x坐标
                        let y = e.offsetY; // 鼠标y坐标
                        // 如果是水平方向移动,则方向只能改为上下方向;如果是垂直方向移动,则方向只能是左右方向
                        if ((this.cudire == 'r' || this.cudire == 'l') && (selnode.offsetTop >= y || selnode.offsetTop + this.options.snodesize <= y)) {
                            if (y > selnode.offsetTop) {
                                this.cudire = 'b'
                            } else {
                                this.cudire = 't'
                            }
                        } else if ((this.cudire == 't' || this.cudire == 'b') && (selnode.offsetLeft >= x || selnode.offsetLeft + this.options.snodesize <= x)) {
                            if (x > selnode.offsetLeft) {
                                this.cudire = 'r'
                            } else {
                                this.cudire = 'l'
                            }
                        }
                        if (this.gamestart && !this.isplaying) {
                            this.snakeClimb();
                        }
                    }.bind(this), false)
                }
                // 判断是否碰到食物
                getFood () {
                    let sel = this.grassel.querySelector('.snake-node');
                    if (sel.offsetLeft == this.food.offsetLeft && sel.offsetTop == this.food.offsetTop) {
                        return true
                    } else {
                        return false
                    }
                }
                // 吃东西
                eatfood () {
                    this.addSnakeNodes(); // 增加蛇关节
                    this.addfood(); // 改变食物位置
                }
                // 开始爬动
                play () {
                    this.gamestart = true;
                    if (!this.isplaying) {
                        this.snakeClimb();
                    }
                    function run (e) {
                        e.preventDefault();
                        this.isplaying = false;
                        if (this.getFood()) {
                            this.eatfood();
                        }
                        this.snakeClimb();
                    }
                    this.grassel.querySelector('.snake-node').removeEventListener('transitionend', run.bind(this), false);
                    this.grassel.querySelector('.snake-node').addEventListener('transitionend', run.bind(this), false);
                }
                // 重置游戏
                reStart () {
                    this.snakegrid = { x: [], y: [], el: [] }
                    this.cudire = 'r';
                    this.isplaying = false;
                    this.gameover = false;
                    this.gamestart = false;
                    this.snake.innerHTML = '';
                    this.addSnakeNodes();
                    this.addfood();
                    this.hideTip()
                }
                // 显示提示框
                showTip (msg) {
                    this.tipcon.style.display = 'flex';
                    this.tipcon.innerText = msg;
                }
                // 隐藏提示框
                hideTip () {
                    this.tipcon.style.display = 'none';
                    this.tipcon.innerText = '';
                }
            }
            let snake = new RetroSnaker();
        </script>
    </body>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值