just lots and lots of structural code

This commit is contained in:
Ronja 2020-02-17 12:56:41 +01:00
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

View 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()
}
}

View 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
}
}

View 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)
}
}

View file

@ -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

View file

@ -0,0 +1,9 @@
import { Component } from "ecsy"
// Door component
export class Human extends Component {
reset() {
}
}

View file

@ -0,0 +1,4 @@
import { TagComponent } from "ecsy";
export class InCabin extends TagComponent {}

View 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"
}
}

View file

@ -0,0 +1,10 @@
import { Component } from "ecsy"
export class OrderZ extends Component{
offset = 0
reset(){
this.offset = 0
}
}

View 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
}
}

View 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
}
}

View file

@ -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)
}

View file

@ -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
}
}

View file

@ -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)
}
}

View file

@ -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)
}
}

View file

@ -0,0 +1,6 @@
import { Component } from "ecsy";
export class WalkArea extends Component{
}

View 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()))
}
}

View 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]
}
}

View file

@ -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 {

View 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
}

View file

@ -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

View 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
}

View 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;
}

View file

@ -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
})
}

View file

@ -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;
}

View 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
}

View 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;
}

View file

@ -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;
}
}

View file

@ -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
}
},
}

View file

@ -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;

View 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
}

View 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;
}

View file

@ -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) => {

View file

@ -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
View 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)
}

View file

@ -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;
};

View file

@ -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
}
}