2022-01-29 01:37:01 -08:00
|
|
|
import { ContextI } from "../ContextI"
|
2022-01-29 03:44:34 -08:00
|
|
|
import { segments } from "../shared/segments"
|
2022-01-29 19:46:15 -08:00
|
|
|
import { audio, playSong, disableSound, enableSound } from '../shared/audio'
|
2022-01-29 01:37:01 -08:00
|
|
|
import { StateI } from "./StateI"
|
2022-01-29 03:44:34 -08:00
|
|
|
import * as PIXI from 'pixi.js'
|
2022-01-29 16:31:40 -08:00
|
|
|
import * as planck from 'planck'
|
2022-01-29 03:44:34 -08:00
|
|
|
import { DecorationInstance } from "../shared/decors"
|
2022-01-29 16:31:40 -08:00
|
|
|
import { SpriteInstance, sprites } from "../shared/sprites"
|
|
|
|
import { ShapeCircle, ShapePoints } from "../data/sprite"
|
2022-01-29 17:54:53 -08:00
|
|
|
import { SegmentZone } from "../data/segment"
|
2022-01-29 18:25:51 -08:00
|
|
|
import { Zone } from "../live/Zone"
|
|
|
|
import { Entity } from "../live/Entity"
|
|
|
|
import { isPlayerEntity, PlayerEntity } from "../live/PlayerEntity"
|
|
|
|
import { Action } from "../live/Action"
|
|
|
|
|
2022-01-29 19:46:15 -08:00
|
|
|
export interface PIXIMissingColorMatrix extends PIXI.Filter {
|
|
|
|
night(intensity: number, multiply: boolean): void
|
|
|
|
contrast(amount: number, multiply: boolean): void
|
|
|
|
brightness(amount: number, multiply: boolean): void
|
|
|
|
saturate(amount: number, multiply: boolean): void
|
|
|
|
hue(rotation: number, multiply: boolean): void
|
|
|
|
colorTone(desaturation: number, toned: number, lightColor: number, darkColor: number, multiple: boolean): void
|
|
|
|
reset(): void
|
|
|
|
}
|
|
|
|
|
2022-01-29 18:25:51 -08:00
|
|
|
export interface Layer {
|
|
|
|
title: string
|
|
|
|
container: PIXI.Container
|
|
|
|
decorations: DecorationInstance[]
|
2022-01-29 19:46:15 -08:00
|
|
|
colorMatrix: PIXIMissingColorMatrix
|
2022-01-29 04:57:01 -08:00
|
|
|
}
|
2022-01-29 01:37:01 -08:00
|
|
|
|
|
|
|
export function GameState(ctx: ContextI): StateI {
|
2022-01-29 19:46:15 -08:00
|
|
|
disableSound()
|
2022-01-29 16:31:40 -08:00
|
|
|
let world: planck.World = planck.World({
|
|
|
|
gravity: planck.Vec2(0, 0),
|
|
|
|
})
|
2022-01-29 17:54:53 -08:00
|
|
|
let worldBody: planck.Body = world.createBody({
|
|
|
|
type: 'static',
|
|
|
|
})
|
2022-01-29 01:37:01 -08:00
|
|
|
|
2022-01-29 03:44:34 -08:00
|
|
|
let rootContainer = new PIXI.Container()
|
2022-01-29 18:25:51 -08:00
|
|
|
let playLayer: Layer
|
|
|
|
let layers: Layer[] = []
|
2022-01-29 04:57:01 -08:00
|
|
|
let entities: Entity[] = []
|
2022-01-29 17:54:53 -08:00
|
|
|
let zones: Zone[] = []
|
2022-01-29 03:44:34 -08:00
|
|
|
|
2022-01-29 01:37:01 -08:00
|
|
|
let enter = () => {
|
2022-01-29 04:57:01 -08:00
|
|
|
hookKeyboard()
|
2022-01-29 03:44:34 -08:00
|
|
|
// Load the world segment.
|
|
|
|
let w = segments.world
|
|
|
|
if (!w) return ctx.pop()
|
|
|
|
rootContainer.width = w.width
|
|
|
|
rootContainer.height = w.height
|
|
|
|
rootContainer.scale.set(2, 2)
|
|
|
|
for (let l of w.layers) {
|
2022-01-29 18:25:51 -08:00
|
|
|
let layer: Layer = {
|
|
|
|
title: l.title,
|
|
|
|
container: new PIXI.Container(),
|
|
|
|
decorations: [],
|
2022-01-29 19:46:15 -08:00
|
|
|
colorMatrix: new PIXI.filters.ColorMatrixFilter()
|
2022-01-29 18:25:51 -08:00
|
|
|
}
|
2022-01-29 19:46:15 -08:00
|
|
|
layer.container.filters = [layer.colorMatrix]
|
2022-01-29 18:25:51 -08:00
|
|
|
layer.container.width = w.width
|
|
|
|
layer.container.height = w.height
|
|
|
|
|
|
|
|
if (l.title === 'objects') {
|
|
|
|
playLayer = layer
|
|
|
|
layer.container.sortableChildren = true
|
|
|
|
}
|
|
|
|
layers.push(layer)
|
2022-01-29 03:44:34 -08:00
|
|
|
|
|
|
|
for (let d of l.decorations) {
|
|
|
|
let di = new DecorationInstance(d.decor, d.decoration)
|
|
|
|
di.elapsed = d.timeOffset
|
|
|
|
di.container.x = d.x
|
|
|
|
di.container.y = d.y
|
2022-01-29 16:31:40 -08:00
|
|
|
if (d.rotation !== 0) {
|
|
|
|
di.container.angle = d.rotation
|
|
|
|
}
|
2022-01-29 03:44:34 -08:00
|
|
|
if (d.flip) {
|
|
|
|
di.container.pivot.y = 1
|
|
|
|
di.container.scale.y *= -1
|
2022-01-29 16:31:40 -08:00
|
|
|
if (d.rotation === 0) {
|
|
|
|
di.container.position.y--
|
|
|
|
}
|
2022-01-29 03:44:34 -08:00
|
|
|
}
|
|
|
|
if (d.mirror) {
|
|
|
|
di.container.pivot.x = 1
|
|
|
|
di.container.scale.x *= -1
|
|
|
|
di.container.position.x--
|
2022-01-29 16:31:40 -08:00
|
|
|
if (d.rotation !== 0) {
|
|
|
|
di.container.angle = -d.rotation
|
|
|
|
di.container.position.x++
|
|
|
|
di.container.position.y--
|
|
|
|
}
|
2022-01-29 03:44:34 -08:00
|
|
|
}
|
2022-01-29 18:25:51 -08:00
|
|
|
if (l.title === 'objects') {
|
|
|
|
di.container.zIndex = di.container.position.y + di.container.height/4
|
|
|
|
}
|
|
|
|
layer.container.addChild(di.container)
|
|
|
|
layer.decorations.push(di)
|
2022-01-29 03:44:34 -08:00
|
|
|
}
|
|
|
|
|
2022-01-29 18:25:51 -08:00
|
|
|
rootContainer.addChild(layer.container)
|
2022-01-29 03:44:34 -08:00
|
|
|
}
|
|
|
|
|
2022-01-29 17:54:53 -08:00
|
|
|
for (let z of w.zones) {
|
|
|
|
addZone(new Zone(z))
|
|
|
|
}
|
|
|
|
|
2022-01-29 04:57:01 -08:00
|
|
|
// Add bogus entity
|
2022-01-29 17:06:13 -08:00
|
|
|
addEntity(new PlayerEntity('bogus-arrows.player.normal.w.0'), 0, 0)
|
2022-01-29 04:57:01 -08:00
|
|
|
|
2022-01-29 03:44:34 -08:00
|
|
|
ctx.app.stage.addChild(rootContainer)
|
2022-01-29 01:37:01 -08:00
|
|
|
}
|
|
|
|
let leave = () => {
|
2022-01-29 04:57:01 -08:00
|
|
|
unhookKeyboard()
|
|
|
|
for (let entity of entities) {
|
|
|
|
removeEntity(entity)
|
|
|
|
}
|
2022-01-29 03:44:34 -08:00
|
|
|
ctx.app.stage.removeChild(rootContainer)
|
2022-01-29 01:37:01 -08:00
|
|
|
}
|
2022-01-29 16:31:40 -08:00
|
|
|
let elapsed: number = 0
|
2022-01-29 01:37:01 -08:00
|
|
|
let update = (delta: number) => {
|
2022-01-29 16:31:40 -08:00
|
|
|
elapsed += delta
|
|
|
|
// Run world sim.
|
|
|
|
while (elapsed >= 1/60) {
|
|
|
|
world.step(1/60)
|
|
|
|
elapsed -= 1/60
|
|
|
|
}
|
|
|
|
// Update/render.
|
2022-01-29 18:25:51 -08:00
|
|
|
for (let layer of layers) {
|
|
|
|
for (let decoration of layer.decorations) {
|
|
|
|
decoration.update(delta)
|
|
|
|
}
|
2022-01-29 03:44:34 -08:00
|
|
|
}
|
2022-01-29 04:57:01 -08:00
|
|
|
for (let entity of entities) {
|
|
|
|
if (isPlayerEntity(entity)) {
|
|
|
|
entity.act(desiredActions)
|
|
|
|
// FIXME: This isn't the right place for this.
|
|
|
|
rootContainer.position.set(Math.round(ctx.app.renderer.width/2), Math.round(ctx.app.renderer.height/2))
|
2022-01-29 05:18:51 -08:00
|
|
|
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)))
|
2022-01-29 04:57:01 -08:00
|
|
|
}
|
|
|
|
entity.update(delta)
|
2022-01-29 16:31:40 -08:00
|
|
|
// I guess...
|
|
|
|
entity.sprite.container.x = entity.x
|
|
|
|
entity.sprite.container.y = entity.y
|
2022-01-29 18:25:51 -08:00
|
|
|
entity.sprite.container.zIndex = entity.y + (entity.sprite.frame?entity.sprite.frame.originY:0)
|
2022-01-29 04:57:01 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-29 16:31:40 -08:00
|
|
|
let addEntity = (entity: Entity, x: number, y: number) => {
|
2022-01-29 04:57:01 -08:00
|
|
|
if (entities.find(v=>v===entity)) return
|
|
|
|
entities.push(entity)
|
2022-01-29 18:25:51 -08:00
|
|
|
playLayer.container.addChild(entity.sprite.container)
|
2022-01-29 16:31:40 -08:00
|
|
|
// 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
|
2022-01-29 04:57:01 -08:00
|
|
|
}
|
|
|
|
let removeEntity = (entity: Entity) => {
|
|
|
|
entities = entities.filter(v=>v!==entity)
|
2022-01-29 18:25:51 -08:00
|
|
|
playLayer.container.removeChild(entity.sprite.container)
|
2022-01-29 16:31:40 -08:00
|
|
|
if (entity.body) {
|
|
|
|
world.destroyBody(entity.body)
|
|
|
|
entity.body = undefined
|
|
|
|
}
|
2022-01-29 04:57:01 -08:00
|
|
|
}
|
|
|
|
|
2022-01-29 17:54:53 -08:00
|
|
|
// Zonage
|
|
|
|
let addZone = (zone: Zone) => {
|
|
|
|
if (zones.find(v=>v===zone)) return
|
|
|
|
let shape = planck.Chain(zone.points.map(v=>planck.Vec2(v[0],v[1])))
|
|
|
|
zone.fixture = worldBody.createFixture({
|
|
|
|
shape: shape,
|
|
|
|
})
|
|
|
|
if (zone.type === 'fluid') {
|
|
|
|
zone.fixture.setSensor(true)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let removeZone = (zone: Zone) => {
|
|
|
|
zones = zones.filter(v=>v!==zone)
|
|
|
|
if (zone.fixture) {
|
|
|
|
worldBody.destroyFixture(zone.fixture)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let desiredActions: Action[] = []
|
2022-01-29 04:57:01 -08:00
|
|
|
let adjustAction = (type: string, v: number) => {
|
|
|
|
let action = desiredActions.find(v=>v.type===type)
|
|
|
|
if (!action) {
|
|
|
|
desiredActions.push({
|
|
|
|
type: type,
|
|
|
|
priority: v,
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
action.priority += v
|
|
|
|
if (action.priority <= 0) {
|
|
|
|
desiredActions = desiredActions.filter(v=>v!==action)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let keyup = (e: KeyboardEvent) => {
|
|
|
|
if (e.key === 'ArrowLeft') {
|
|
|
|
adjustAction('west', -1)
|
|
|
|
} else if (e.key === 'ArrowRight') {
|
|
|
|
adjustAction('east', -1)
|
|
|
|
} else if (e.key === 'ArrowUp') {
|
|
|
|
adjustAction('north', -1)
|
|
|
|
} else if (e.key === 'ArrowDown') {
|
|
|
|
adjustAction('south', -1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let keydown = (e: KeyboardEvent) => {
|
|
|
|
if (e.repeat) return
|
|
|
|
if (e.key === 'ArrowLeft') {
|
|
|
|
adjustAction('west', 1)
|
|
|
|
} else if (e.key === 'ArrowRight') {
|
|
|
|
adjustAction('east', 1)
|
|
|
|
} else if (e.key === 'ArrowUp') {
|
|
|
|
adjustAction('north', 1)
|
|
|
|
} else if (e.key === 'ArrowDown') {
|
|
|
|
adjustAction('south', 1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let hookKeyboard = () => {
|
|
|
|
window.addEventListener('keyup', keyup)
|
|
|
|
window.addEventListener('keydown', keydown)
|
|
|
|
}
|
|
|
|
let unhookKeyboard = () => {
|
|
|
|
window.removeEventListener('keyup', keyup)
|
|
|
|
window.removeEventListener('keydown', keydown)
|
2022-01-29 01:37:01 -08:00
|
|
|
}
|
|
|
|
|
2022-01-29 19:46:15 -08:00
|
|
|
let nightfall = (b: boolean) => {
|
|
|
|
if (b) {
|
|
|
|
for (let l of layers) {
|
|
|
|
//l.colorMatrix.brightness(0.25, false)
|
|
|
|
l.colorMatrix.night(0.2, true)
|
|
|
|
l.colorMatrix.saturate(-0.75, true)
|
|
|
|
//l.colorMatrix.hue(160, true)
|
|
|
|
}
|
|
|
|
for (let e of entities) {
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
playSong('GGJ-HappyMusic')
|
|
|
|
for (let l of layers) {
|
|
|
|
l.colorMatrix.reset()
|
|
|
|
}
|
|
|
|
for (let e of entities) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nightfall(false)
|
|
|
|
|
2022-01-29 01:37:01 -08:00
|
|
|
return {
|
|
|
|
enter,
|
|
|
|
leave,
|
|
|
|
update,
|
|
|
|
}
|
|
|
|
}
|