140 lines
3.8 KiB
TypeScript
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);
|
|
}
|
|
}
|