From 84eadde10139fb93a489b3b85f240449b09fd752 Mon Sep 17 00:00:00 2001 From: kts of kettek Date: Sat, 29 Jan 2022 04:57:01 -0800 Subject: [PATCH] Add some entity garbage --- Engine/src/data/sprite.ts | 94 ++++++++++++++++++++++ Engine/src/engine.ts | 2 + Engine/src/shared/sprites.ts | 35 ++++++++ Engine/src/states/Game.ts | 151 ++++++++++++++++++++++++++++++++++- 4 files changed, 280 insertions(+), 2 deletions(-) create mode 100644 Engine/src/data/sprite.ts create mode 100644 Engine/src/shared/sprites.ts diff --git a/Engine/src/data/sprite.ts b/Engine/src/data/sprite.ts new file mode 100644 index 0000000..7acc232 --- /dev/null +++ b/Engine/src/data/sprite.ts @@ -0,0 +1,94 @@ +import * as PIXI from 'pixi.js' + +export class Sprite { + uuid: string + texture: PIXI.Texture + originX: number = 0 + originY: number = 0 + x: number = 0 + y: number = 0 + width: number = 0 + height: number = 0 + root: SpritePart + + constructor(o: any) { + this.uuid = o.uuid + this.texture = PIXI.Texture.from('./Assets/Sprites/'+o.source) + this.texture.baseTexture.scaleMode = PIXI.SCALE_MODES.NEAREST + this.root = new SpritePart(o, { + texture: this.texture, + originX: 0, + originY: 0, + x: 0, + y: 0, + width: 0, + height: 0, + time: 0, + source: '', + }, this.texture) + } +} + +export interface SpritePartI { + texture: PIXI.Texture + originX: number + originY: number + x: number + y: number + width: number + height: number + time: number + source: string + children?: Record +} + +export class SpritePart { + texture: PIXI.Texture + originX: number = 0 + originY: number = 0 + x: number = 0 + y: number = 0 + width: number = 0 + height: number = 0 + time: number = 0 + source: string = '' + children: Record = {} + frames?: SpritePart[] + + constructor(o: any, p: SpritePartI, t: PIXI.Texture) { + this.time = o.time ?? p.time + this.x = o.x ?? p.x + this.y = o.y ?? p.y + this.width = o.width ?? p.width + this.height = o.height ?? p.height + this.originX = o.origin_x ?? p.originX + this.originY = o.origin_y ?? p.originY + if (o.source) { + t = PIXI.Texture.from('./Assets/Sprites/'+o.source) + t.baseTexture.scaleMode = PIXI.SCALE_MODES.NEAREST + } + if (this.x === p.x && this.y === p.y && this.width === p.width && this.height === p.height && o.source === p.source) { + this.texture = p.texture + } else { + this.texture = new PIXI.Texture(t.baseTexture, new PIXI.Rectangle(this.x, this.y, this.width, this.height)) + } + + if (o.animations) { + for (let [key, value] of Object.entries(o.animations)) { + this.children[key] = new SpritePart(value, this, t) + } + } else if (o.sets) { + for (let [key, value] of Object.entries(o.sets)) { + this.children[key] = new SpritePart(value, this, t) + } + } else if (o.subsets) { + for (let [key, value] of Object.entries(o.subsets)) { + this.children[key] = new SpritePart(value, this, t) + } + } else if (o.frames) { + this.frames = o.frames.map((v: any) => { + return new SpritePart(v, this, t) + }) + } + } +} \ No newline at end of file diff --git a/Engine/src/engine.ts b/Engine/src/engine.ts index dd51f7d..ebe1923 100644 --- a/Engine/src/engine.ts +++ b/Engine/src/engine.ts @@ -4,6 +4,7 @@ import { MenuState } from './states/Menu' import { StateI } from './states/StateI' import { decors } from './shared/decors' import { segments } from './shared/segments' +import { sprites } from './shared/sprites' export class Engine { ctx: ContextI @@ -19,6 +20,7 @@ export class Engine { console.log( decors, segments, + sprites, ) // Setup diff --git a/Engine/src/shared/sprites.ts b/Engine/src/shared/sprites.ts new file mode 100644 index 0000000..0c25f6b --- /dev/null +++ b/Engine/src/shared/sprites.ts @@ -0,0 +1,35 @@ +import assets from '../../../Assets/Sprites/**/*.yaml' +import { Sprite } from '../data/sprite' +import * as PIXI from 'pixi.js' + +export const sprites: Record = {} + +for (let [key, value] of Object.entries(assets)) { + sprites[key] = new Sprite(value) +} + +export class SpriteInstance { + container: PIXI.Container + + constructor(ctor: string) { + this.container = new PIXI.Container() + let [spriteKey, animationKey, setKey, subsetKey, frameKey] = ctor.split('.') + let frameIndex = Number(frameKey) + let sprite = sprites[spriteKey] + if (!sprite) { + this.container.addChild(new PIXI.Text('missing sprite')) + return + } + let animation = sprite.root.children[animationKey] + let set = animation.children[setKey] + let subset = set.children[subsetKey] + // + if (subset.frames) { + let frame = subset.frames[frameIndex] + let s = new PIXI.Sprite(frame.texture) + s.x -= frame.originX + s.y -= frame.originY + this.container.addChild(s) + } + } +} \ No newline at end of file diff --git a/Engine/src/states/Game.ts b/Engine/src/states/Game.ts index f418d08..a03eeb6 100644 --- a/Engine/src/states/Game.ts +++ b/Engine/src/states/Game.ts @@ -3,14 +3,89 @@ import { segments } from "../shared/segments" import { StateI } from "./StateI" import * as PIXI from 'pixi.js' import { DecorationInstance } from "../shared/decors" +import { SpriteInstance } from "../shared/sprites" + +interface Action { + type: string + priority: number +} + +class Entity { + sprite: SpriteInstance + + constructor(ctor: string) { + this.sprite = new SpriteInstance(ctor) + } + + update(delta: number) { + // TODO: Update sprite. + } + + get x(): number { + return this.sprite.container.x + } + set x(v: number) { + this.sprite.container.x = v + } + get y(): number { + return this.sprite.container.y + } + set y(v: number) { + this.sprite.container.y = v + } +} + +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) => { + 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. + switch(this.action.type) { + case 'west': + this.x-- + break + case 'east': + this.x++ + break + case 'north': + this.y-- + break + case 'south': + this.y++ + break + } + } + } +} +function isPlayerEntity(o: any): o is PlayerEntity { + return o.act +} export function GameState(ctx: ContextI): StateI { let rootContainer = new PIXI.Container() let decorations: DecorationInstance[] = [] + let entities: Entity[] = [] let enter = () => { - console.log('less goooo') + hookKeyboard() // Load the world segment. let w = segments.world if (!w) return ctx.pop() @@ -28,7 +103,6 @@ export function GameState(ctx: ContextI): StateI { di.container.x = d.x di.container.y = d.y if (d.flip) { - console.log('friggin flip it') di.container.pivot.y = 1 di.container.scale.y *= -1 di.container.position.y-- @@ -46,15 +120,88 @@ export function GameState(ctx: ContextI): StateI { rootContainer.addChild(container) } + // Add bogus entity + addEntity(new PlayerEntity('animals.deer.animal.west.0')) + ctx.app.stage.addChild(rootContainer) } let leave = () => { + unhookKeyboard() + for (let entity of entities) { + removeEntity(entity) + } ctx.app.stage.removeChild(rootContainer) } let update = (delta: number) => { for (let decoration of decorations) { decoration.update(delta) } + 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)) + rootContainer.pivot.set(entity.x, entity.y) + } + entity.update(delta) + } + } + + let addEntity = (entity: Entity) => { + if (entities.find(v=>v===entity)) return + entities.push(entity) + rootContainer.addChild(entity.sprite.container) + } + let removeEntity = (entity: Entity) => { + entities = entities.filter(v=>v!==entity) + rootContainer.removeChild(entity.sprite.container) + } + + let desiredActions: Action[] = [] + 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) } return {