base2020/src/Ecs/Components.ts

140 lines
3.8 KiB
TypeScript

import { Layer, SpriteSheet } from "../Applet/Render";
import { Component, copyDense, copySparse, EntityState, StateForSchema, Store } from "./Data";
export class Box {
constructor(
public x: number, public y: number,
public w: number, public h: number
) {};
};
/**
* Return source moved towards target by speed, without going past.
*/
export function Approach(source: number, target: number, speed: number): number {
const delta = target - source;
if(Math.abs(delta) <= speed) {
return target;
} else {
return source + Math.sign(delta) * speed;
}
}
/**
* pairs of vertex coordinates in ccw winding order
*/
export interface Polygon {
points: number[];
}
export class PolygonComponent extends Component<PolygonComponent> {
points: number[];
constructor(from: Partial<PolygonComponent>) {
super(from);
this.points = from.points?.slice() ?? []
};
clone() {
return new PolygonComponent(this);
}
}
export class Location extends Component<Location> {
X: number;
Y: number;
Angle: number;
VX: number;
VY: number;
VAngle: number;
constructor(from: Partial<Location>) {
super(from);
this.X = from.X ?? 0;
this.Y = from.Y ?? 0;
this.Angle = from.Angle ?? 0;
this.VX = from.VX ?? 0;
this.VY = from.VY ?? 0;
this.VAngle = from.VAngle ?? 0;
};
clone() {
return new Location(this);
}
}
export class CollisionClass extends Component<CollisionClass> {
public name: string;
constructor(from: Partial<CollisionClass>) {
super(from);
this.name = from.name ?? "unknown";
};
clone() {
return new CollisionClass(this);
}
}
export class RenderBounds extends Component<RenderBounds> {
public color: string;
public layer: number;
constructor(from: Partial<RenderBounds>) {
super(from);
this.color = from.color ?? "#f00";
this.layer = from.layer ?? 1;
};
clone() {
return new RenderBounds(this);
}
};
export class RenderSprite extends Component<RenderSprite> {
// TODO: make this an id/handle for serializability
public sheet: SpriteSheet;
public layer: number;
public index: number;
public offsetX: number;
public offsetY: number;
constructor(from: Partial<RenderSprite> & {sheet: SpriteSheet}) {
super(from);
this.sheet = from.sheet;
this.layer = from.layer ?? 1;
this.index = from.index ?? 0;
this.offsetX = from.offsetX ?? 0;
this.offsetY = from.offsetY ?? 0;
};
clone() {
return new RenderSprite(this);
}
};
export interface ComponentSchema {
location: Location;
bounds: PolygonComponent;
renderBounds: RenderBounds;
renderSprite: RenderSprite;
collisionSourceClass: CollisionClass;
collisionTargetClass: CollisionClass;
}
export class Data implements StateForSchema<ComponentSchema> {
entity: EntityState[];
location: Store<Location>;
bounds: Store<PolygonComponent>;
renderBounds: Store<RenderBounds>;
renderSprite: Store<RenderSprite>;
collisionSourceClass: Store<CollisionClass>;
collisionTargetClass: Store<CollisionClass>;
layers: Layer[] = [new Layer(0), new Layer(1)];
constructor(from: Partial<Data>) {
this.entity = copyDense(from.entity);
this.location = copyDense(from.location);
this.bounds = copyDense(from.bounds);
this.renderBounds = copySparse(from.renderBounds);
this.renderSprite = copySparse(from.renderSprite);
this.collisionSourceClass = copySparse(from.collisionSourceClass);
this.collisionTargetClass = copySparse(from.collisionTargetClass);
}
clone() {
return new Data(this);
}
}