diff options
Diffstat (limited to 'engine/entities')
-rw-r--r-- | engine/entities/Entity.ts | 46 | ||||
-rw-r--r-- | engine/entities/Floor.ts | 41 | ||||
-rw-r--r-- | engine/entities/Player.ts | 67 | ||||
-rw-r--r-- | engine/entities/index.ts | 7 | ||||
-rw-r--r-- | engine/entities/names.ts | 4 |
5 files changed, 125 insertions, 40 deletions
diff --git a/engine/entities/Entity.ts b/engine/entities/Entity.ts index ca8d314..63fb370 100644 --- a/engine/entities/Entity.ts +++ b/engine/entities/Entity.ts @@ -1,13 +1,17 @@ -import type { Component } from "../components"; +import { EntityNames, Floor, Player } from '.'; +import { type Component } from '../components'; -export abstract class Entity { - private static ID = 0; +const randomId = () => + (performance.now() + Math.random() * 10_000_000).toString(); - public readonly id: number; - public readonly components: Map<string, Component>; +export abstract class Entity { + public id: string; + public components: Map<string, Component>; + public name: string; - constructor() { - this.id = Entity.ID++; + constructor(name: string, id: string = randomId()) { + this.name = name; + this.id = id; this.components = new Map(); } @@ -17,7 +21,7 @@ export abstract class Entity { public getComponent<T extends Component>(name: string): T { if (!this.hasComponent(name)) { - throw new Error("Entity does not have component " + name); + throw new Error('Entity does not have component ' + name); } return this.components.get(name) as T; } @@ -29,4 +33,30 @@ export abstract class Entity { public hasComponent(name: string): boolean { return this.components.has(name); } + + public static from(entityName: string, id: string, args: any): Entity { + let entity: Entity; + + switch (entityName) { + case EntityNames.Player: + const player = new Player(); + player.setFrom(args); + entity = player; + break; + case EntityNames.Floor: + const floor = new Floor(args.floorWidth); + floor.setFrom(args); + entity = floor; + break; + default: + throw new Error('.from() Entity type not implemented: ' + entityName); + } + + entity.id = id; + return entity; + } + + public abstract setFrom(args: Record<string, any>): void; + + public abstract serialize(): Record<string, any>; } diff --git a/engine/entities/Floor.ts b/engine/entities/Floor.ts index 44587e6..b4f48e5 100644 --- a/engine/entities/Floor.ts +++ b/engine/entities/Floor.ts @@ -1,15 +1,19 @@ -import { IMAGES, SPRITE_SPECS, Sprites, type SpriteSpec } from "../config"; -import { BoundingBox, Sprite } from "../components"; -import { TopCollidable } from "../components/TopCollidable"; -import { Entity } from "../entities"; +import { IMAGES, SPRITE_SPECS, Sprites, type SpriteSpec } from '../config'; +import { BoundingBox, ComponentNames, Sprite } from '../components'; +import { TopCollidable } from '../components/TopCollidable'; +import { Entity, EntityNames } from '../entities'; export class Floor extends Entity { private static spriteSpec: SpriteSpec = SPRITE_SPECS.get( - Sprites.FLOOR, + Sprites.FLOOR ) as SpriteSpec; + private width: number; + constructor(width: number) { - super(); + super(EntityNames.Floor); + + this.width = width; this.addComponent( new Sprite( @@ -17,17 +21,28 @@ export class Floor extends Entity { { x: 0, y: 0 }, { width, height: Floor.spriteSpec.height }, Floor.spriteSpec.msPerFrame, - Floor.spriteSpec.frames, - ), + Floor.spriteSpec.frames + ) ); + this.addComponent(new TopCollidable()); + } + + public serialize() { + return { + floorWidth: this.width, + boundingBox: this.getComponent<BoundingBox>(ComponentNames.BoundingBox) + }; + } + + public setFrom(args: any) { + const { boundingBox } = args; this.addComponent( new BoundingBox( - { x: 300, y: 300 }, - { width, height: Floor.spriteSpec.height }, - ), + boundingBox.center, + boundingBox.dimension, + boundingBox.rotation + ) ); - - this.addComponent(new TopCollidable()); } } diff --git a/engine/entities/Player.ts b/engine/entities/Player.ts index 45d7500..4d91c6f 100644 --- a/engine/entities/Player.ts +++ b/engine/entities/Player.ts @@ -1,5 +1,5 @@ -import { Entity } from "."; -import { IMAGES, SPRITE_SPECS, Sprites, type SpriteSpec } from "../config"; +import { Entity, EntityNames } from '.'; +import { IMAGES, SPRITE_SPECS, Sprites, type SpriteSpec } from '../config'; import { Jump, FacingDirection, @@ -10,32 +10,38 @@ import { WallBounded, Forces, Collide, - Control, Mass, Moment, -} from "../components"; -import { Direction } from "../interfaces"; + ComponentNames, + Control +} from '../components'; +import { Direction } from '../interfaces'; export class Player extends Entity { private static MASS: number = 10; - private static MOI: number = 1000; + private static MOI: number = 100; private static spriteSpec: SpriteSpec = SPRITE_SPECS.get( - Sprites.COFFEE, + Sprites.COFFEE ) as SpriteSpec; constructor() { - super(); + super(EntityNames.Player); this.addComponent( new BoundingBox( - { x: 300, y: 100 }, + { + x: 0, + y: 0 + }, { width: Player.spriteSpec.width, height: Player.spriteSpec.height }, - 0, - ), + 0 + ) ); - this.addComponent(new Velocity({ dx: 0, dy: 0 }, 0)); + this.addComponent( + new Velocity({ dCartesian: { dx: 0, dy: 0 }, dTheta: 0 }) + ); this.addComponent(new Mass(Player.MASS)); this.addComponent(new Moment(Player.MOI)); @@ -43,7 +49,6 @@ export class Player extends Entity { this.addComponent(new Gravity()); this.addComponent(new Jump()); - this.addComponent(new Control()); this.addComponent(new Collide()); this.addComponent(new WallBounded()); @@ -59,11 +64,41 @@ export class Player extends Entity { { x: 0, y: 0 }, { width: Player.spriteSpec.width, height: Player.spriteSpec.height }, Player.spriteSpec.msPerFrame, - Player.spriteSpec.frames, - ), + Player.spriteSpec.frames + ) ); this.addComponent(new FacingDirection(leftSprite, rightSprite)); - this.addComponent(leftSprite); // face Left by default + this.addComponent(leftSprite); // face left by default + } + + public serialize(): Record<string, any> { + return { + control: this.getComponent<Control>(ComponentNames.Control), + boundingBox: this.getComponent<BoundingBox>(ComponentNames.BoundingBox), + velocity: this.getComponent<Velocity>(ComponentNames.Velocity), + forces: this.getComponent<Forces>(ComponentNames.Forces) + }; + } + + public setFrom(args: Record<string, any>) { + const { control, velocity, forces, boundingBox } = args; + + let center = boundingBox.center; + + const myCenter = this.getComponent<BoundingBox>( + ComponentNames.BoundingBox + ).center; + const distance = Math.sqrt( + Math.pow(center.y - myCenter.y, 2) + Math.pow(center.x - myCenter.x, 2) + ); + if (distance < 30) center = myCenter; + + [ + Object.assign(new Control(control.controllableBy), control), + new Velocity(velocity.velocity), + new Forces(forces.forces), + new BoundingBox(center, boundingBox.dimension, boundingBox.rotation) + ].forEach((component) => this.addComponent(component)); } } diff --git a/engine/entities/index.ts b/engine/entities/index.ts index a921512..8aee83c 100644 --- a/engine/entities/index.ts +++ b/engine/entities/index.ts @@ -1,3 +1,4 @@ -export * from "./Entity"; -export * from "./Floor"; -export * from "./Player"; +export * from './Entity'; +export * from './Floor'; +export * from './Player'; +export * from './names'; diff --git a/engine/entities/names.ts b/engine/entities/names.ts new file mode 100644 index 0000000..cf65f9f --- /dev/null +++ b/engine/entities/names.ts @@ -0,0 +1,4 @@ +export namespace EntityNames { + export const Player = 'Player'; + export const Floor = 'Floor'; +} |