TypeScript 贪吃蛇项目(下)

本文详细介绍了如何在JavaScript中实现贪吃蛇游戏的关键功能,包括蛇的移动、墙壁和食物的碰撞检测、防止蛇自相碰撞以及速度随分数增加而加快的机制。通过蛇头坐标更新后的检查,确保蛇不会非法调头或穿过自己的身体。文章还提供了完整的代码示例,帮助读者理解游戏逻辑并进行调试。
摘要由CSDN通过智能技术生成

蛇的移动

......

//游戏控制器,控制其他所有类
class GameControl {
    ......
    //判断蛇是否还活着
    isAlive = true;

   ......

    //游戏初始化
    init() {
        //绑定键盘按下事件
        document.addEventListener('keydown', this.keyDownHandler.bind(this))
        //调用run方法,使蛇移动
        this.run();
    }

    ......

    //蛇移动的方法
    run() {
        /**
         * 根据方向使蛇的位置改变
         */
        let x = this.snake.X;
        let y = this.snake.Y;
        switch (this.direction) {
            case "ArrowUp":
            case "Up":
                //向上 top减少
                y -= 10;
                break
            case "ArrowDown":
            case "Down":
                y += 10;
                break
            case "ArrowLeft":
            case "Left":
                x -= 10;
                break
            case "ArrowRight":
            case "Right":
                x += 10;
                break
        }
        //修改蛇的x和y
        this.snake.X = x;
        this.snake.Y = y;
        //开启定时调用,开始每300ms调用一次
        //蛇的移动应该越了来越快 根据 level计算
        //如果蛇还活着,再执行setTimeout
        this.isAlive && setTimeout(this.run.bind(this), 300 - (this.scorePanel.level - 1) * 30);
    }
}

export default GameControl;

这样我们就可以控制蛇的移动了
在这里插入图片描述

蛇撞墙检测

把蛇撞墙的检测写在 Snake 类中。由于蛇每次移动只移动一个方向,上、下、左、右,也就是一次只会改变 x 或者 y 的值。这里修改 set X 和 set Y 方法

 //设置蛇头的坐标
    set X(value: number) {
        //如果新值和旧值相同,直接返回,不再修改
        if(this.X === value){
            return;
        }
        //x 的合法范围 0-290
        if(value < 0 || value > 290){
            //进入判断说明蛇撞墙了,抛出异常
            throw new Error("蛇撞墙了!");
        }
        this.head.style.left = value + "px";
    }

    set Y(value: number) {
        if(this.Y === value){
            return;
        }
        //Y 的合法范围 0-290
        if(value < 0 || value > 290){
            //进入判断说明蛇撞墙了,抛出异常
            throw new Error("蛇撞墙了!");
        }
        this.head.style.top = value + "px";
    }

然后在 GameControl 中调用 set X 和 set Y 的时候捕获异常

......

//游戏控制器,控制其他所有类
class GameControl {
    ......

    //蛇移动的方法
    run() {
       	......

        try {
            //修改蛇的x和y
            this.snake.X = x;
            this.snake.Y = y;
        } catch (e) {
            alert(e);
            this.isAlive = false;
        }

        ......
    }
}

export default GameControl;

这样就完成了蛇的撞墙检测
在这里插入图片描述

蛇吃食物检测

......

//游戏控制器,控制其他所有类
class GameControl {
    ......
    //蛇移动的方法
    run() {
        /**
         * 根据方向使蛇的位置改变
         */
        let x = this.snake.X;
        let y = this.snake.Y;
        switch (this.direction) {
            ......
        }

        //检查蛇是否吃到了食物
        this.checkEat(x,y);
        ......
    }

    //检测蛇是否吃到了食物的方法
    checkEat(x:number,y:number){
        if(x === this.food.X && y === this.food.Y){
            console.log("吃到了食物");
            //食物的位置要进行重置
            this.food.change();
            //分数增加
            this.scorePanel.addScore();
            //蛇增加一节
            this.snake.addBody();
        }
    }
}

export default GameControl;

到这里我们就可以吃到食物了,每吃到食物,分数增加1分,左上角就会出现一个蛇的身体,同时食物的位置发生改变。接下来处理蛇的身体问题

蛇的身体移动

class Snake {
    ......

    //设置蛇头的坐标
    set X(value: number) {
        ......
        //移动身体
        this.moveBody();
        this.head.style.left = value + "px";
    }

    set Y(value: number) {
        ......
        //移动身体
        this.moveBody();
        this.head.style.top = value + "px";
    }

	......

    //移动身体的方法
    moveBody(){
        /**
         * 将后边的身体设置为前边身体的位置
         *      第4节 = 第3节的位置
         *      第3节 = 第2节的位置
         *      第2节 = 蛇头的位置
         */
        for(let i=this.bodies.length-1;i>0;i--){
            //获取前边身体的位置
            let x = (this.bodies[i-1] as HTMLElement).offsetLeft;
            let y = (this.bodies[i-1] as HTMLElement).offsetTop;

            (this.bodies[i] as HTMLElement).style.left = x+"px";
            (this.bodies[i] as HTMLElement).style.top = y+"px";
        }
    }
}

......

在这里插入图片描述
这样每吃一次蛇的身体就会在后边增加一节了,不过现在还存在几个bug,接下来一个一个解决

禁止调头

现在有个bug就是当蛇在向左走的时候,我们按右,蛇会继续向右走,这样是不对的

当我们修改 x 时,是在修改水平坐标,蛇在左右移动,蛇在向左移动时,不能向右,反之亦然

class Snake {
    ......

    //设置蛇头的坐标
    set X(value: number) {
        //如果新值和旧值相同,直接返回,不再修改
        if (this.X === value) {
            return;
        }
        //x 的合法范围 0-290
        if (value < 0 || value > 290) {
            //进入判断说明蛇撞墙了,抛出异常
            throw new Error("蛇撞墙了!");
        }

        //如果有第2节身体 并且 第二节身体的值等于新值,也就是头到了第二节身体的位置
        if (this.bodies[1] && (this.bodies[1] as HTMLElement).offsetLeft === value) {
            //console.log("水平方向发生了调头");
            //如果value的值大于现在的x,说明值变大,就是向右走了
            //需要让蛇继续向左走
            if (value > this.X) {
                value = this.X - 10;
            } else {
                value = this.X + 10;
            }
        }

        //移动身体
        this.moveBody();
        this.head.style.left = value + "px";
    }

    set Y(value: number) {
        if (this.Y === value) {
            return;
        }
        //Y 的合法范围 0-290
        if (value < 0 || value > 290) {
            //进入判断说明蛇撞墙了,抛出异常
            throw new Error("蛇撞墙了!");
        }

        //当我们修改y时,是在修改垂直坐标,蛇在上下移动,蛇在向上移动时,不能向下,反之亦然
        if (this.bodies[1] && (this.bodies[1] as HTMLElement).offsetTop === value) {
            if (value > this.Y) {
                value = this.Y - 10;
            } else {
                value = this.Y + 10;
            }
        }

        //移动身体
        this.moveBody();
        this.head.style.top = value + "px";
    }
    ......
}

......

禁止蛇穿过自己身体

思路很简单,只要检查蛇头和身体坐标是否重复即可,所以在蛇头的坐标更新后检查

class Snake {
	......
    //设置蛇头的坐标
    set X(value: number) {
        ......
        //检查是否撞到自己
        this.checkBody();
    }

    set Y(value: number) {
        ......
        //检查是否撞到自己
        this.checkBody();
    }

    ......

    //检查蛇头和蛇身体是否相撞
    checkBody() {
        for (let i = 1; i < this.bodies.length; i++) {
            let bd = this.bodies[i] as HTMLElement;
            if(this.X === bd.offsetLeft && this.Y === bd.offsetTop){
                //撞到身体,游戏结束
                throw new Error("撞到自己了~~");
            }
        }
    }
}

......

为了测试方便,我们在初始化记分牌的时候,让它最高等级是10,然后每1分升一级,修改 GameControl.ts

this.scorePanel = new ScorePanel(10,1);

最终效果

在这里插入图片描述

源码下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值