我使用Immutable.js和Typescript为我正在进行的游戏构建实体组件系统。现在,我正试图充实组件创建方式的语义。我目前的设计比我想要的重复一点,所以我正在寻找改进它的方法。
其中一个主要障碍是我真的希望我的组件是不可变的。更改它们会导致出现新情况,但我无法找到实际执行此操作的方法。
/**
* @file game/Component.ts
*/
/**
* All possible component types. Used for serialization
*/
export enum ComponentType {
OCCUPANCY
};
/**
* Components are used to make entities interesting. Components provide almost
* all of the core game functionality from basic movement to unique items.
* Components are completely independent and should primarily contain data,
* NOT behavior.
*/
export abstract class Component {
/**
* The id of this component
* @type {ComponentID}
*/
public readonly id: ComponentID;
/**
* The type of this component
* @type {ComponentType}
*/
public readonly type: ComponentType;
constructor(type: ComponentType, id: ComponentID) {
this.id = id;
this.type = type;
}
}
/**
* @file game/components/Occupancy.ts
* Describes the occupancy status of a grid cell
*/
import { ComponentType, Component, ComponentID } from "../Component"
import { Entity } from "../Entity"
import { Record } from "immutable"
export type OccupancyStatus = Entity | "free" | "unknown"
export type OccupancyParams = {
status?: Entity | "free" | "unknown"
};
export const OccupancyRecord = Record({
status: "unknown"
});
class OccupancyData extends OccupancyRecord {
/**
* The occupancy status of this entity
* @type {OccupancyStatus}
*/
status: OccupancyStatus;
/**
* Construct a new state with the given parameters
*
* @param {OccupancyParams} params Parameters to use instead of defaults
*/
public constructor(params?: OccupancyParams) {
params ? super(params) : super();
}
/**
* Create a new OccupancyData with the same values as this one except as
* indicated by the provided values
* @param {OccupancyParams} values Values to replace in the new instance
* @return {OccupancyData} New instance
*/
public with(values: OccupancyParams): OccupancyData {
return this.merge(values) as this;
}
}
export class Occupancy extends Component {
public readonly data: OccupancyData;
constructor(id: ComponentID, params?: OccupancyParams) {
super(ComponentType.OCCUPANCY, id);
this.data = new OccupancyData(params);
}
public with(values: OccupancyParams): Occupancy {
const new_data = this.data.with(values);
return new Occupancy(this.id, new_data);
}
}
正如您所看到的,这是非常重复的。我必须为每个组件定义枚举组件的所有属性3次:一次用于Params结构,一次用于定义记录默认值,一次用于添加访问器。此外,没有什么能够真正强制执行这些组件遵循这种结构或使其自身不可变,这对我来说很有趣。