利用TypeScript编写贪吃蛇游戏

目录
  • Explanation
    • 1. tsconfig.json配置
    • 2. HTML & CSS 布局相关
    • 3. TS核心逻辑
  • 项目源码链接

先来康康效果图

我接下来将讲解相关配置和代码,源码链接放在最底下了,在GitHub上。

Explanation

1. tsconfig.json配置

{
    "compilerOptions": {
        "target": "ES2015",
        "module": "ES2015",
        "strict": true,
        "noEmitOnError": true
    }
}

此处是对编译选项进行配置

  • target: 我们将TS转译成JS的版本。
  • module: 模块化的版本。
  • strict: 所有相关的严格模式是否开启。
  • noEmitOnError: 当出现错误时是否停止编译。

2. 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>Document</title>
</head>
<body scroll="no">
    <!-- 创建游戏的主容器 -->
    <div id="main">
        <!-- 设置游戏舞台 -->
        <div id="stage">
            <!-- 设置蛇 -->
            <div id="snack">
                <!-- snack内部的div表示蛇的各部分 -->
                <div></div>
            </div>
            <div id="food">
                <!-- 设置食物的样式 -->
                <div></div>
                <div></div>
                <div></div>
                <div></div>
            </div>
        </div>
        <!-- 设置游戏的积分牌 -->
        <div id="scoreStage">
            <div>SCORE:<span id="score">0</span></div>
            <div>LEVEL:<span id="level">1</span></div>
        </div>
    </div>
</body>
</html>

CSS代码

// 设置变量
@bgColor: #b7d4a8;

// 清除默认样式清除默认样式
* {
    margin: 0;
    padding: 0;
    // 怪异模式
    box-sizing: border-box;
}

body {
    font: bold 20px "Courier";
    width: 100%;
    height: 100%;
    overflow: hidden;
}

// 设置主窗口的样式
#main {
    width: 360px;
    height: 420px;
    background-color: @bgColor;
    margin: 100px auto;
    border: 10px solid #000;
    border-radius: 40px;
    display: flex;
    flex-direction: column;
    align-items: center;
    // 主轴对齐方式
    justify-content: space-around;

}

#stage {
    width: 304px;
    height: 304px;
    border: 2px solid black;
    position: relative;
}

#scoreStage {
    width: 300px;
    display: flex;
    justify-content: space-between;
}

#snack {
    &>div {
        width: 10px;
        height: 10px;
        background-color: #000;
        border: 1px solid @bgColor;
        position: absolute;
    }
}

// 食物
#food {
    width: 10px;
    height: 10px;
    position: absolute;
    left: 40px;
    top: 100px;
    display: flex;
    flex-flow: row wrap;
    justify-content: space-between;
    align-content: space-between;
    &>div {
        width: 4px;
        height: 4px;
        background-color: #000;
        transform: rotate(45deg);
        // border: 1px solid @bgColor;
    }
}

body {
    scroll-behavior: unset;
}

这里面比较有意思是可以通过@xxx来设置CSS变量

比如这里的:@bgColor: #b7d4a8;

3. TS核心逻辑

TS的核心在于Class,所以我们需要定义出非常多的类来对这个贪吃蛇小游戏进行分析。

我们先来看看这个贪吃蛇小游戏有几个主要的部分。

  • 食物
  • 分数版
  • 游戏操控

食物

食物有几个核心逻辑

食物这个类。

首先,我们需要获取其中的横纵坐标。可以设置get来获取X与Y。

其次,当蛇蛇碰到食物的时候,这个食物的位置会改变,可以设置一个change()方法。

class Food {
    // 属性 & 方法
    // 定义食物所对应的元素
    element: HTMLElement;

    constructor() {
        // 加一个 “!”表示这玩意不会为空
        this.element = document.getElementById('food')!;
    }
    // 方法
    // 1. 获取食物的x坐标的方法
    get X() {
        return this.element.offsetLeft;
    }
    // 2. 获取食物的y坐标的方法
    get Y() {
        return this.element.offsetTop;
    }

    // 修改食物位置的方法
    change() {
        // 使用random,生成随机位置
        // 蛇移动一次就是一格,大小为10
        const left = Math.round(Math.random()*29)*10;
        const top = Math.round(Math.random()*29)*10;
        this.element.style.left = left + 'px';
        this.element.style.top = top + 'px';
    }

}

export default Food

蛇的话,话头就很多了。

首先,我们需要获取到蛇头的横纵坐标,还要能够给横纵坐标赋值。

其次,我们需要有方法增加蛇的身子addBody

同时还需要增加身子移动的方式moveBody

当然还需要增加检测机制,舌头不能与身子重叠

这个比较复杂,我们分而析之

1.元素设置与constructor

// 表示蛇的元素
head: HTMLElement;
// 蛇的身体,包括蛇头
bodies: HTMLCollection;
// 获取蛇的容器
element: HTMLElement;
constructor() {
   // 断言一下 | 找到蛇头
  this.head = document.querySelector('#snack > div') as HTMLElement;
  this.element = document.getElementById('snack')!
  this.bodies = this.element.getElementsByTagName('div');
}

这里面的!是用来确定存在id为snack这个元素的。

2.增加身子

addBody() {
    this.element.insertAdjacentHTML("beforeend", "<div></div>")
}

3.移动身子

    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';
        }
    }

4.检测机制

    checkHeadBody() {
        // 获取所有的身体,检查其是否和蛇头的坐标发生重叠
        for(let i=1;i<this.bodies.length;i++) {
            const bd = (this.bodies[i] as HTMLElement)
            if(this.X === bd.offsetLeft && this.Y === bd.offsetTop) {
                // 说明出现了碰撞
                throw Error('撞到自己了~~~')
            }
        }
    }

5.完整代码

class Snack {
    // 表示蛇的元素
    head: HTMLElement;
    // 蛇的身体,包括蛇头
    bodies: HTMLCollection;
    // 获取蛇的容器
    element: HTMLElement;
    constructor() {
        // 断言一下 | 找到蛇头
        this.head = document.querySelector('#snack > div') as HTMLElement;
        this.element = document.getElementById('snack')!
        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
        if(value < 0 || value > 290) {
            throw new Error('您撞墙了')
        }
        // 蛇在往左走,不能往右走
        if(this.bodies[1] && (this.bodies[1] as HTMLElement).offsetLeft === value) {
            // 让蛇向反方向继续移动
            if(value > this.X) {
                // 如果新值大于旧值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('您撞墙了')
        }
        if(this.bodies[1] && (this.bodies[1] as HTMLElement).offsetTop === value) {
            // 让蛇向反方向继续移动
            if(value > this.Y) {
                // 如果新值大于旧值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';
        }
    }

    checkHeadBody() {
        // 获取所有的身体,检查其是否和蛇头的坐标发生重叠
        for(let i=1;i<this.bodies.length;i++) {
            const bd = (this.bodies[i] as HTMLElement)
            if(this.X === bd.offsetLeft && this.Y === bd.offsetTop) {
                // 说明出现了碰撞
                throw Error('撞到自己了~~~')
            }
        }
    }
}

export default Snack

得分面板

这个就比较简单了,主要是得分增加的方法与等级提升的方法。

class scorePanel {
    // score和level用来记录分数和等级
    score: number = 0;
    level: number = 1;
    scoreSpan: HTMLElement;
    levelSpan: HTMLElement;

    // 设置等级
    maxLevel: number;
    // 设置一个变量表示多少分升级
    upScore: number;
    // 给两个需要修改的元素赋值
    constructor(maxLevel: number = 10, upScore: number = 2) {
        this.scoreSpan = document.getElementById('score')!;
        this.levelSpan = document.getElementById('level')!;

        this.maxLevel = maxLevel
        this.upScore = upScore
    }

    // method
    // 设置加分的方法
    addScore() {
        // 分数自增
        this.score += 1
        this.scoreSpan.innerHTML = this.score + '';
        // 判断一下分数是多少
        if(this.score % this.upScore === 0) {
            this.levelUp()
        }
    }

    // 提升等级的方法
    levelUp() {
        if(this.level < this.maxLevel) {
            this.level += 1
            this.levelSpan.innerHTML = this.level + '';
        }
    }
}

export default scorePanel

控制面板

这个逻辑的核心之一是整合,之二是监控键盘keydown事件

关于整合:我们会把其中的蛇,面板,食物都整合到这个类中,所谓一个启动游戏的开关。

    snack: Snack;
    food: Food;
    scorePanel: scorePanel;
    arrowDirection: string = '';
    // 创建一个属性用来记录游戏是否结束
    isLeave: boolean = true
    constructor() {
        this.snack = new Snack();
        this.food = new Food();
        this.scorePanel = new scorePanel();
        this.init();
    }

关于监控键盘事件

这里的核心逻辑就是监控,看是上下左右中的哪一个,然后对应的改变蛇蛇的方向。

其中蛇的移动需要不断的调用run这个函数,所以我们使用isLeave作为开关,用递归来多次调用run这个函数。

import Snack from './snack';
import Food from "./Food";
import scorePanel from './scorePanel';

class GameControl {
    snack: Snack;
    food: Food;
    scorePanel: scorePanel;
    arrowDirection: string = '';
    // 创建一个属性用来记录游戏是否结束
    isLeave: boolean = true
    constructor() {
        this.snack = new Snack();
        this.food = new Food();
        this.scorePanel = new scorePanel();
        this.init();
    }
    // 游戏的初始化方法
    init() {
        // 绑定键盘按下的时间
        // const _this = this
        // 如果不改变这个this,则会绑定到document上面
        // document.addEventListener('keydown', _this.keyDownHandler)
        document.addEventListener('keydown', this.keyDownHandler.bind(this));
        // 调用run方法
        this.run();
    }
    // 创建一个键盘按下的响应函数
    /**
     *  ArrowRight Right
        ArrowLeft Left
        ArrowDown Down
        ArrowUp Up
    */
    keyDownHandler(event: KeyboardEvent) {
        this.arrowDirection = event.key
        // this.run();
    }

    // 创建一个控制蛇移动的方法
    run() {
        // 根据方向(this.direction)来使蛇的位置改变
        // 向上 top -
        // 向下 top +
        // 向左 left -
        // 向右 left +
        let X = this.snack.X;
        let Y = this.snack.Y;
        // 根据按键方向修改值
        switch (this.arrowDirection) {
            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
        }
        try {
            this.snack.X = X;
            this.snack.Y = Y;
        } catch(e: any) {
            alert(e.message)
            this.isLeave = false
        }

        this.checkEat(X, Y)
        // 开启定时调用
        // 这是递归调用
        this.isLeave && 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.snack.addBody()
        }
    }
}

export default GameControl

项目源码链接

Github

以上就是利用TypeScript编写贪吃蛇游戏的详细内容,更多关于TypeScript贪吃蛇游戏的资料请关注我们其它相关文章!

(0)

相关推荐

  • JavaScript TypeScript实现贪吃蛇游戏完整详细流程

    目录 项目背景及简介 多模块需求分析 场景模块需求 食物类模块需求 记分牌模块需求 蛇类模块需求 控制模块需求 项目搭建 ts转译为js代码 package.json包配置文件 webpack.config.js打包工具配置 项目结构搭建 html文件 css文件(这里使用的是less) 项目页面 多模块搭建 完成Food(食物)类 完成ScorePanel(记分牌)类 完成Snake(蛇)类 完成GameControl(控制)类 完成index类(启动项目) 项目启动 总结 项目背景及简介 t

  • 使用Angular9和TypeScript开发RPG游戏的方法

    RPG系统构造 通过对于斗罗大陆小说的游戏化过程,熟悉Angular的结构以及使用TypeScript的面向对象开发方法. 项目地址 人物 和其他RPG游戏类似,游戏里面的人物角色大致有这样的一些属性:生命值,魔法值(魂力),攻击力,防御力,速度.RPG游戏中的角色随着等级的提高,这些属性都会提升,属性提升的快慢则取决于资质,同时,由于在实际战斗中,会出现各种增益和光环效果,这些值都是动态变化的,所以这里将这些属性都设置了Base和Real两套数据. Base属性是指人物的初始属性,是一种固有属

  • 使用 TypeScript 重新编写的 JavaScript 坦克大战游戏代码

    源码下载 源码我已经上传到 CSDN 了,无需资源分,下载地址:http://download.csdn.net/detail/zgynhqf/8565873. 源码使用 VS 2013 +TypeScript 1.4 进行开发.打开后,显示如下图: JsTankGame 1.0:老的使用 JS 编写的坦克游戏. JsTankGame 2.0:新的使用 TS 直接翻译过来的游戏. JsTankGame:在 2.0 的基础上,对类型进行了重构后的新游戏. 重构步骤 由于老的 JS 游戏是采用 MS

  • 利用TypeScript编写贪吃蛇游戏

    目录 Explanation 1. tsconfig.json配置 2. HTML & CSS 布局相关 3. TS核心逻辑 项目源码链接 先来康康效果图 我接下来将讲解相关配置和代码,源码链接放在最底下了,在GitHub上. Explanation 1. tsconfig.json配置 { "compilerOptions": { "target": "ES2015", "module": "ES2015&

  • 从0到1学习JavaScript编写贪吃蛇游戏

    本文实例为大家分享了JavaScript编写贪吃蛇游戏的具体代码,供大家参考,具体内容如下 游戏截图 1.画出游戏界面 var c=document.getElementById("myCanvas"); var cxt=c.getContext("2d");//获取地图 2.给小蛇设置参数 var time = 160 ; //蛇的速度 var x = y = 8; var t = 20; //蛇身长 var map = []; //记录蛇运行路径 var siz

  • python实战之利用pygame实现贪吃蛇游戏(二)

    一.前言 在上一篇博客中,我们实现了基本的界面搭建,这次实现一下逻辑部分. 二.创建蛇 首先,先分析一下蛇的移动,不然我们一定会吃亏的(别问,问就是自己写了一堆无效代码). 蛇的移动其实并没有想象中那样复杂,每一个模块都需要有一个方向,按照方向进行移动. 其实实际上就是一个出队的感觉,即每一个元素都取代上一个元素的位置,然后再按照贪吃蛇当前的方向,移动一下头节点即可. snake.py: """"

  • python实战之利用pygame实现贪吃蛇游戏(一)

    一.前言 之前尝试了自己用pygame写井字棋,这次玩的是贪吃蛇系列. 个人感觉模块可能会比较大,所以选择将函数和主要逻辑代码分在了两个文件中. fuc为函数模块,存储了事件感应和刷新界面等部分. main模块则是游戏的核心. 二.搭建界面 这里我就不重复了,可以先看一下这篇博客 其中界面的基本要素都有. main.py import pygame from fuc import * # 基本属性 lattice_wh = 20 #长宽 snake_color = (84, 255, 159)

  • 基于Android Flutter编写贪吃蛇游戏

    目录 前言 开发步骤: 1.定义蛇和豆子 2.让蛇动起来 3.使用陀螺仪来控制蛇 4.让蛇吃掉豆子 5.吃掉豆子随机生成一个豆子 前言 放假期间,小T打算回顾一下经典,想用Flutter做一下小游戏,做什么好呢,从打飞机到坦克大战,最后还是想做一款贪吃蛇,依稀还记得,小时候第一次玩游戏是在父母的小灵通上玩贪吃蛇哈哈,但是光光一个贪吃蛇太单调了,我们就加一个陀螺仪吧~ 话不多说,先上效果图,有图有真相!!(陀螺仪好难操控)! 开发步骤: 非常简单,就是玩起来有点费手~ github仓库还没有搭建,

  • Python利用手势识别实现贪吃蛇游戏

    目录 一.前言 二.项目介绍 1.游戏的操作方式 2.开发的过程中的注意事项 三.游戏的实现要点 1.选择第三方库 2.找到关键点并标记 3.创建一个类来保存关于游戏的所有功能 4.定义函数进行不断更新 四.总体代码 一.前言 想必大家都玩过贪吃蛇的游戏吧:通过操纵蛇的移动方向能够让蛇吃到随机出现的食物,吃到的食物越多,蛇就会变得越长,但如果不小心撞到了自己,那么蛇就会死亡,game over!! 我们玩过的贪吃蛇游戏一般都是在手机或者游戏机上进行的,通过方向键操纵蛇的移动,那么我们是否可以直接

  • 教你一步步利用python实现贪吃蛇游戏

    0 引言 前几天,星球有人提到贪吃蛇,一下子就勾起了我的兴趣,毕竟在那个Nokia称霸的年代,这款游戏可是经典中的经典啊!而用Python(蛇)玩Snake(贪吃蛇),那再合适不过了

  • javascript编写贪吃蛇游戏

    代码很简单,这里就不多BB了,小伙伴们直接看示例吧 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta

  • 用最少的JS代码写出贪吃蛇游戏

    曾经诺基亚的贪吃蛇风靡一时,在游戏匮乏的年代,用java实现太难,现在网页制作20行代码就做成一个简单的demo了,时代在进步啊 完整脚本代码: <!doctype html> <html> <body> <canvas id="can" width="400" height="400" style="background: Black"></canvas> <

随机推荐