diff --git a/Assets/Background.aseprite b/Assets/Background.aseprite index 433a27d..9887b92 100644 Binary files a/Assets/Background.aseprite and b/Assets/Background.aseprite differ diff --git a/Assets/Human.aseprite b/Assets/Human.aseprite index 617a3c4..e63b305 100644 Binary files a/Assets/Human.aseprite and b/Assets/Human.aseprite differ diff --git a/Program/assets/Background.png b/Program/assets/Background.png index 177f7d0..16bd992 100644 Binary files a/Program/assets/Background.png and b/Program/assets/Background.png differ diff --git a/Program/assets/Human.png b/Program/assets/Human.png index 6295155..4f38875 100644 Binary files a/Program/assets/Human.png and b/Program/assets/Human.png differ diff --git a/Program/src/Components/adventure.ts b/Program/src/Components/adventure.ts new file mode 100644 index 0000000..ae5a2ce --- /dev/null +++ b/Program/src/Components/adventure.ts @@ -0,0 +1,19 @@ +import { Component, Entity } from "ecsy" + +// Door component +export class Adventure extends Component { + members: Entity[] + arrivalTime: Date + + copy(values: any){ + if(values.members) + this.members = values.members + if(values.arrivalTime) + this.arrivalTime = values.arrivalTime + } + + reset() { + this.members = [] + this.arrivalTime = new Date() + } +} \ No newline at end of file diff --git a/Program/src/Components/appearance.ts b/Program/src/Components/appearance.ts new file mode 100644 index 0000000..6a66822 --- /dev/null +++ b/Program/src/Components/appearance.ts @@ -0,0 +1,13 @@ +import { Component } from "ecsy"; +import { Texture } from "pixi.js"; + + +export class Appearance extends Component{ + + + idleTexture: Texture + + reset(){ + this.idleTexture = null + } +} \ No newline at end of file diff --git a/Program/src/Components/debugRect.ts b/Program/src/Components/debugRect.ts new file mode 100644 index 0000000..7b91e70 --- /dev/null +++ b/Program/src/Components/debugRect.ts @@ -0,0 +1,13 @@ +import { Component } from "ecsy"; +import { AABB } from "../Datatypes/aabb"; + + +export class DebugRect extends Component{ + color = 0xFF0000 + rect: AABB + + reset(){ + this.color = 0xFF0000 + this.rect = new AABB(0, 0, 0, 0) + } +} \ No newline at end of file diff --git a/Program/src/Components/door.ts b/Program/src/Components/door.ts index 642cc83..ed742b4 100644 --- a/Program/src/Components/door.ts +++ b/Program/src/Components/door.ts @@ -1,14 +1,14 @@ -import { Point } from "../Datatypes/point" import { Texture } from "pixi.js" import { Component } from "ecsy" +import { Vector } from "../Datatypes/vector" // Door component export class Door extends Component { open: boolean - openPosition: Point - closedPosition: Point + openOffset: Vector + closedOffset: Vector openTex: Texture closedTex: Texture @@ -16,8 +16,8 @@ export class Door extends Component { reset() { this.open = false - this.openPosition = null - this.closedPosition = null + this.openOffset = new Vector(0,0) + this.closedOffset = new Vector(0,0) this.openTex = null this.closedTex = null diff --git a/Program/src/Components/human.ts b/Program/src/Components/human.ts new file mode 100644 index 0000000..159f4be --- /dev/null +++ b/Program/src/Components/human.ts @@ -0,0 +1,9 @@ +import { Component } from "ecsy" + +// Door component +export class Human extends Component { + + + reset() { + } +} \ No newline at end of file diff --git a/Program/src/Components/inCabin.ts b/Program/src/Components/inCabin.ts new file mode 100644 index 0000000..e9e917b --- /dev/null +++ b/Program/src/Components/inCabin.ts @@ -0,0 +1,4 @@ +import { TagComponent } from "ecsy"; + + +export class InCabin extends TagComponent {} \ No newline at end of file diff --git a/Program/src/Components/name.ts b/Program/src/Components/name.ts new file mode 100644 index 0000000..3b7f9fc --- /dev/null +++ b/Program/src/Components/name.ts @@ -0,0 +1,22 @@ +import { Component } from "ecsy"; + +export class Name extends Component{ + first: string + last: string + nick: string + + fullName():string{ + return `${this.first} ${this.last}` + } + + copy(values: any){ + if(values.first) + this.first = values?.first + } + + reset(){ + this.first = "firstname" + this.last = "lastname" + this.nick = "nickname" + } +} \ No newline at end of file diff --git a/Program/src/Components/orderZ.ts b/Program/src/Components/orderZ.ts new file mode 100644 index 0000000..22b509c --- /dev/null +++ b/Program/src/Components/orderZ.ts @@ -0,0 +1,10 @@ +import { Component } from "ecsy" + + +export class OrderZ extends Component{ + offset = 0 + + reset(){ + this.offset = 0 + } +} \ No newline at end of file diff --git a/Program/src/Components/pathWalker.ts b/Program/src/Components/pathWalker.ts new file mode 100644 index 0000000..607d911 --- /dev/null +++ b/Program/src/Components/pathWalker.ts @@ -0,0 +1,15 @@ +import { Component } from "ecsy"; +import { Path } from "../Datatypes/path"; + + +export class PathWalker extends Component { + path: Path + progress: number + speed: number //speed in pixels per second + + reset(){ + this.path = null + this.progress = 0 + this.speed = 0 + } +} \ No newline at end of file diff --git a/Program/src/Components/pixiRepresentation.ts b/Program/src/Components/pixiRepresentation.ts new file mode 100644 index 0000000..d570a16 --- /dev/null +++ b/Program/src/Components/pixiRepresentation.ts @@ -0,0 +1,10 @@ +import { SystemStateComponent } from "ecsy"; +import { DisplayObject } from "pixi.js"; + +export class PixiRepresentation extends SystemStateComponent { + value: DisplayObject + + reset(){ + this.value = null + } +} \ No newline at end of file diff --git a/Program/src/Components/position.ts b/Program/src/Components/position.ts index 33b7779..4f61505 100644 --- a/Program/src/Components/position.ts +++ b/Program/src/Components/position.ts @@ -5,6 +5,12 @@ import { Component } from "ecsy" export class Position extends Component { value: Point + //position is used so often copy is performance sensitive I assume??? + //this can crash with wrong values, but I trust my code enough to pass ONE variable + copy(values:any){ + this.value = values.value + } + reset() { this.value = new Point(0, 0) } diff --git a/Program/src/Components/shape.ts b/Program/src/Components/shape.ts deleted file mode 100644 index 0b97b41..0000000 --- a/Program/src/Components/shape.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Component } from "ecsy" - -// Shape component -export class Shape extends Component { - onStage = false - shape: PIXI.Graphics - - reset() { - this.onStage = false - this.shape = null - } -} \ No newline at end of file diff --git a/Program/src/Components/spriteRenderer.ts b/Program/src/Components/spriteRenderer.ts index b93c1ec..f632d81 100644 --- a/Program/src/Components/spriteRenderer.ts +++ b/Program/src/Components/spriteRenderer.ts @@ -1,10 +1,14 @@ -import { Sprite } from "pixi.js"; +import { Texture } from "pixi.js"; import { Component } from "ecsy"; +import { Vector } from "../Datatypes/vector"; +//todo: consider making this a systemstatecomponent so system order isn't as critical for removing sprites export class SpriteRenderer extends Component{ - sprite: Sprite + texture: Texture + offset: Vector reset() :void { - this.sprite = null + this.texture = null + this.offset = new Vector(0, 0) } } \ No newline at end of file diff --git a/Program/src/Components/velocity.ts b/Program/src/Components/velocity.ts deleted file mode 100644 index 1f62230..0000000 --- a/Program/src/Components/velocity.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Vector } from "../Datatypes/vector" -import { Component } from "ecsy" - -// Velocity component -export class Velocity extends Component { - value: Vector - - reset() { - this.value = new Vector(0, 0) - } -} \ No newline at end of file diff --git a/Program/src/Components/walkArea.ts b/Program/src/Components/walkArea.ts new file mode 100644 index 0000000..0a5e5e4 --- /dev/null +++ b/Program/src/Components/walkArea.ts @@ -0,0 +1,6 @@ +import { Component } from "ecsy"; + + +export class WalkArea extends Component{ + +} \ No newline at end of file diff --git a/Program/src/Datatypes/aabb.ts b/Program/src/Datatypes/aabb.ts new file mode 100644 index 0000000..68bb1a5 --- /dev/null +++ b/Program/src/Datatypes/aabb.ts @@ -0,0 +1,60 @@ +import { Point } from "./point"; +import { Vector } from "./vector"; +import { RNG } from "./rng"; + + +export class AABB{ + source: Point + size: Vector + + constructor(x:number, y:number, width:number, height:number){ + this.source = new Point(x, y) + this.size = new Vector(width, height) + } + + ///get corners clockwise starting at the upper left corner + corners(): Point[]{ + return [ + this.source, + new Point(this.source.x + this.size.x, this.source.y), + this.source.add(this.size), + new Point(this.source.x + this.size.x, this.source.y), + ] + } + + center(): Point{ + return this.source.add(this.size.scale(0.5)) + } + + containsPoint(other: Point): boolean{ + return other.gt(this.min()) && other.lt(this.max()) + } + + containsAABB(other: AABB): boolean{ + return this.min().lt(other.min()) && this.max().gt(other.max()) + } + + overlapsAABB(other: AABB): boolean{ + return this.min().lt(other.max()) && this.max().gt(other.min()) + } + + min(): Point{ + return this.source + } + + area(): number{ + return this.size.x * this.size.y + } + + max(): Point{ + return this.source.add(this.size) + } + + randomPoint(generator?: RNG): Point{ + if (generator) + //allow custom rng for deterministic values + return this.source.add(this.size.scale2(generator.random(), generator.random())) + else + return this.source.add(this.size.scale2(Math.random(), Math.random())) + } +} \ No newline at end of file diff --git a/Program/src/Datatypes/path.ts b/Program/src/Datatypes/path.ts new file mode 100644 index 0000000..3b3b92d --- /dev/null +++ b/Program/src/Datatypes/path.ts @@ -0,0 +1,37 @@ +import { Point } from "./point"; +import { clamp } from "../util"; + + +//todo: consider caching some stuff for performance +export class Path{ + points: Point[] + + calculateLength(): number{ + length = 0 + for(let i=1;i other.x && this.y > other.y + } + + lt(other: Point):boolean{ + return this.x < other.x && this.y < other.y } set(x?: number, y?: number): this { diff --git a/Program/src/Datatypes/rng.ts b/Program/src/Datatypes/rng.ts new file mode 100644 index 0000000..b8cd3a5 --- /dev/null +++ b/Program/src/Datatypes/rng.ts @@ -0,0 +1,7 @@ + +export interface RNG{ + seed?:number ///the random seed + random():number ///simple 0-1 random function (0 incl, 1 excl) + range(min:number, max:number):number ///random value from min incl to max excl + setSeed(seed:number):void ///set a new seed and reset the random chain +} \ No newline at end of file diff --git a/Program/src/Datatypes/vector.ts b/Program/src/Datatypes/vector.ts index 093d1bc..c10f595 100644 --- a/Program/src/Datatypes/vector.ts +++ b/Program/src/Datatypes/vector.ts @@ -10,29 +10,28 @@ export class Vector implements IPoint{ this.y = y } - normalize(): this { + normalize(): Vector { let len = this.length() if(len < 0.001){ - this.set(0, 0) + return new Vector(0,0) } else { - this.scale(1/len) + return this.scale(1/len) } - return this } length(): number { return Math.sqrt(this.x*this.x + this.y*this.y) } - scale(scalar: number): this { - this.set(this.x*scalar, this.y*scalar) - return this - } - - scaled(scalar: number): Vector { + scale(scalar: number): Vector { return new Vector(this.x * scalar, this.y * scalar) } + scale2(x: number, y: number): Vector { + return new Vector(this.x * x, this.y * y) + } + + //IPoint interface functions set(x?: number, y?: number): void { if (x !== undefined) this.x = x diff --git a/Program/src/Systems/AdventureReturnSystem.ts b/Program/src/Systems/AdventureReturnSystem.ts new file mode 100644 index 0000000..102230f --- /dev/null +++ b/Program/src/Systems/AdventureReturnSystem.ts @@ -0,0 +1,39 @@ +import { System, Entity } from "ecsy" +import { Adventure } from "../Components/adventure" +import { InCabin } from "../Components/inCabin" + +// MovableSystem +export class AdventureReturnSystem extends System { + priority = -100 + // This method will get called on every frame by default + execute(delta : number) { + //TODO: consider only executing this every few seconds? + let now = Date.now() + // Iterate through all the entities on the query + this.queries.adventures.results.forEach((entity: Entity) => { + let adventure = entity.getComponent(Adventure) + if(adventure.arrivalTime.getTime() < now) + this.arriveAdventure(entity, adventure) + }) + } + + arriveAdventure(entity: Entity, adventure?: Adventure){ + if(!adventure) + adventure = entity.getComponent(Adventure) + + //TODO: resource management + + adventure.members.forEach((member: Entity) => { + member.addComponent(InCabin) + }); + + entity.remove() + } + + static queries = { + adventures: { + components: [ Adventure ] + }, + } + queries: any +} \ No newline at end of file diff --git a/Program/src/Systems/DebugRenderSystem.ts b/Program/src/Systems/DebugRenderSystem.ts new file mode 100644 index 0000000..912c782 --- /dev/null +++ b/Program/src/Systems/DebugRenderSystem.ts @@ -0,0 +1,44 @@ +import { System, Entity, Not } from "ecsy" +import { DebugRect } from "../Components/debugRect"; +import { PixiRepresentation } from "../Components/pixiRepresentation"; +import { Graphics, DisplayObject } from "pixi.js"; +import { app } from ".."; + +// MovableSystem +export class DebugRenderSystem extends System { + priority: 90 + + // This method will get called on every frame by default + execute(delta : number) { + // Iterate through all the entities on the query + this.queries.newRectangles.results.forEach((entity: Entity) => { + let debugRect = entity.getComponent(DebugRect) + let graphic = new Graphics() + graphic.lineStyle(1, debugRect.color, 0.5) + graphic.drawRect(debugRect.rect.source.x, debugRect.rect.source.y, debugRect.rect.size.x, debugRect.rect.size.y) + app.stage.addChild(graphic) + entity.addComponent(PixiRepresentation, {value: graphic}) + }) + + this.queries.rectangles.changed.forEach((entity: Entity) => { + let debugRect = entity.getComponent(DebugRect) + let graphic = entity.getMutableComponent(PixiRepresentation).value as Graphics + graphic.clear + graphic.lineStyle(1, debugRect.color, 0.5) + graphic.drawRect(debugRect.rect.source.x, debugRect.rect.source.y, debugRect.rect.size.x, debugRect.rect.size.y) + }) + } + + static queries = { + newRectangles: { + components: [ DebugRect, Not(PixiRepresentation) ] + }, + rectangles: { + components: [ DebugRect, PixiRepresentation ], + listen: { + changed: [ DebugRect ] + } + }, + } + queries: any; +} \ No newline at end of file diff --git a/Program/src/Systems/DoorSystem.ts b/Program/src/Systems/DoorSystem.ts index d148839..8f8f321 100644 --- a/Program/src/Systems/DoorSystem.ts +++ b/Program/src/Systems/DoorSystem.ts @@ -2,7 +2,7 @@ import { System, Entity } from "ecsy" import { Position } from "../Components/position"; import { Door } from "../Components/door"; import { SpriteRenderer } from "../Components/spriteRenderer"; -import { IPoint, Texture, Sprite } from "pixi.js"; +import { IPoint, Texture } from "pixi.js"; import { addOrSetComponent } from "../util"; // MovableSystem @@ -13,20 +13,17 @@ export class DoorSystem extends System { this.queries.newDoors.added.forEach((entity: Entity) => { let door = entity.getComponent(Door) - let doorPos: IPoint = door.open ? door.openPosition : door.closedPosition - addOrSetComponent(entity, Position, {value: doorPos}) - + let doorOffset: IPoint = door.open ? door.openOffset : door.closedOffset let doorTex: Texture = door.open ? door.openTex : door.closedTex - addOrSetComponent(entity, SpriteRenderer, {sprite: new Sprite(doorTex)}) + addOrSetComponent(entity, SpriteRenderer, {texture: doorTex, offset: doorOffset}) }) this.queries.changedDoors.changed.forEach((entity: Entity) => { let door = entity.getComponent(Door) - let pos = entity.getMutableComponent(Position) let renderer = entity.getMutableComponent(SpriteRenderer) - pos.value = door.open ? door.openPosition : door.closedPosition - renderer.sprite.texture = door.open ? door.openTex : door.closedTex + renderer.offset = door.open ? door.openOffset : door.closedOffset + renderer.texture = door.open ? door.openTex : door.closedTex }) } diff --git a/Program/src/Systems/MovableSystem.ts b/Program/src/Systems/MovableSystem.ts deleted file mode 100644 index e7c07a1..0000000 --- a/Program/src/Systems/MovableSystem.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { System, Entity } from "ecsy" -import { canvasWidth, canvasHeight } from ".."; -import { Velocity } from "../Components/velocity"; -import { Position } from "../Components/position"; -import { SHAPE_HALF_SIZE } from "../constants"; - -// MovableSystem -export class MovableSystem extends System { - // This method will get called on every frame by default - execute(delta : number) { - // Iterate through all the entities on the query - this.queries.moving.results.forEach((entity: Entity) => { - var velocity = entity.getComponent(Velocity); - var position = entity.getMutableComponent(Position); - //if this system breaks, this is the error: scale might change the base component - position.value.add(velocity.value.scaled(delta)) - - if (position.value.x > canvasWidth + SHAPE_HALF_SIZE) position.value.x = - SHAPE_HALF_SIZE; - if (position.value.x < - SHAPE_HALF_SIZE) position.value.x = canvasWidth + SHAPE_HALF_SIZE; - if (position.value.y > canvasHeight + SHAPE_HALF_SIZE) position.value.y = - SHAPE_HALF_SIZE; - if (position.value.y < - SHAPE_HALF_SIZE) position.value.y = canvasHeight + SHAPE_HALF_SIZE; - }); - } - - static queries = { - moving: { - components: [Velocity, Position] - } - } - queries: any; -} \ No newline at end of file diff --git a/Program/src/Systems/PathWalkerSystem.ts b/Program/src/Systems/PathWalkerSystem.ts new file mode 100644 index 0000000..94dcf92 --- /dev/null +++ b/Program/src/Systems/PathWalkerSystem.ts @@ -0,0 +1,29 @@ +import { System, Entity } from "ecsy" +import { PathWalker } from "../Components/pathWalker" +import { addOrSetComponent } from "../util"; +import { Position } from "../Components/position"; + +// MovableSystem +export class PathWalkerSystem extends System { + // This method will get called on every frame by default + execute(delta : number) { + // Iterate through all the entities on the query + this.queries.walkers.results.forEach((entity: Entity) => { + let walker = entity.getMutableComponent(PathWalker) + walker.progress += walker.speed * delta + let position = walker.path.calculateAbsolutePoint(walker.progress) + addOrSetComponent(entity, Position, {value: position}) + + let pathLength = walker.path.calculateLength() + if(walker.progress > pathLength) + entity.removeComponent(PathWalker) + }); + } + + static queries = { + walkers: { + components: [ PathWalker ] + } + } + queries: any +} \ No newline at end of file diff --git a/Program/src/Systems/PixiCleanupSystem.ts b/Program/src/Systems/PixiCleanupSystem.ts new file mode 100644 index 0000000..6420a37 --- /dev/null +++ b/Program/src/Systems/PixiCleanupSystem.ts @@ -0,0 +1,28 @@ +import { PixiRepresentation } from "../Components/pixiRepresentation"; +import { Not, Entity, System } from "ecsy"; +import { DebugRect } from "../Components/debugRect"; +import { SpriteRenderer } from "../Components/spriteRenderer"; +import { app } from ".."; + + +export class PixiCleanupSystem extends System { + + priority: 99 + + // This method will get called on every frame by default + execute(delta : number) { + this.queries.oldRepresentations.results.forEach((entity:Entity) => { + app.stage.removeChild(entity.getComponent(PixiRepresentation).value) + entity.removeComponent(PixiRepresentation) + entity.remove() + }); + } + + static queries = { + oldRepresentations: { + // add all draw components here as not thingy otherwise your representation will be killed + components: [ PixiRepresentation, Not(DebugRect), Not(SpriteRenderer) ] + }, + } + queries: any; +} \ No newline at end of file diff --git a/Program/src/Systems/ShapeRenderSystem.ts b/Program/src/Systems/ShapeRenderSystem.ts deleted file mode 100644 index 5184f47..0000000 --- a/Program/src/Systems/ShapeRenderSystem.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { System, Entity } from "ecsy"; -import { app } from ".."; -import { Position } from "../Components/position"; -import { Shape } from "../Components/shape"; - -// RendererSystem -export class ShapeRenderSystem extends System { - static queries = { - renderables: { - components: [Position, Shape], - } - }; - - queries: any; - - // This method will get called on every frame by default - execute(delta : number) { - - // Iterate through all the entities on the query - this.queries.renderables.results.forEach((entity: Entity) => { - var shape = entity.getComponent(Shape); - var position = entity.getComponent(Position); - this.drawShape(position, shape); - }); - } - - drawShape(position : Position, shape : Shape) { - if(!shape.onStage){ - app.stage.addChild(shape.shape); - shape.onStage = true; - } - - shape.shape.x = position.value.x; - shape.shape.y = position.value.y; - } -} \ No newline at end of file diff --git a/Program/src/Systems/SpriteSystem.ts b/Program/src/Systems/SpriteSystem.ts index 5367158..fd27b7d 100644 --- a/Program/src/Systems/SpriteSystem.ts +++ b/Program/src/Systems/SpriteSystem.ts @@ -2,6 +2,9 @@ import { System, Entity } from "ecsy" import { Position } from "../Components/position"; import { SpriteRenderer } from "../Components/spriteRenderer"; import { app } from ".."; +import { Sprite, DisplayObject } from "pixi.js"; +import { PixiRepresentation } from "../Components/pixiRepresentation"; +import { addOrSetComponent } from "../util"; // MovableSystem export class SpriteSystem extends System { @@ -11,21 +14,23 @@ export class SpriteSystem extends System { execute(delta : number) { // Iterate through all the entities on the query this.queries.sprites.added.forEach((entity: Entity) => { - let renderer = entity.getMutableComponent(SpriteRenderer) - let pos = entity.getComponent(Position) - renderer.sprite.position = pos.value - app.stage.addChild(renderer.sprite) - }) + if(!(entity as any).alive) + return - this.queries.sprites.removed.forEach((entity: Entity) => { - let renderer = entity.getRemovedComponent(SpriteRenderer) - app.stage.removeChild(renderer.sprite) + let renderer = entity.getComponent(SpriteRenderer) + let pos = entity.getComponent(Position) + let sprite = new Sprite(renderer.texture) + sprite.position = pos.value.add(renderer.offset) + app.stage.addChild(sprite) + addOrSetComponent(entity, PixiRepresentation, {value: sprite}) }) this.queries.sprites.changed.forEach((entity: Entity) => { - let renderer = entity.getMutableComponent(SpriteRenderer) + let renderer = entity.getComponent(SpriteRenderer) let pos = entity.getComponent(Position) - renderer.sprite.position = pos.value; + let object = entity.getComponent(PixiRepresentation).value as Sprite + object.texture = renderer.texture + object.position = pos.value.add(renderer.offset) }) } @@ -34,8 +39,7 @@ export class SpriteSystem extends System { components: [ SpriteRenderer, Position ], listen: { added: true, - removed: true, - changed: [ Position ] + changed: true } }, } diff --git a/Program/src/Systems/TestSystem.ts b/Program/src/Systems/TestSystem.ts index 86d4506..a185ab3 100644 --- a/Program/src/Systems/TestSystem.ts +++ b/Program/src/Systems/TestSystem.ts @@ -1,20 +1,41 @@ import { System, Entity } from "ecsy" -import { Door } from "../Components/door"; +import { world } from ".."; +import { Human } from "../Components/human"; +import { Name } from "../Components/name"; +import { Appearance } from "../Components/appearance"; +import { Loader } from "pixi.js"; +import { InCabin } from "../Components/inCabin"; +import { Position } from "../Components/position"; +import { OrderZ } from "../Components/orderZ"; +import { AABB } from "../Datatypes/aabb"; // MovableSystem export class TestSystem extends System { priority = -100 // This method will get called on every frame by default execute(delta : number) { - // Iterate through all the entities on the query - this.queries.doors.results.forEach((entity: Entity) => { - //entity.getMutableComponent(Door).open = Math.random() > 0.5 //violently vibrate door - }) + + for(let i=0;i<1;i++){ + let ent: Entity = this.queries.humans.results[i] + ent.remove() + } + + let roomBounds = new AABB(10, 17, 62, 56) + let resources = Loader.shared.resources; + for(let i=0;i<1;i++){ + world.createEntity() + .addComponent(Human) + .addComponent(Name, {first: "Sarah", last:"Lee"}) + .addComponent(Appearance, {idleTexture: resources["Human"].texture}) //Todo: generate appearance from body traits instead? + .addComponent(InCabin) + .addComponent(Position, {value: roomBounds.randomPoint()}) + .addComponent(OrderZ) + } } static queries = { - doors: { - components: [ Door ] + humans: { + components: [ Human ] }, } queries: any; diff --git a/Program/src/Systems/VisibleHumanSystem.ts b/Program/src/Systems/VisibleHumanSystem.ts new file mode 100644 index 0000000..32f3b80 --- /dev/null +++ b/Program/src/Systems/VisibleHumanSystem.ts @@ -0,0 +1,39 @@ +import { System, Entity, Not } from "ecsy" +import { Human } from "../Components/human" +import { Appearance } from "../Components/appearance" +import { InCabin } from "../Components/inCabin" +import { Position } from "../Components/position" +import { SpriteRenderer } from "../Components/spriteRenderer" +import { Vector } from "../Datatypes/vector" + +// MovableSystem +export class VisibleHumanSystem extends System { + priority = 50 + + + execute(delta : number) { + // add sprite at start + this.queries.newHumans.results.forEach((entity: Entity) => { + let texture = entity.getComponent(Appearance).idleTexture + entity.addComponent(SpriteRenderer, {texture: texture, offset: new Vector(-texture.width/2, -texture.height)}) + }) + //update sprite texture + this.queries.visibleHumans.changed.forEach((entity: Entity) => { + let texture = entity.getComponent(Appearance).idleTexture + entity.getMutableComponent(SpriteRenderer).texture = texture + }) + } + + static queries = { + newHumans: { + components: [ Human, Appearance, InCabin, Position, Not(SpriteRenderer) ] + }, + visibleHumans: { + components: [ Human, Appearance, InCabin, Position, SpriteRenderer ], + listen: { + changed: [ Appearance ] + } + }, + } + queries: any +} \ No newline at end of file diff --git a/Program/src/Systems/ZOrderSystem.ts b/Program/src/Systems/ZOrderSystem.ts new file mode 100644 index 0000000..0dfb095 --- /dev/null +++ b/Program/src/Systems/ZOrderSystem.ts @@ -0,0 +1,38 @@ +import { PixiRepresentation } from "../Components/pixiRepresentation"; +import { Entity, System } from "ecsy"; +import { Position } from "../Components/position"; +import { OrderZ } from "../Components/orderZ"; + + +export class ZOrderSystem extends System { + priority: 98 + + // This method will get called on every frame by default + execute() { + this.queries.objects.added.forEach((entity:Entity) => { + let representation = entity.getComponent(PixiRepresentation).value + let order = entity.getComponent(OrderZ) + let pos = entity.getComponent(Position).value + representation.zIndex = pos.y + order.offset + }); + + this.queries.objects.changed.forEach((entity:Entity) => { + let representation = entity.getComponent(PixiRepresentation).value + let order = entity.getComponent(OrderZ) + let pos = entity.getComponent(Position).value + representation.zIndex = pos.y + order.offset + }); + } + + static queries = { + objects: { + // add all draw components here as not thingy otherwise your representation will be killed + components: [ Position, OrderZ , PixiRepresentation ], + listen: { + added: true, + changed: [ Position, OrderZ ], + } + }, + } + queries: any; +} \ No newline at end of file diff --git a/Program/src/index.ts b/Program/src/index.ts index 2d8e57b..d05f722 100644 --- a/Program/src/index.ts +++ b/Program/src/index.ts @@ -1,19 +1,26 @@ +import { Application, Ticker, settings, SCALE_MODES } from "pixi.js" +import { World } from "ecsy" + +import { setup } from "./setup" import { loadResources } from "./Resources" -import { Door } from "./Components/door" + import { DoorSystem } from "./Systems/DoorSystem" import { SpriteSystem } from "./Systems/SpriteSystem" -import { Application, Ticker, settings, SCALE_MODES, Sprite, Loader } from "pixi.js" -import { World } from "ecsy" import { RenderSystem } from "./Systems/RenderSystem" import { TestSystem } from "./Systems/TestSystem" +import { AdventureReturnSystem } from "./Systems/AdventureReturnSystem" +import { VisibleHumanSystem } from "./Systems/VisibleHumanSystem" +import { DebugRenderSystem } from "./Systems/DebugRenderSystem" +import { PixiCleanupSystem } from "./Systems/PixiCleanupSystem" +import { ZOrderSystem } from "./Systems/ZOrderSystem" // Initialize pixi export let canvasWidth = 81 -export let canvasHeight = 81 +export let canvasHeight = 144 export const app = new Application({ width: canvasWidth, height: canvasHeight, - backgroundColor: 0xFFFFFF, + backgroundColor: 0x000000, resolution: 1, antialias: false, }) @@ -33,28 +40,24 @@ function recalculateSize(){ } // Create world and register the systems on it -export let world = new World(); +//we could also register components here but they should get automatically registered once used for the first time +export let world = new World() world - .registerSystem(TestSystem) //prio -100 - .registerSystem(DoorSystem) //prio 0 - .registerSystem(SpriteSystem) //prio 90 - .registerSystem(RenderSystem) //prio 100 + .registerSystem(TestSystem) //prio -100 + .registerSystem(AdventureReturnSystem) //prio -100 + .registerSystem(DoorSystem) //prio 0 + .registerSystem(VisibleHumanSystem) //prio 50 + .registerSystem(SpriteSystem) //prio 90 + .registerSystem(DebugRenderSystem) //prio 90 + .registerSystem(ZOrderSystem) //prio 98 + .registerSystem(PixiCleanupSystem) //prio 99 + .registerSystem(RenderSystem) //prio 100 loadResources(init) function init(){ - let resources = Loader.shared.resources; - - //base sprites without entity representation - const bgTex = new Sprite(resources["Background"].texture) - app.stage.addChild(bgTex) - - //start entities - world.createEntity() - .addComponent(Door, {open: false, - openPosition: {x:38, y:2}, openTex: resources["Door"].spritesheet.textures[0], - closedPosition: {x:38, y:2}, closedTex: resources["Door"].spritesheet.textures[1]}) + setup() // Run! Ticker.shared.add((delta : number) => { diff --git a/Program/src/random.ts b/Program/src/random.ts deleted file mode 100644 index 193be8a..0000000 --- a/Program/src/random.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { Velocity } from "./Components/velocity" -import { Position } from "./Components/position" - -import { Vector } from "./Datatypes/vector" - -import { canvasWidth, canvasHeight } from "." -import { Point } from "./Datatypes/point" -import { SHAPE_HALF_SIZE, SHAPE_SIZE } from "./constants" - -// Some helper functions when creating the components -function getRandomVelocity(speedMultiplier: number): Velocity { - return { - value: new Vector( - speedMultiplier * (2 * Math.random() - 1), - speedMultiplier * (2 * Math.random() - 1) - ) - } -} - -function getRandomPosition(): Position{ - return { - value: new Point( - Math.random() * canvasWidth, - Math.random() * canvasHeight - ) - } -} - - -function getRandomShape() { - let graphics = new PIXI.Graphics() - if(Math.random() >= 0.5) { - graphics.beginFill(0x888888) - graphics.lineStyle(1, 0x222222) - graphics.drawCircle(0, 0, SHAPE_HALF_SIZE) - } else { - graphics.beginFill(0xf28d89) - graphics.lineStyle(1, 0x800904) - graphics.drawRect(-SHAPE_HALF_SIZE, -SHAPE_HALF_SIZE, SHAPE_SIZE, SHAPE_SIZE) - } - - return { - shape: graphics - } -} \ No newline at end of file diff --git a/Program/src/setup.ts b/Program/src/setup.ts new file mode 100644 index 0000000..b0e3ad0 --- /dev/null +++ b/Program/src/setup.ts @@ -0,0 +1,43 @@ +import { Loader, Sprite } from "pixi.js"; +import { app, world } from "."; +import { Door } from "./Components/door"; +import { Human } from "./Components/human"; +import { Name } from "./Components/name"; +import { InCabin } from "./Components/inCabin"; +import { Appearance } from "./Components/appearance"; +import { Position } from "./Components/position"; +import { AABB } from "./Datatypes/aabb"; +import { DebugRect } from "./Components/debugRect"; +import { OrderZ } from "./Components/orderZ"; + + +export function setup(){ + let resources = Loader.shared.resources; + + //base sprites without entity representation + const bgTex = new Sprite(resources["Background"].texture) + app.stage.addChild(bgTex) + + //start entities + + //door + world.createEntity() + .addComponent(Door, {open: true, + openOffset: {x:38, y:2}, openTex: resources["Door"].spritesheet.textures[0], + closedOffset: {x:38, y:2}, closedTex: resources["Door"].spritesheet.textures[1]}) + + //example humans + //TODO delete those + let roomBounds = new AABB(10, 17, 62, 56) + world.createEntity() + .addComponent(DebugRect, {color:0x0000FF, rect: roomBounds}) + + for(let i=0;i<10;i++) + world.createEntity() + .addComponent(Human) + .addComponent(Name, {first: "Sarah", last:"Lee"}) + .addComponent(Appearance, {idleTexture: resources["Human"].texture}) //Todo: generate appearance from body traits instead? + .addComponent(InCabin) + .addComponent(Position, {value: roomBounds.randomPoint()}) + .addComponent(OrderZ) +} \ No newline at end of file diff --git a/Program/src/util.ts b/Program/src/util.ts index 32f5e43..f3a53f8 100644 --- a/Program/src/util.ts +++ b/Program/src/util.ts @@ -1,7 +1,7 @@ -import { Entity, ComponentConstructor, Component } from "ecsy"; +import { Entity, ComponentConstructor, Component } from "ecsy" -export function addOrSetComponent(entity: Entity, Component: ComponentConstructor, values: object) { +export function addOrSetComponent(entity: Entity, Component: ComponentConstructor, values: any) { if(entity.hasComponent(Component)){ //component exists, copy values into it let component: any = entity.getMutableComponent(Component) @@ -9,11 +9,19 @@ export function addOrSetComponent(entity: Entity, Component: ComponentConstructo component.copy(values) } else { for (var name in values) { - component[name] = values[name]; + component[name]= values[name] } } } else { //component doesn't exist, add new one entity.addComponent(Component, values) } -} \ No newline at end of file +} + +export function clamp(value: number, min:number, max:number) { + return Math.min(Math.max(value, min), max) +}; + +export function lerp(from: number, to:number, at:number) { + return from + (to - from) * at; +}; \ No newline at end of file diff --git a/Program/tsconfig.json b/Program/tsconfig.json index 4e510b3..a79a300 100644 --- a/Program/tsconfig.json +++ b/Program/tsconfig.json @@ -2,6 +2,15 @@ "compilerOptions": { "sourceMap": true, "target": "es6", - "moduleResolution": "Node" + "moduleResolution": "Node", + + //have harsh code standards + "pretty": true, + "noImplicitAny": true, + "noImplicitThis": true, + "noUnusedLocals": true, + "noImplicitReturns": true, + "allowUnreachableCode": false, + "noImplicitUseStrict": true } } \ No newline at end of file