ts实现贪吃蛇记录

只记录TS逻辑,不做布局说明

一、主体:

1、食物

2、分数、等级变化

3、蛇(蛇头,蛇身)

4、控制器(键盘监听)

 

二、模块:

1、Food.ts

复制代码
// 食物类
class Food {
    // 定义一个属性表示食物所对应的元素
    element: HTMLElement;
    constructor() {
        // 获取页面中的food元素并赋值给element
        this.element = document.getElementById('food')! ;   // 叹号表示不可能为空
    }
    // 定义一个获取食物X轴坐标的方法
    get X() {
        return this.element.offsetLeft;
    }
    // 定义一个获取食物Y轴坐标的方法
    get Y() {
        retutn this.element.offsetTop;
    }
    // 修改食物的位置
    change() {
        // 生成一个随机的位置
        // 食物的位置最小是0 最大是290
        // 蛇移动一次就是一格,一格的大小就是10
        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' ;
    }    
}
export default Food;
复制代码

 

2、ScorePanel.ts

复制代码
// 记分牌类
class ScorePanel {
    // score 和 level 用来记录分数和等级
    score = 0 ;
    level = 1 ;
    maxLevel = 10;
    // 分数和等级所在的元素,在构造函数中进行初始化
    scoreEle : HTMLElement;
    levelEle : HTMLElement;
    maxLevel : number;
    upScore : number;

    constructor( maxLevel:number = 10, upScore:number = 10 ){
        this.scoreEle = document.getElementById('scoreEle')
        this.levelEle = document.getElementById('levelEle')
        this.maxLevel = maxLevel;
        this.upScore = upScore;
    }
    // 设置一个加分的方法
    addScore(){
        this.scoreEle.innderHTML = ++this.score + '';   //分数自增
        if (this.score % this.upScore === 0 ) {
            this.levelUp();
        }
    }
    // 设置一个等级提升的方法
    levelUp(){
        if (this.level < this.maxLevel) {
            this.levelEle.innderHTML = ++this.level + '';   //等级自增
        } 
    }
}
export default ScorePanel;
复制代码

 

3、Snake.ts

复制代码
class Snake {
    // 表示蛇头的元素
    head: HTMLElement;
    // 蛇的身体(包括蛇头)
    bodies: HTMLCollection;
    // 获取蛇的容器
    element: HTMLElement;

    construcotr(){
        this.element = document.getElementById('snake')! ;
        this.head = document.querySelector('#snake > div') as HTMLElement ;
        this.bodyies = this.element.getElementsByTagName('div') ;
    }

    // 获取蛇的坐标(蛇头坐标)
    get X(){
        return this.head.offsetLeft;
    }
    get Y(){
        return this.head.offsetTop;
    }
    // 设置蛇的坐标(蛇头坐标)
    set X( value : number ){
        // 如果新值和旧值相同,则直接返回不再修改
        if (this.X === value) return;
        // X的值是否再合法范围0-290
        if ( value<0 || value>290 ) {
            throw new Error("蛇撞墙了");
        }
        // 蛇向左时不能往右移动,反之
        if ( this.bodies[1] && (this.bodies[1] as HTMLElement).offerLeft === value ) {
            // 如果发生了掉头,让蛇继续向反方向移动
            if (value>this.X) {
                // 如果新值value大于旧值X,说明蛇在往右走,此时发生掉头,应该使蛇继续向左走
                value = this.X - 10;
            } else {
                value = this.X + 10;
            }
        }
        // 移动身体
        this.moveBody();
        this.head.style.left = value + 'px';
        // 检查有没有撞到自己
        this.checkHeadBody();
    }
    set Y( value : number ){
        if (this.Y === value) return;
        if ( value<0 || value>290 ) {
            throw new Error("蛇撞墙了");
        }
        // 蛇向上时不能往下移动,反之
        if ( this.bodies[1] && (this.bodies[1] as HTMLElement).offerTop === value ) {
            // 如果发生了掉头,让蛇继续向反方向移动
            if (value>this.Y) {
                // 如果新值value大于旧值X,说明蛇在往下走,此时发生掉头,应该使蛇继续向上走
                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] 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";
        }
    }

} 
export default Snake;
复制代码

 

4、GameControl.ts

复制代码
// 游戏控制器,控制其他所有类
import Snake from "./Snake";
import Food from "./Food";
import ScorePanel from "./ScorePanel";
class GameControl {
    // 定义三个属性
    snake: Snake;    
    food: Food;
    scorePanel : ScorePanel;
    // 创建一个属性来存储蛇的移动方向(按键方向)
    direction: string='';   // 字符串默认为空串
    // 创建一个属性用来记录游戏是否结束
    isLive = true;

    constructor() {
        this.snake = new Snake();
        this.food = new Food();
        this.scorePanel = new ScorePanel();
    }
    
    // 游戏的初始化方法,调用后游戏即开始
    init() {
        // 绑定键盘按下事件
        document.addEventListener('keydown', this.keyboardEvent.bind(this) )    // bind
        // 调用run方法,使蛇移动
        this.run();
    }

    // 创建一个键盘按下的响应函数
    keydownHandler(event:keyboardEvent) {
        // 检查event.key的值是否合法
        // ArrowUp ArrowDown ArrowLeft ArrowRight 、 Up Down Left Right
        // 修改direction属性(方向)
        if( event.key )
        this.direction = event.key; 
    }

    // 创建一个控制蛇移动的方法
    run(){
        // 获取蛇现在的坐标
        let X = this.snake.X;
        let Y = this.snake.y;
        // 根据方向(this.direction)来使蛇的位置改变 top- top+ left- left+
        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)

        // 修改蛇的x和y值
        try{
            this.snake.x = X
            this.snake.y = Y
        }catch(e){
            // 进入到catch 说明出现了异常 游戏结束
            alert(e.message);
            this.isLive = false;
        }
        // 开启一个定时调用
        this.isLive && setTimeout( this.run.bind(this), 300 - (this.ScorePanel.level-1)*30 )
    }

    // 定义一个方法,检查蛇是否吃到了食物
    checkEat(X: number, Y: number){
        if (X === this.food.X && Y === this.food.Y) {
            // 食物位置重制
            this.food.change();
            // 分数增加
            this.scorePanel.addScore();
            // 蛇要增加一节
            this.snake.addBody();
        }
    }

    //获取所有的身体,检查是否发生重叠
    checkHeadBody(){
        for(let i = 1; i<this.bodies.length; i++){
            let bd = this.bodies[i] as HTMLElement;
            if (this.X === bd.offsetTop) {
                // 进入判断说明蛇头撞到了自己
                throw new Error("撞到自己了");
            }
        }
    }


}
复制代码

 

来自: https://www.bilibili.com/video/BV1Xy4y1v7S2?p=30&spm_id_from=pageDriver

posted @   Comedyy  阅读(97)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
点击右上角即可分享
微信分享提示