just lots and lots of structural code
This commit is contained in:
parent
5d979b3e5c
commit
af9c71e564
40 changed files with 621 additions and 207 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 285 B After Width: | Height: | Size: 278 B |
19
Program/src/Components/adventure.ts
Normal file
19
Program/src/Components/adventure.ts
Normal file
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
13
Program/src/Components/appearance.ts
Normal file
13
Program/src/Components/appearance.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import { Component } from "ecsy";
|
||||
import { Texture } from "pixi.js";
|
||||
|
||||
|
||||
export class Appearance extends Component{
|
||||
|
||||
|
||||
idleTexture: Texture
|
||||
|
||||
reset(){
|
||||
this.idleTexture = null
|
||||
}
|
||||
}
|
||||
13
Program/src/Components/debugRect.ts
Normal file
13
Program/src/Components/debugRect.ts
Normal file
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
9
Program/src/Components/human.ts
Normal file
9
Program/src/Components/human.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import { Component } from "ecsy"
|
||||
|
||||
// Door component
|
||||
export class Human extends Component {
|
||||
|
||||
|
||||
reset() {
|
||||
}
|
||||
}
|
||||
4
Program/src/Components/inCabin.ts
Normal file
4
Program/src/Components/inCabin.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
import { TagComponent } from "ecsy";
|
||||
|
||||
|
||||
export class InCabin extends TagComponent {}
|
||||
22
Program/src/Components/name.ts
Normal file
22
Program/src/Components/name.ts
Normal file
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
10
Program/src/Components/orderZ.ts
Normal file
10
Program/src/Components/orderZ.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import { Component } from "ecsy"
|
||||
|
||||
|
||||
export class OrderZ extends Component{
|
||||
offset = 0
|
||||
|
||||
reset(){
|
||||
this.offset = 0
|
||||
}
|
||||
}
|
||||
15
Program/src/Components/pathWalker.ts
Normal file
15
Program/src/Components/pathWalker.ts
Normal file
|
|
@ -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
|
||||
}
|
||||
}
|
||||
10
Program/src/Components/pixiRepresentation.ts
Normal file
10
Program/src/Components/pixiRepresentation.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import { SystemStateComponent } from "ecsy";
|
||||
import { DisplayObject } from "pixi.js";
|
||||
|
||||
export class PixiRepresentation extends SystemStateComponent {
|
||||
value: DisplayObject
|
||||
|
||||
reset(){
|
||||
this.value = null
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
6
Program/src/Components/walkArea.ts
Normal file
6
Program/src/Components/walkArea.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
import { Component } from "ecsy";
|
||||
|
||||
|
||||
export class WalkArea extends Component{
|
||||
|
||||
}
|
||||
60
Program/src/Datatypes/aabb.ts
Normal file
60
Program/src/Datatypes/aabb.ts
Normal file
|
|
@ -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()))
|
||||
}
|
||||
}
|
||||
37
Program/src/Datatypes/path.ts
Normal file
37
Program/src/Datatypes/path.ts
Normal file
|
|
@ -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<this.points.length;i++){
|
||||
length += this.points[i-1].to(this.points[i]).length()
|
||||
}
|
||||
return length
|
||||
}
|
||||
|
||||
/// point on the path in normalized 0-1 space
|
||||
calculateRelativePoint(relativePathDistance: number): Point{
|
||||
relativePathDistance = clamp(relativePathDistance, 0, 1)
|
||||
let length = this.calculateLength()
|
||||
let absolutePathDistance = relativePathDistance * length
|
||||
return this.calculateAbsolutePoint(absolutePathDistance)
|
||||
}
|
||||
|
||||
calculateAbsolutePoint(absolutePathDistance: number): Point{
|
||||
for(let i=1;i<this.points.length;i++){
|
||||
let segmentVector = this.points[i-1].to(this.points[i])
|
||||
let segmentLength = segmentVector.length();
|
||||
if(absolutePathDistance <= segmentLength){
|
||||
let relativeSegmentPos = absolutePathDistance / segmentLength
|
||||
return this.points[i-1].add(segmentVector.scale(relativeSegmentPos))
|
||||
}
|
||||
absolutePathDistance -= segmentLength
|
||||
}
|
||||
return this.points[this.points.length-1]
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,13 @@
|
|||
import { IPoint } from "pixi.js"
|
||||
import { Vector } from "./vector"
|
||||
import { lerp } from "../util"
|
||||
|
||||
// my own point I can extend however I want to, compatible with pixijs points
|
||||
export class Point implements IPoint{
|
||||
static lerp(from:Point, to:Point, at:number): Point {
|
||||
return new Point(lerp(from.x, to.x, at), lerp(from.y, to.y, at))
|
||||
}
|
||||
|
||||
x: number
|
||||
y: number
|
||||
|
||||
|
|
@ -16,7 +21,15 @@ export class Point implements IPoint{
|
|||
}
|
||||
|
||||
add(vec: Vector): Point{
|
||||
return this.set(vec.x, vec.y)
|
||||
return new Point(this.x + vec.x, this.y + vec.y)
|
||||
}
|
||||
|
||||
gt(other: Point):boolean{
|
||||
return this.x > 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 {
|
||||
|
|
|
|||
7
Program/src/Datatypes/rng.ts
Normal file
7
Program/src/Datatypes/rng.ts
Normal file
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
39
Program/src/Systems/AdventureReturnSystem.ts
Normal file
39
Program/src/Systems/AdventureReturnSystem.ts
Normal file
|
|
@ -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
|
||||
}
|
||||
44
Program/src/Systems/DebugRenderSystem.ts
Normal file
44
Program/src/Systems/DebugRenderSystem.ts
Normal file
|
|
@ -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, <PixiRepresentation>{value: <DisplayObject>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;
|
||||
}
|
||||
|
|
@ -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, <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
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
29
Program/src/Systems/PathWalkerSystem.ts
Normal file
29
Program/src/Systems/PathWalkerSystem.ts
Normal file
|
|
@ -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, <Position>{value: position})
|
||||
|
||||
let pathLength = walker.path.calculateLength()
|
||||
if(walker.progress > pathLength)
|
||||
entity.removeComponent(PathWalker)
|
||||
});
|
||||
}
|
||||
|
||||
static queries = {
|
||||
walkers: {
|
||||
components: [ PathWalker ]
|
||||
}
|
||||
}
|
||||
queries: any
|
||||
}
|
||||
28
Program/src/Systems/PixiCleanupSystem.ts
Normal file
28
Program/src/Systems/PixiCleanupSystem.ts
Normal file
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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, <PixiRepresentation>{value: <DisplayObject>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
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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, <Name>{first: "Sarah", last:"Lee"})
|
||||
.addComponent(Appearance, <Appearance>{idleTexture: resources["Human"].texture}) //Todo: generate appearance from body traits instead?
|
||||
.addComponent(InCabin)
|
||||
.addComponent(Position, <Position>{value: roomBounds.randomPoint()})
|
||||
.addComponent(OrderZ)
|
||||
}
|
||||
}
|
||||
|
||||
static queries = {
|
||||
doors: {
|
||||
components: [ Door ]
|
||||
humans: {
|
||||
components: [ Human ]
|
||||
},
|
||||
}
|
||||
queries: any;
|
||||
|
|
|
|||
39
Program/src/Systems/VisibleHumanSystem.ts
Normal file
39
Program/src/Systems/VisibleHumanSystem.ts
Normal file
|
|
@ -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, <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
|
||||
}
|
||||
38
Program/src/Systems/ZOrderSystem.ts
Normal file
38
Program/src/Systems/ZOrderSystem.ts
Normal file
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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, <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) => {
|
||||
|
|
|
|||
|
|
@ -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 <Velocity> {
|
||||
value: new Vector(
|
||||
speedMultiplier * (2 * Math.random() - 1),
|
||||
speedMultiplier * (2 * Math.random() - 1)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function getRandomPosition(): Position{
|
||||
return <Position> {
|
||||
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
|
||||
}
|
||||
}
|
||||
43
Program/src/setup.ts
Normal file
43
Program/src/setup.ts
Normal file
|
|
@ -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, <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, <DebugRect>{color:0x0000FF, rect: roomBounds})
|
||||
|
||||
for(let i=0;i<10;i++)
|
||||
world.createEntity()
|
||||
.addComponent(Human)
|
||||
.addComponent(Name, <Name>{first: "Sarah", last:"Lee"})
|
||||
.addComponent(Appearance, <Appearance>{idleTexture: resources["Human"].texture}) //Todo: generate appearance from body traits instead?
|
||||
.addComponent(InCabin)
|
||||
.addComponent(Position, <Position>{value: roomBounds.randomPoint()})
|
||||
.addComponent(OrderZ)
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import { Entity, ComponentConstructor, Component } from "ecsy";
|
||||
import { Entity, ComponentConstructor, Component } from "ecsy"
|
||||
|
||||
|
||||
export function addOrSetComponent(entity: Entity, Component: ComponentConstructor<Component>, values: object) {
|
||||
export function addOrSetComponent(entity: Entity, Component: ComponentConstructor<Component>, 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
};
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue