likes
comments
collection
share

ts练习项目-贪吃蛇(格子类)

作者站长头像
站长
· 阅读数 30

项目介绍

学习了typescript语法。教程中的练习项目是贪吃蛇。项目中是利用元素的绝对定位来实现蛇与食物的动作。个人觉得不是很好,于是自己设计了一套实现方法。

项目代码已全部完成,并放到了github

效果演示

ts练习项目-贪吃蛇(格子类)

一、设计构思


在贪吃蛇游戏中,我们可以把整个游戏界面看成由一组正方形格子组成的一个 x * y 的矩形( x 列, y 行)。每个格子只有两种状态:白色或黑色。白色表示空白,黑色表示蛇或者食物。这样整个界面就可以看成一个布尔类型的二维数组。

但是为了更美观,现在希望代表食物的黑色格子和代表蛇的黑色格子样式不一样。很明显这个布尔类型的二维数组已经不能满足我们的需求了。那么让我们再设计一个格子类( Cell ),并将布尔类型的二维数组改成 Cell 二维数组吧。

二、基本功能


这个类中需要有哪些属性和方法呢?

每个 Cell 都对应页面中一个 divdiv 的所有操作都由这个 Cell 管理。另外 Cell 还需要记录当前表示的是什么,即类型。

由于 Cell 的类型只有三种,分别是:空白、食物和蛇。这明显是一个标准的枚举类型。

那么先在项目的常量Constant.ts )中写一个 Cell 的类型枚举吧。

//格子的类型
export const enum CELL_TYPE {
    Empty,
    Snake,
    Food
}

考虑到如果格子的大小是可以自己配置,那不是更 better ?于是项目的常量Constant.ts )中又多了一个 CELL_LENGTH 表示每个格子的长度。

export const CELL_LENGTH = 20;//每格长度

其实 Cell 对应 div 标签的样式是通过添加或移除 class 控制的。我们也顺道在项目的常量Constant.ts )中定义好需要的 class 吧。

export const SNAKE_CLASS = "snake";//蛇的class
export const FOOD_CLASS = "food";//食物的class

终于到 Cell 类了。

注意

  • Cell 中的 div ,需要在构造方法中初始化,并放入 html 页面的“舞台”( stage )中。
  • 代码中的 CELL_LENGTH 需要减 2 ,是因为 div 设置了 1px 的边框。
class Cell {
    private _element: HTMLElement;
    private _type: CELL_TYPE;

    constructor(stage: HTMLElement) {
        this._element = document.createElement("div");
        this._element.style.width = (CELL_LENGTH - 2) + 'px';
        this._element.style.height = (CELL_LENGTH - 2) + 'px';
        this._type = CELL_TYPE.Empty;
        stage.appendChild(this._element);
    }
    
    get type() {
        return this._type;
    }

    set type(type) {
        this._type = type;
    }
}

三、代码优化


细想一下,其实 Cell 中的 typeelement 样式的 class 关系如下。

序号typeclass
1CELL_TYPE.Empty
2CELL_TYPE.SnakeSNAKE_CLASS
3CELL_TYPE.FoodFOOD_CLASS

那么只需在设置 type 的时候把 element 样式的 class 一并改了即可。

set type(type) {
    if (type !== this._type) {
        //类型不同再修改
        this._updateElementClass(this._type, type);
        this._type = type;
    }
}

//设置div样式的class
private _updateElementClass(oldType: CELL_TYPE, newType: CELL_TYPE) {
    if (oldType !== CELL_TYPE.Empty) {
        this._element.classList.remove(
            oldType === CELL_TYPE.Food ?
                FOOD_CLASS : SNAKE_CLASS
        );
    }

    if (newType !== CELL_TYPE.Empty) {
        this._element.classList.add(
            newType === CELL_TYPE.Food ?
                FOOD_CLASS : SNAKE_CLASS
        );
    }
}

完整代码

import {CELL_TYPE, FOOD_CLASS, SNAKE_CLASS, CELL_LENGTH} from "./Constant";

class Cell {
    private _element: HTMLElement;
    private _type: CELL_TYPE;

    constructor(stage: HTMLElement) {
        this._element = document.createElement("div");
        this._element.style.width = (CELL_LENGTH - 2) + 'px';
        this._element.style.height = (CELL_LENGTH - 2) + 'px';
        this._type = CELL_TYPE.Empty;
        stage.appendChild(this._element);
    }

    get type() {
        return this._type;
    }

    set type(type) {
        if (type !== this._type) {
            //类型不同再修改
            this._updateElementClass(this._type, type);
            this._type = type;
        }
    }

    private _updateElementClass(oldType: CELL_TYPE, newType: CELL_TYPE) {
        if (oldType !== CELL_TYPE.Empty) {
            this._element.classList.remove(
                oldType === CELL_TYPE.Food ?
                    FOOD_CLASS : SNAKE_CLASS
            );
        }

        if (newType !== CELL_TYPE.Empty) {
            this._element.classList.add(
                newType === CELL_TYPE.Food ?
                    FOOD_CLASS : SNAKE_CLASS
            );
        }
    }

}


export default Cell;
转载自:https://juejin.cn/post/7369616053552889866
评论
请登录