JS贪吃蛇小游戏(简陋版)

前言

贪吃蛇游戏在我上小学的时候就接触了,当时只有一台诺基亚,每天无聊的时候就是玩贪吃蛇,回想当年,为了吃到每个球都是小心翼翼,看着蛇慢慢变长。每天都想着突破记录,达到最高分。
现在选择软件工程专业,突然就想能不能做出这个游戏来,不管做成什么样子。因为对web感兴趣,学习了js,开始了尝试。

项目准备阶段

  • 软件使用的是vscode
  • 创建好三个文件index.html,index.css,index.js

项目开始

第一步先搭建结构

使用html、css搭建好类似于屏幕的盒子

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>贪吃蛇</title>
    <link rel="stylesheet" href="./style/index.css">
</head>
<body>
    <!-- 创建游戏的主容器 -->
    <div id="main">
        <!-- 设置游戏的舞台 -->
        <div id="stage">
            <!-- 蛇 -->
            <div id="snake">
                <div></div>
            </div>
            <!-- 食物 -->
            <div id="food">
                <!-- 设置四个div来设置食物的样式 -->
                <div></div>
                <div></div>
                <div></div>
                <div></div>
            </div>
        </div>
        <div id="score-panle">
            <div>
                SCORE: <span id="score">0</span>
            </div>
            <div>
                level: <span id="level">1</span>
            </div>
        </div>
    </div>

    <script src="./index.js"></script>
</body>
</html>

第二步对结构进行布局修饰

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
body {
  font: bold 20px "Courier";
}
#main {
  width: 360px;
  height: 420px;
  background-color: #b7d4a8;
  margin: 100px auto;
  border: 10px solid #000;
  border-radius: 40px;
  display: flex;
  flex-flow: column;
  justify-content: space-around;
  align-items: center;
}
#main #stage {
  width: 304px;
  height: 304px;
  border: 2px solid #000;
  position: relative;
}
#main #stage #snake > div {
  width: 10px;
  height: 10px;
  background-color: #000;
  border: 1px solid #b7d4a8;
  position: absolute;
}
#main #stage #food {
  width: 10px;
  height: 10px;
  background-color: black;
  border: 1px solid #b7d4a8;
  position: absolute;
  left: 40px;
  top: 100px;
  display: flex;
  flex-flow: row wrap;
  justify-content: space-between;
  align-content: space-between;
}
#main #stage #food > div {
  width: 4px;
  height: 4px;
  background-color: black;
  transform: rotate(45deg);
}
#main #score-panle {
  width: 300px;
  display: flex;
  justify-content: space-between;
  align-items: space-between;
}

在这里插入图片描述

第三步js编写游戏

先从简单的部分开始:记分牌类
  • 实现功能有:
    1. 加分
    2. 提升等级(提升速度)
// 定义表示记分牌的类
class ScorePanel {
    score = 0;
    level = 1;
    scoreEle;
    levelEle;

    // 设置一个变量限制等级
    maxLevel;
    upScore
    constructor(maxLevel = 10, upScore = 10) {
        this.scoreEle = document.getElementById("score")
        this.levelEle = document.getElementById("level")
        this.maxLevel = maxLevel
        this.upScore = upScore
    }
    // 设置一个加分的方法
    addScore() {

        this.scoreEle.innerHTML = ++this.score + ""
        if (this.score % this.upScore === 0) {
            this.levelUp()
        }
    }

    // 设置提升等级的方法
    levelUp() {
        if (this.level < this.maxLevel)
            this.levelEle.innerHTML = ++this.level + ""
    }
}
食物类
  • 实现功能:
    1. 获得食物的位置
    2. 修改食物的位置
// 定义食物类Food
class Food {
    // 定义一个属性表示食物所对应的元素
    // element: HTMLElement;
    element;
    constructor() {
        this.element = document.getElementById("food");

    }

    get X() {
        return this.element.offsetLeft;
    }

    get Y() {
        return this.element.offsetTop;
    }

    // 修改食物的位置
    change() {
        // 生成一个随机的位置
        let top = Math.round(Math.random() * 29) * 10;
        let left = Math.round(Math.random() * 29) * 10;

        this.element.style.left = left + "px";
        this.element.style.top = top + "px";

    }
}
蛇类
  • 实现功能
    1. 设置和获取头的位置
    2. 设置蛇的运动
    3. 蛇吃食物后变长
    4. 判断蛇有没有撞墙和有没有撞身体
    5. 设置蛇不能反向移动

class Snake {
    head;
    element;
    // 包括蛇头
    bodies;

    constructor() {
        this.head = document.querySelector("#snake>div")
        this.element = document.getElementById("snake")
        this.bodies = this.element.getElementsByTagName("div")
    }

    get X() {
        return this.head.offsetLeft
    }

    get Y() {
        return this.head.offsetTop
    }

    set X(value) {

        if (this.X === value) {
            return
        }

        // X的值的合法范围0-290之间
        if (value < 0 || value > 290) {
            // 进入判断寿命蛇撞墙了
            
            throw new Error("蛇撞墙了")
        }

        // 修改X是,是在修改水平坐标,蛇不能反向移动
        if (this.bodies[1] && this.bodies[1].offsetLeft === value) {
            if (value > this.X) {
                value = this.X - 10
            } else {
                value = this.X + 10
            }
        }

        this.moveBody()
        this.head.style.left = value + "px"
        this.checkHeadBody()
    }
    set Y(value) {
        if (this.Y === value) {
            return
        }

        if (value < 0 || value > 290) {
            // 进入判断寿命蛇撞墙了
            throw new Error("蛇撞墙了")
        }

        // 修改Y是,是在修改垂直坐标,蛇不能反向移动
        if (this.bodies[1] && this.bodies[1].offsetTop === value) {
            if (value > this.Y) {
                value = this.Y - 10
            } else {
                value = this.Y + 10
            }
        }

        this.moveBody()
        this.head.style.top = value + "px"
        this.checkHeadBody()
    }

    // 蛇增加身体的方法
    addBody() {
        this.element.insertAdjacentHTML("beforeend", "<div></div>")
    }
    // 添加一个蛇身体移动的方法
    moveBody() {
        for (let i = this.bodies.length - 1; i > 0; i--) {
            // 获取前边身体的位置
            let X = this.bodies[i-1].offsetLeft;
            let Y = this.bodies[i-1].offsetTop;

            // 将值设置道当前身体上
            this.bodies[i].style.left = X + "px";
            this.bodies[i].style.top = Y + "px";
        }
    }

    checkHeadBody() {
        // 获取所有的身体,检查其是否和蛇头坐标发生重叠
        for (let i = 1; i < this.bodies.length; i++) {
            let bd = this.bodies[i]
            console.log(bd.offsetTop);
            console.log(bd.offsetLeft);
            if (this.Y === bd.offsetTop && this.X === bd.offsetLeft) {
                throw new Error("撞到自己了")
            }
        }
    }
}
游戏控制类
  • 实现功能
    1. 对蛇、食物、记分牌三个类的引用
    2. 控制游戏的开始和结束
    3. 获取用户键盘(如果键盘按的太快有bug)
    4. 让蛇一直在移动
    5. 对加分、升级、食物位置变化、蛇变长的调用

class GameControl {

    snake = new Snake();
    food = new Food();
    scorePanel = new ScorePanel();

    // 创建一个属性来存储蛇的移动方向
    direction = ""
    // 创建一个属性用来记录游戏是否结束
    isLive = true
    constructor() {
        this.snake = new Snake()
        this.food = new Food()
        this.scorePanel = new ScorePanel(10, 8)
        this.init()
    }
    init() {
        //绑定键盘按下的事件
        document.addEventListener("keydown", this.keydownHandler.bind(this))
        this.run()
    }
    keydownHandler(event) {
        // 检查event.key 的值是否合法(用户是否按了正确的按钮)
        this.direction = event.key

    }
    // 创建一个控制蛇移动的方法
    run() {
        // 获取蛇当前的坐标
        let X = this.snake.X
        let Y = this.snake.Y

        switch (this.direction) {
            case "ArrowUp":
            case "Up":
                Y -=10
               break;  
            case "ArrowDown":
            case "Down":
                Y += 10
                break;
            case "ArrowLeft":
            case "Left":
                X -= 10
                break;
            case "ArrowRight":
            case "Right":
                X += 10
                break;
        }

        this.checkEat(X, Y)

        // 捕获异常,程序就不会停止了
        try {
            this.snake.X = X
            this.snake.Y = Y
        } catch (e) {
            alert(e.message + "GameOver")
            this.isLive = false
        }

        //修改蛇的X和Y


        // 开启一个定时调用
        this.isLive && setTimeout(this.run.bind(this), 300 - (this.scorePanel.level - 1) * 30)
    }

    // 定义一个方法,用来检测是否吃到食物
    checkEat(X, Y) {
        if (X === this.food.X && Y === this.food.Y) {
            // 食物的位置重置
            this.food.change()
            // 记分牌加分
            this.scorePanel.addScore()
            // 蛇身体增加一节
            this.snake.addBody()
        }

    }

}


let game = new GameControl()
game.init()

总结

该项目使用了一些ES6标准,但有些地方优化也不是很好。该项目是学习尚硅谷视频后制作的。
新手尝试,不足之处敬请谅解。欢迎大佬评论区指教指教。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值