js贪吃蛇小游戏

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>贪吃蛇</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div id="game">
        <div id="explain">
            <div>操作WASD 空格开始/暂停 R重新开始</div>
            <div>当前分数:<span  id="grade">0</span>分</div>
        </div>
        <canvas id="snakegame" width="500" height="500">
        </canvas>
    </div>
    <script type="text/javascript" src="main.js" charset="UTF-8"></script>
</body>
</html>

style.css

*{
    padding: 0;
    margin: 0;
}
#game {
    width: 500px;
    margin: auto;
}
#explain {
    width: 500px;
}
#explain div{
    width: 500px;
    height: 30px;
}
#snakegame {
    background: green;
}

main.js

/**
 * el 挂载的元素
 * attribute 贪吃蛇的属性
 */
class Game {
    constructor (el, attribute) {
        this.el = document.getElementById(el);
        // 获取画布的宽高
        this.el.elW = parseInt(window.getComputedStyle(this.el).width);
        this.el.elH = parseInt(window.getComputedStyle(this.el).height);
        this.init(attribute);
        this.keyListening();
    }
    // 初始化
    init(attribute) {
        this.attribute = {
            color: "red", // 颜色
            direction: "rigth", // 移动方向
            state: "pause", // 状态 run pause end
            grade: 0, // 分数
            body: [{x: 20, y: 0}, {x: 0, y: 0}], // 贪吃蛇身体
            wh: 20, // 矩形的宽高
            speed: 200 // 速度
        };
        if (attribute) {
            this.newAttribute = attribute;
            Object.keys(attribute).forEach(key => {
                this.attribute[key] = attribute[key];
            });
        }
        this.food ={
            x: 0,
            y: 0,
            color: 'red'
        }
        this.draw();
        this.foodDraw();
    }
    // 绘制贪吃蛇
    draw() {
        let el = this.el;
        let { body, wh, color } = this.attribute;
        // 确定浏览器是否支持canvans元素
        if (el.getContext) {
            let context = snakegame.getContext("2d");
            context.fillStyle = color;
            body.forEach( key => {
                context.fillRect(key.x, key.y, wh, wh);
            });
        }
    }
    // 随机生成食物
    foodDraw() {
        let el = this.el, wh = this.attribute.wh;
        this.food.x = Math.floor(Math.random()*(el.elW - wh)),
        this.food.y = Math.floor(Math.random()*(el.elH - wh));
        while (this.isOverlap()) {
            this.food.x = Math.floor(Math.random()*(el.elW - wh)),
            this.food.y = Math.floor(Math.random()*(el.elH - wh));
        }
        if (el.getContext) {
            let context = snakegame.getContext("2d");
            context.fillStyle = this.food.color;
            context.fillRect(this.food.x, this.food.y, wh, wh);
        }
    }
    // 判断食物是否与贪吃蛇的身体重叠
    isOverlap() {
        let { wh } = this.attribute;
        let food = this.food;
        let flag = false;
        function isIn(key, x, y) {
            if (key.x <= x && key.x + wh >= x  && key.y <= y && key.y + wh >= y) {
                return true;
            } else {
                return false;
            }
        }
        this.attribute.body.forEach(key => {
            // 食物的上下左右四个点一个点在贪吃蛇的身体内就判断为重叠
            if (isIn(key, food.x, food.y) || isIn(key, food.x, food.y + wh) || isIn(key, food.x + wh, food.y) || isIn(key, food.x + wh, food.y + wh)) {
                flag = true;
            }
        });
        return flag;
    }
    // 清除图形
    clear(x, y, width, height) {
        // 确定浏览器是否支持canvans元素
        if (this.el.getContext) {
            let context = snakegame.getContext("2d");
            context.clearRect(x, y, width, height);
        }
    }
    // 游戏状态更新
    updateState(state) {
        this.attribute.state = state;
        if (state === "run") {
            this.run();
        } 
    }
    // 游戏线程
    run() {
        let { body, wh, speed} = this.attribute;
        let time = setInterval(() => {
            // 判断游戏线程是否在运行
            if (this.attribute.state !== 'run') {
                clearInterval(time);
            }
            let obj = {};
            switch(this.attribute.direction) {
                case 'left':
                    obj['x'] = body[0].x - wh;
                    obj['y'] = body[0].y;
                    break;
                case 'rigth':
                    obj['x'] = body[0].x + wh;
                    obj['y'] = body[0].y;
                    break;
                case 'up':
                    obj['x'] = body[0].x;
                    obj['y'] = body[0].y - wh;
                    break;
                case 'down':
                    obj['x'] = body[0].x;
                    obj['y'] = body[0].y + wh;
                    break;
            }
            body.unshift(obj);
            // 判断是否吃到食物 
            if (this.isOverlap()) {
                this.clear(this.food.x, this.food.y, wh, wh);
                this.attribute.grade++; 
                this.foodDraw();
                this.draw();
            } else {
                if (this.end()) {
                    alert("游戏结束");
                    this.updateState('end');
                    clearInterval(time);
                } else {
                    let item = body.pop();
                    this.clear(item.x, item.y, wh, wh);
                    this.draw();
                }
            }
        }, speed);
    }
    // 键盘事件监听
    keyListening() {
        document.onkeydown = (event) => {
            let e = event || window.event || arguments.callee.caller.arguments[0];
            if (e && e.keyCode === 87 && this.attribute.direction !== 'down') { // 按下W
                this.attribute.direction = 'up';
            }
            if (e && e.keyCode === 65 && this.attribute.direction !== 'rigth') { // 按下A
                this.attribute.direction = 'left';
            }
            if (e && e.keyCode === 68 && this.attribute.direction !== 'left') { // 按下D
                this.attribute.direction = 'rigth';
            }
            if (e && e.keyCode === 83 && this.attribute.direction !== 'up') { // 按下W
                this.attribute.direction = 'down';
            }
            if (e && e.keyCode === 32) { // 按下空格 
                let state;
                if (this.attribute.state === 'pause') {
                    state = 'run';
                } 
                if (this.attribute.state === 'run') {
                    state = 'pause';
                }
                this.updateState(state);
            }
            if (e && e.keyCode === 82) { // 按下R键
                this.reStart();
            }
        }  
    }
    // 是否死亡
    end() {
        let body = [...this.attribute.body];
        let obj = body.shift();
        let flag = false;
        if (obj.x < 0 || obj.x >= this.el.elW || obj.y < 0 || obj.y >= this.el.elH) {
            flag = true;
        }
        body.forEach(key => {
            if (key.x === obj.x && key.y === obj.y) {
                flag = true;
            }
        });
        return flag;
    }
    // 重新开始
    reStart() {
        // 清除整个画布
        this.clear(0, 0, this.el.elW, this.el.elH);
        // 重新开始
        this.init(this.newAttribute);
    }
}
let game = new Game("snakegame", {color: "yellow"});
let grade = document.getElementById("grade");
let oldGrade = game.attribute.grade;
setInterval(() => {
    if (oldGrade !== game.attribute.grade) {
        oldGrade = game.attribute.grade;
        grade.innerText = game.attribute.grade;
    }
})

截图

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值