diff --git a/Engine/src/live/Action.ts b/Engine/src/live/Action.ts new file mode 100644 index 0000000..6aa447d --- /dev/null +++ b/Engine/src/live/Action.ts @@ -0,0 +1,4 @@ +export interface Action { + type: string + priority: number +} diff --git a/Engine/src/live/Entity.ts b/Engine/src/live/Entity.ts new file mode 100644 index 0000000..971e828 --- /dev/null +++ b/Engine/src/live/Entity.ts @@ -0,0 +1,68 @@ +import * as planck from 'planck' +import { SpriteInstance } from '../shared/sprites' + +export class Entity { + sprite: SpriteInstance + body?: planck.Body + velocity: [number, number] = [0, 0] + acceleration: number = 0.5 + maxSpeed: number = 4 + direction: number = 0 + turnRate: number = 10 + + constructor(ctor: string) { + this.sprite = new SpriteInstance(ctor) + } + + update(delta: number) { + // TODO: Update sprite. + } + + get position(): [number, number] { + if (this.body) { + let p = this.body.getPosition() + return [p.x, p.y] + } + return [this.sprite.container.x, this.sprite.container.y] + } + get x(): number { + if (this.body) { + let p = this.body.getPosition() + return p.x + } + return this.sprite.container.x + } + set x(v: number) { + if (this.body) { + let p = this.body.getPosition() + this.body.setPosition( + planck.Vec2( + v, + p.y, + ) + ) + } else { + this.sprite.container.y = v + } + } + get y(): number { + if (this.body) { + let p = this.body.getPosition() + return p.y + } + return this.sprite.container.y + } + set y(v: number) { + if (this.body) { + let p = this.body.getPosition() + this.body.setPosition( + planck.Vec2( + p.x, + v, + ) + ) + } else { + this.sprite.container.y = v + } + } +} diff --git a/Engine/src/live/PlayerEntity.ts b/Engine/src/live/PlayerEntity.ts new file mode 100644 index 0000000..2ec82a8 --- /dev/null +++ b/Engine/src/live/PlayerEntity.ts @@ -0,0 +1,119 @@ +import * as planck from 'planck' +import { Action } from "./Action" +import { Entity } from "./Entity" + +export class PlayerEntity extends Entity { + action?: Action + constructor(ctor: string) { + super(ctor) + } + act(actions: Action[]) { + this.action = actions.sort((a, b) => { + if (a.priority < b.priority) { + return -1 + } + if (a.priority > b.priority) { + return 1 + } + return 0 + })[0] + } + update(delta: number) { + if (this.action) { + // FIXME: Use physics. + let shouldMove = false + switch(this.action.type) { + case 'west': + if (this.direction !== 0) { + if (this.direction < 180) { + this.direction -= this.turnRate + } else { + this.direction += this.turnRate + } + } + shouldMove = true + break + case 'east': + if (this.direction !== 180) { + if (this.direction < 180) { + this.direction += this.turnRate + } else { + this.direction -= this.turnRate + } + } + shouldMove = true + break + case 'north': + if (this.direction !== 90) { + if (this.direction < 90 || this.direction > 270) { + this.direction += this.turnRate + } else { + this.direction -= this.turnRate + } + } + shouldMove = true + break + case 'south': + if (this.direction !== 270) { + if (this.direction > 90 && this.direction < 270) { + this.direction += this.turnRate + } else { + this.direction -= this.turnRate + } + } + shouldMove = true + break + } + if (this.direction > 360) { + this.direction = 0 + } else if (this.direction < 0) { + this.direction = 360 + } + if (shouldMove) { + let r = this.direction * (Math.PI/180) + if (Math.abs(this.velocity[0]) < this.maxSpeed) { + this.velocity[0] -= Math.cos(r) * this.acceleration + } + if (Math.abs(this.velocity[1]) < this.maxSpeed) { + this.velocity[1] -= Math.sin(r) * this.acceleration + } + let cardinal = this.getCardinal() + if (this.sprite.subsetKey !== cardinal) { + this.sprite.setCtor(`${this.sprite.spriteKey}.${this.sprite.animationKey}.${this.sprite.setKey}.${cardinal}.${this.sprite.frameIndex}`) + } + } + } + + // + this.velocity[0] *= 0.5 + this.velocity[1] *= 0.5 + + // Eh... let's manually handle velocity + this.body?.setLinearVelocity(planck.Vec2(this.velocity[0], this.velocity[1])) + } + getCardinal(): string { + const degreesPerDirection = 360 / 8 + const angle = this.direction + degreesPerDirection / 2 + + if (angle >= 0 * degreesPerDirection && angle < 1 * degreesPerDirection) { + return 'w' + } else if (angle >= 1 * degreesPerDirection && angle < 2 * degreesPerDirection) { + return 'nw' + } else if (angle >= 2 * degreesPerDirection && angle < 3 * degreesPerDirection) { + return 'n' + } else if (angle >= 3 * degreesPerDirection && angle < 4 * degreesPerDirection) { + return 'ne' + } else if (angle >= 4 * degreesPerDirection && angle < 5 * degreesPerDirection) { + return 'e' + } else if (angle >= 5 * degreesPerDirection && angle < 6 * degreesPerDirection) { + return 'se' + } else if (angle >= 6 * degreesPerDirection && angle < 7 * degreesPerDirection) { + return 's' + } + return 'sw' + } +} + +export function isPlayerEntity(o: any): o is PlayerEntity { + return o.act +} diff --git a/Engine/src/live/Zone.ts b/Engine/src/live/Zone.ts new file mode 100644 index 0000000..2da4a7b --- /dev/null +++ b/Engine/src/live/Zone.ts @@ -0,0 +1,13 @@ +import * as planck from 'planck' +import { SegmentZone } from '../data/segment' + +export class Zone { + fixture: planck.Fixture|undefined + type: 'solid'|'fluid' + points: [number, number][] + constructor(z: SegmentZone) { + this.type = z.type + this.points = z.points.map(v=>[v[0], v[1]]) + } +} + diff --git a/Engine/src/states/Game.ts b/Engine/src/states/Game.ts index 780c388..a9e6397 100644 --- a/Engine/src/states/Game.ts +++ b/Engine/src/states/Game.ts @@ -7,201 +7,15 @@ import { DecorationInstance } from "../shared/decors" import { SpriteInstance, sprites } from "../shared/sprites" import { ShapeCircle, ShapePoints } from "../data/sprite" import { SegmentZone } from "../data/segment" +import { Zone } from "../live/Zone" +import { Entity } from "../live/Entity" +import { isPlayerEntity, PlayerEntity } from "../live/PlayerEntity" +import { Action } from "../live/Action" -interface Action { - type: string - priority: number -} - -class Zone { - fixture: planck.Fixture|undefined - type: 'solid'|'fluid' - points: [number, number][] - constructor(z: SegmentZone) { - this.type = z.type - this.points = z.points.map(v=>[v[0], v[1]]) - } -} - -class Entity { - sprite: SpriteInstance - body?: planck.Body - velocity: [number, number] = [0, 0] - acceleration: number = 0.5 - maxSpeed: number = 4 - direction: number = 0 - turnRate: number = 10 - - constructor(ctor: string) { - this.sprite = new SpriteInstance(ctor) - } - - update(delta: number) { - // TODO: Update sprite. - } - - get position(): [number, number] { - if (this.body) { - let p = this.body.getPosition() - return [p.x, p.y] - } - return [this.sprite.container.x, this.sprite.container.y] - } - get x(): number { - if (this.body) { - let p = this.body.getPosition() - return p.x - } - return this.sprite.container.x - } - set x(v: number) { - if (this.body) { - let p = this.body.getPosition() - this.body.setPosition( - planck.Vec2( - v, - p.y, - ) - ) - } else { - this.sprite.container.y = v - } - } - get y(): number { - if (this.body) { - let p = this.body.getPosition() - return p.y - } - return this.sprite.container.y - } - set y(v: number) { - if (this.body) { - let p = this.body.getPosition() - this.body.setPosition( - planck.Vec2( - p.x, - v, - ) - ) - } else { - this.sprite.container.y = v - } - } -} - -class PlayerEntity extends Entity { - action?: Action - constructor(ctor: string) { - super(ctor) - } - act(actions: Action[]) { - this.action = actions.sort((a, b) => { - if (a.priority < b.priority) { - return -1 - } - if (a.priority > b.priority) { - return 1 - } - return 0 - })[0] - } - update(delta: number) { - if (this.action) { - // FIXME: Use physics. - let shouldMove = false - switch(this.action.type) { - case 'west': - if (this.direction !== 0) { - if (this.direction < 180) { - this.direction -= this.turnRate - } else { - this.direction += this.turnRate - } - } - shouldMove = true - break - case 'east': - if (this.direction !== 180) { - if (this.direction < 180) { - this.direction += this.turnRate - } else { - this.direction -= this.turnRate - } - } - shouldMove = true - break - case 'north': - if (this.direction !== 90) { - if (this.direction < 90 || this.direction > 270) { - this.direction += this.turnRate - } else { - this.direction -= this.turnRate - } - } - shouldMove = true - break - case 'south': - if (this.direction !== 270) { - if (this.direction > 90 && this.direction < 270) { - this.direction += this.turnRate - } else { - this.direction -= this.turnRate - } - } - shouldMove = true - break - } - if (this.direction > 360) { - this.direction = 0 - } else if (this.direction < 0) { - this.direction = 360 - } - if (shouldMove) { - let r = this.direction * (Math.PI/180) - if (Math.abs(this.velocity[0]) < this.maxSpeed) { - this.velocity[0] -= Math.cos(r) * this.acceleration - } - if (Math.abs(this.velocity[1]) < this.maxSpeed) { - this.velocity[1] -= Math.sin(r) * this.acceleration - } - let cardinal = this.getCardinal() - if (this.sprite.subsetKey !== cardinal) { - this.sprite.setCtor(`${this.sprite.spriteKey}.${this.sprite.animationKey}.${this.sprite.setKey}.${cardinal}.${this.sprite.frameIndex}`) - } - } - } - - // - this.velocity[0] *= 0.5 - this.velocity[1] *= 0.5 - - // Eh... let's manually handle velocity - this.body?.setLinearVelocity(planck.Vec2(this.velocity[0], this.velocity[1])) - } - getCardinal(): string { - const degreesPerDirection = 360 / 8 - const angle = this.direction + degreesPerDirection / 2 - - if (angle >= 0 * degreesPerDirection && angle < 1 * degreesPerDirection) { - return 'w' - } else if (angle >= 1 * degreesPerDirection && angle < 2 * degreesPerDirection) { - return 'nw' - } else if (angle >= 2 * degreesPerDirection && angle < 3 * degreesPerDirection) { - return 'n' - } else if (angle >= 3 * degreesPerDirection && angle < 4 * degreesPerDirection) { - return 'ne' - } else if (angle >= 4 * degreesPerDirection && angle < 5 * degreesPerDirection) { - return 'e' - } else if (angle >= 5 * degreesPerDirection && angle < 6 * degreesPerDirection) { - return 'se' - } else if (angle >= 6 * degreesPerDirection && angle < 7 * degreesPerDirection) { - return 's' - } - return 'sw' - } -} -function isPlayerEntity(o: any): o is PlayerEntity { - return o.act +export interface Layer { + title: string + container: PIXI.Container + decorations: DecorationInstance[] } export function GameState(ctx: ContextI): StateI { @@ -213,7 +27,8 @@ export function GameState(ctx: ContextI): StateI { }) let rootContainer = new PIXI.Container() - let decorations: DecorationInstance[] = [] + let playLayer: Layer + let layers: Layer[] = [] let entities: Entity[] = [] let zones: Zone[] = [] @@ -226,9 +41,19 @@ export function GameState(ctx: ContextI): StateI { rootContainer.height = w.height rootContainer.scale.set(2, 2) for (let l of w.layers) { - let container = new PIXI.Container() - container.width = w.width - container.height = w.height + let layer: Layer = { + title: l.title, + container: new PIXI.Container(), + decorations: [], + } + layer.container.width = w.width + layer.container.height = w.height + + if (l.title === 'objects') { + playLayer = layer + layer.container.sortableChildren = true + } + layers.push(layer) for (let d of l.decorations) { let di = new DecorationInstance(d.decor, d.decoration) @@ -255,11 +80,14 @@ export function GameState(ctx: ContextI): StateI { di.container.position.y-- } } - container.addChild(di.container) - decorations.push(di) + if (l.title === 'objects') { + di.container.zIndex = di.container.position.y + di.container.height/4 + } + layer.container.addChild(di.container) + layer.decorations.push(di) } - rootContainer.addChild(container) + rootContainer.addChild(layer.container) } for (let z of w.zones) { @@ -267,7 +95,6 @@ export function GameState(ctx: ContextI): StateI { } // Add bogus entity - //addEntity(new PlayerEntity('animals.deer.animal.west.0'), 0, 0) addEntity(new PlayerEntity('bogus-arrows.player.normal.w.0'), 0, 0) ctx.app.stage.addChild(rootContainer) @@ -288,8 +115,10 @@ export function GameState(ctx: ContextI): StateI { elapsed -= 1/60 } // Update/render. - for (let decoration of decorations) { - decoration.update(delta) + for (let layer of layers) { + for (let decoration of layer.decorations) { + decoration.update(delta) + } } for (let entity of entities) { if (isPlayerEntity(entity)) { @@ -302,13 +131,14 @@ export function GameState(ctx: ContextI): StateI { // I guess... entity.sprite.container.x = entity.x entity.sprite.container.y = entity.y + entity.sprite.container.zIndex = entity.y + (entity.sprite.frame?entity.sprite.frame.originY:0) } } let addEntity = (entity: Entity, x: number, y: number) => { if (entities.find(v=>v===entity)) return entities.push(entity) - rootContainer.addChild(entity.sprite.container) + playLayer.container.addChild(entity.sprite.container) // I guess this is a fair enough place to create physics and add it to the entity. let spriteShape = entity.sprite.getBodyShape() if (spriteShape) { @@ -338,7 +168,7 @@ export function GameState(ctx: ContextI): StateI { } let removeEntity = (entity: Entity) => { entities = entities.filter(v=>v!==entity) - rootContainer.removeChild(entity.sprite.container) + playLayer.container.removeChild(entity.sprite.container) if (entity.body) { world.destroyBody(entity.body) entity.body = undefined