diff --git a/Engine/src/states/Game.ts b/Engine/src/states/Game.ts index 334d840..b8b4259 100644 --- a/Engine/src/states/Game.ts +++ b/Engine/src/states/Game.ts @@ -2,8 +2,10 @@ import { ContextI } from "../ContextI" import { segments } from "../shared/segments" import { StateI } from "./StateI" import * as PIXI from 'pixi.js' +import * as planck from 'planck' import { DecorationInstance } from "../shared/decors" -import { SpriteInstance } from "../shared/sprites" +import { SpriteInstance, sprites } from "../shared/sprites" +import { ShapeCircle, ShapePoints } from "../data/sprite" interface Action { type: string @@ -12,6 +14,11 @@ interface Action { class Entity { sprite: SpriteInstance + body?: planck.Body + velocity: [number, number] = [0, 0] + acceleration: number = 0.5 + maxSpeed: number = 4 + direction: number = 0 constructor(ctor: string) { this.sprite = new SpriteInstance(ctor) @@ -21,17 +28,52 @@ class Entity { // 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) { - this.sprite.container.x = v + 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) { - this.sprite.container.y = v + if (this.body) { + let p = this.body.getPosition() + this.body.setPosition( + planck.Vec2( + p.x, + v, + ) + ) + } else { + this.sprite.container.y = v + } } } @@ -39,9 +81,6 @@ class PlayerEntity extends Entity { action?: Action constructor(ctor: string) { super(ctor) - this.x = 100 - this.y = 100 - // TODO: Hooks for key state check input, perhaps? } act(actions: Action[]) { this.action = actions.sort((a, b) => { @@ -59,19 +98,33 @@ class PlayerEntity extends Entity { // FIXME: Use physics. switch(this.action.type) { case 'west': - this.x-- + if (this.velocity[0] > -this.maxSpeed) { + this.velocity[0] -= this.acceleration + } break case 'east': - this.x++ + if (this.velocity[0] < this.maxSpeed) { + this.velocity[0] += this.acceleration + } break case 'north': - this.y-- + if (this.velocity[1] > -this.maxSpeed) { + this.velocity[1] -= this.acceleration + } break case 'south': - this.y++ + if (this.velocity[1] < this.maxSpeed) { + this.velocity[1] += this.acceleration + } break } } + // + 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])) } } function isPlayerEntity(o: any): o is PlayerEntity { @@ -79,6 +132,9 @@ function isPlayerEntity(o: any): o is PlayerEntity { } export function GameState(ctx: ContextI): StateI { + let world: planck.World = planck.World({ + gravity: planck.Vec2(0, 0), + }) let rootContainer = new PIXI.Container() let decorations: DecorationInstance[] = [] @@ -102,17 +158,26 @@ export function GameState(ctx: ContextI): StateI { di.elapsed = d.timeOffset di.container.x = d.x di.container.y = d.y + if (d.rotation !== 0) { + di.container.angle = d.rotation + } if (d.flip) { di.container.pivot.y = 1 di.container.scale.y *= -1 - di.container.position.y-- + if (d.rotation === 0) { + di.container.position.y-- + } } if (d.mirror) { di.container.pivot.x = 1 di.container.scale.x *= -1 di.container.position.x-- + if (d.rotation !== 0) { + di.container.angle = -d.rotation + di.container.position.x++ + di.container.position.y-- + } } - container.addChild(di.container) decorations.push(di) } @@ -121,7 +186,8 @@ export function GameState(ctx: ContextI): StateI { } // Add bogus entity - addEntity(new PlayerEntity('animals.deer.animal.west.0')) + //addEntity(new PlayerEntity('animals.deer.animal.west.0'), 0, 0) + addEntity(new PlayerEntity('bogus-arrows.player.normal.e.0'), 0, 0) ctx.app.stage.addChild(rootContainer) } @@ -132,7 +198,15 @@ export function GameState(ctx: ContextI): StateI { } ctx.app.stage.removeChild(rootContainer) } + let elapsed: number = 0 let update = (delta: number) => { + elapsed += delta + // Run world sim. + while (elapsed >= 1/60) { + world.step(1/60) + elapsed -= 1/60 + } + // Update/render. for (let decoration of decorations) { decoration.update(delta) } @@ -144,17 +218,50 @@ export function GameState(ctx: ContextI): StateI { rootContainer.pivot.set(Math.max(rootContainer.width/6, Math.min(entity.x, rootContainer.width/3)), Math.max(rootContainer.height/6, Math.min(entity.y, rootContainer.height/3))) } entity.update(delta) + // I guess... + entity.sprite.container.x = entity.x + entity.sprite.container.y = entity.y } } - let addEntity = (entity: Entity) => { + let addEntity = (entity: Entity, x: number, y: number) => { if (entities.find(v=>v===entity)) return entities.push(entity) rootContainer.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) { + let shape: planck.Shape|undefined + if (spriteShape instanceof ShapeCircle) { + shape = planck.Circle(planck.Vec2(spriteShape.x, spriteShape.y), spriteShape.radius) + } else if (spriteShape instanceof ShapePoints) { + shape = planck.Polygon(spriteShape.points.map(v=>planck.Vec2(v[0], v[1]))) + } + if (shape !== undefined) { + let body = world.createDynamicBody({ + position: planck.Vec2(entity.x, entity.y), + fixedRotation: true, + }) + let fixture = body.createFixture({ + shape, + density: 1, + friction: 0.9, + restitution: 0.05, + }) + entity.body = body + body.setUserData(entity) + } + } + entity.x = x + entity.y = y } let removeEntity = (entity: Entity) => { entities = entities.filter(v=>v!==entity) rootContainer.removeChild(entity.sprite.container) + if (entity.body) { + world.destroyBody(entity.body) + entity.body = undefined + } } let desiredActions: Action[] = []