【TypeScript】贪吃蛇小游戏

这篇博客介绍了如何用TypeScript实现一个贪吃蛇小游戏,包括Food、ScorePanel、Snake和GameControl四个核心类的设计。食物类负责生成食物,记分牌类管理分数和等级,蛇类通过更新其身体位置来移动,而整个游戏控制类则整合了游戏逻辑。项目源码已开源在Gitee上。
摘要由CSDN通过智能技术生成

效果预览

在这里插入图片描述

项目结构

在这里插入图片描述
共有Food,GameControl,ScorePanel,Snake四个类

食物类

//食物类
class Food {
  //食物所对应的元素
  element: HTMLElement;
  constructor() {
    this.element = document.getElementById('food');
  }

  //获取食物位置的方法
  get X() {
    return this.element.offsetLeft;
  }
  get Y() {
    return this.element.offsetTop;
  }

  //食物位置的修改
  change() {
    //生成随机位置
    //0~290的随机数,一格是10px
    //Math.round(Math.random() * 29) * 10
    let Left = Math.round(Math.random() * 29) * 10;
    let Top = Math.round(Math.random() * 29) * 10;
    this.element.style.left = Left + 'px';
    this.element.style.top = Top + 'px';
  }
}

export default Food;

记分牌类

记分牌只需要控制自己的分数增长和等级提高

/**
 * 记分牌
 */

 class ScorePanel {
  //分数和等级
  score = 0;
  level = 1;
  scoreEle: HTMLElement;
  leveEle: HTMLElement;

  //等级限制
  maxLevel: number;

  //多少分升级
  upLevel: number;

  constructor(maxLevel: number = 10, upLevel: number = 10) {
    this.scoreEle = document.getElementById('score');
    this.leveEle = document.getElementById('level');
    this.maxLevel = maxLevel;
    this.upLevel = upLevel;
  }

  //分数增加方法
  addScore() {
    this.scoreEle.innerHTML = ++this.score + '';

    //每10分升1级
    if(this.score % this.upLevel == 0) {
      this.addLevel();
    }
  }

  //等级提升
  addLevel() {
    if(this.level < 10) {
      this.leveEle.innerHTML = ++this.level + '';
    }
  }
}

export default ScorePanel;

蛇类

蛇类最主要的是身体如何根据蛇头来改变位置
这里是对蛇身体除了蛇头进行遍历,将前一个div的位置赋值给后一个div的位置

/**
 * snake
 */

class Snake {
  //蛇头
  head: HTMLElement;

  //蛇身体
  bodies: HTMLCollection;

  //蛇的容器
  element: HTMLElement;

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

  //获取蛇头的坐标
  get X() {
    return this.head.offsetLeft;
  }
  get Y() {
    return this.head.offsetTop;
  }

  //给蛇头坐标赋值
  set X(value: number) {
    if (this.X === value) {
      return;
    }
    if (value < 0 || value > 290) {
      throw new Error("游戏结束");
    }
    if (
      this.bodies[1] &&
      value === (this.bodies[1] as HTMLElement).offsetLeft
    ) {
      if (value > this.X) {
        value = this.X - 10;
      } else {
        value = this.X + 10;
      }
    }
    this.bodyMove();
    this.head.style.left = `${value}px`;
    this.checkHead();
  }
  set Y(value: number) {
    if (this.Y === value) {
      return;
    }
    if (value < 0 || value > 290) {
      throw new Error("游戏结束");
    }
    if (this.bodies[1] && value === (this.bodies[1] as HTMLElement).offsetTop) {
      if (value > this.Y) {
        value = this.Y - 10;
      } else {
        value = this.Y + 10;
      }
    }
    this.bodyMove();
    this.head.style.top = `${value}px`;
    this.checkHead();
  }

  //蛇的身体增加
  addBody() {
    this.element.insertAdjacentHTML("beforeend", "<div></div>");
  }

  bodyMove() {
    //遍历到除了蛇头意外的div
    for (let i = this.bodies.length - 1; i > 0; i--) {
      //获取前一个div的位置
      let preX = (this.bodies[i - 1] as HTMLElement).offsetLeft;
      let preY = (this.bodies[i - 1] as HTMLElement).offsetTop;

      //将前一个的位置赋值给当前div的位置
      (this.bodies[i] as HTMLElement).style.left = `${preX}px`;
      (this.bodies[i] as HTMLElement).style.top = `${preY}px`;
    }
  }

  //检查蛇头有没有撞到自己
  checkHead() {
    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("蛇撞到自己的身体了");
      }
    }
  }
}

export default Snake;

整个游戏控制类

import Food from "./Food";
import ScorePanel from "./ScorePanel";
import Snake from "./Snake";

//游戏控制器
class GameControl {
  //蛇
  snake: Snake;
  food: Food;
  scorePanel: ScorePanel;

  //存储蛇的移动方向
  direction: string;

  //记录游戏是否结束
  isLive: boolean = true;

  constructor() {
    this.snake = new Snake();
    this.food = new Food();
    this.scorePanel = new ScorePanel(10, 2);

    this.init();
  }

  //初始化
  init() {
    document.addEventListener("keydown", this.keyDownHandler.bind(this));
    this.run();
  }

  keyDownHandler(event: KeyboardEvent) {
    //判断按键是否合法
    this.direction = event.key;
  }

  //让蛇移动的方法
  run() {
    let X = this.snake.X;
    let Y = this.snake.Y;

    switch (this.direction) {
      case "ArrowUp":
        Y -= 10;
        break;
      case "ArrowDown":
        Y += 10;
        break;
      case "ArrowLeft":
        X -= 10;
        break;
      case "ArrowRight":
        X += 10;
        break;
    }
    //检查蛇是否吃到食物
    this.checkEat(X, Y);

    try {
      this.snake.X = X;
      this.snake.Y = Y;
    } catch (err) {
      alert(err);
      this.isLive = false;
    }
    this.isLive &&
      setTimeout(this.run.bind(this), 300 - (this.scorePanel.level - 1) * 50);
  }

  checkEat(x: number, y: number) {
    if (x === this.food.X && y === this.food.Y) {
      this.food.change();
      this.scorePanel.addScore();
      this.snake.addBody();
    }
  }
}

export default GameControl;

完整项目代码

https://gitee.com/tao-yuhan/type-script-snake.git

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

boboj1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值