Add some physics handling

This commit is contained in:
Ketchetwahmeegwun T. Southall 2022-01-29 16:31:40 -08:00
parent b3ef7a86f0
commit 745c3573a7

View File

@ -2,8 +2,10 @@ import { ContextI } from "../ContextI"
import { segments } from "../shared/segments" import { segments } from "../shared/segments"
import { StateI } from "./StateI" import { StateI } from "./StateI"
import * as PIXI from 'pixi.js' import * as PIXI from 'pixi.js'
import * as planck from 'planck'
import { DecorationInstance } from "../shared/decors" import { DecorationInstance } from "../shared/decors"
import { SpriteInstance } from "../shared/sprites" import { SpriteInstance, sprites } from "../shared/sprites"
import { ShapeCircle, ShapePoints } from "../data/sprite"
interface Action { interface Action {
type: string type: string
@ -12,6 +14,11 @@ interface Action {
class Entity { class Entity {
sprite: SpriteInstance sprite: SpriteInstance
body?: planck.Body
velocity: [number, number] = [0, 0]
acceleration: number = 0.5
maxSpeed: number = 4
direction: number = 0
constructor(ctor: string) { constructor(ctor: string) {
this.sprite = new SpriteInstance(ctor) this.sprite = new SpriteInstance(ctor)
@ -21,17 +28,52 @@ class Entity {
// TODO: Update sprite. // 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 { get x(): number {
if (this.body) {
let p = this.body.getPosition()
return p.x
}
return this.sprite.container.x return this.sprite.container.x
} }
set x(v: number) { 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 { get y(): number {
if (this.body) {
let p = this.body.getPosition()
return p.y
}
return this.sprite.container.y return this.sprite.container.y
} }
set y(v: number) { 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 action?: Action
constructor(ctor: string) { constructor(ctor: string) {
super(ctor) super(ctor)
this.x = 100
this.y = 100
// TODO: Hooks for key state check input, perhaps?
} }
act(actions: Action[]) { act(actions: Action[]) {
this.action = actions.sort((a, b) => { this.action = actions.sort((a, b) => {
@ -59,19 +98,33 @@ class PlayerEntity extends Entity {
// FIXME: Use physics. // FIXME: Use physics.
switch(this.action.type) { switch(this.action.type) {
case 'west': case 'west':
this.x-- if (this.velocity[0] > -this.maxSpeed) {
this.velocity[0] -= this.acceleration
}
break break
case 'east': case 'east':
this.x++ if (this.velocity[0] < this.maxSpeed) {
this.velocity[0] += this.acceleration
}
break break
case 'north': case 'north':
this.y-- if (this.velocity[1] > -this.maxSpeed) {
this.velocity[1] -= this.acceleration
}
break break
case 'south': case 'south':
this.y++ if (this.velocity[1] < this.maxSpeed) {
this.velocity[1] += this.acceleration
}
break 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 { function isPlayerEntity(o: any): o is PlayerEntity {
@ -79,6 +132,9 @@ function isPlayerEntity(o: any): o is PlayerEntity {
} }
export function GameState(ctx: ContextI): StateI { export function GameState(ctx: ContextI): StateI {
let world: planck.World = planck.World({
gravity: planck.Vec2(0, 0),
})
let rootContainer = new PIXI.Container() let rootContainer = new PIXI.Container()
let decorations: DecorationInstance[] = [] let decorations: DecorationInstance[] = []
@ -102,17 +158,26 @@ export function GameState(ctx: ContextI): StateI {
di.elapsed = d.timeOffset di.elapsed = d.timeOffset
di.container.x = d.x di.container.x = d.x
di.container.y = d.y di.container.y = d.y
if (d.rotation !== 0) {
di.container.angle = d.rotation
}
if (d.flip) { if (d.flip) {
di.container.pivot.y = 1 di.container.pivot.y = 1
di.container.scale.y *= -1 di.container.scale.y *= -1
di.container.position.y-- if (d.rotation === 0) {
di.container.position.y--
}
} }
if (d.mirror) { if (d.mirror) {
di.container.pivot.x = 1 di.container.pivot.x = 1
di.container.scale.x *= -1 di.container.scale.x *= -1
di.container.position.x-- 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) container.addChild(di.container)
decorations.push(di) decorations.push(di)
} }
@ -121,7 +186,8 @@ export function GameState(ctx: ContextI): StateI {
} }
// Add bogus entity // 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) ctx.app.stage.addChild(rootContainer)
} }
@ -132,7 +198,15 @@ export function GameState(ctx: ContextI): StateI {
} }
ctx.app.stage.removeChild(rootContainer) ctx.app.stage.removeChild(rootContainer)
} }
let elapsed: number = 0
let update = (delta: number) => { 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) { for (let decoration of decorations) {
decoration.update(delta) 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))) 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) 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 if (entities.find(v=>v===entity)) return
entities.push(entity) entities.push(entity)
rootContainer.addChild(entity.sprite.container) 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) => { let removeEntity = (entity: Entity) => {
entities = entities.filter(v=>v!==entity) entities = entities.filter(v=>v!==entity)
rootContainer.removeChild(entity.sprite.container) rootContainer.removeChild(entity.sprite.container)
if (entity.body) {
world.destroyBody(entity.body)
entity.body = undefined
}
} }
let desiredActions: Action[] = [] let desiredActions: Action[] = []