diff --git a/Engine/src/live/AnimalEntity.ts b/Engine/src/live/AnimalEntity.ts index eb60eb7..cd0b09b 100644 --- a/Engine/src/live/AnimalEntity.ts +++ b/Engine/src/live/AnimalEntity.ts @@ -3,6 +3,7 @@ import { AnimalDefinition, CreatureDefinition } from '../data/animals' import { playSong, playSound } from '../shared/audio' import { Action, adjustAction } from "./Action" import { Entity, Sensor } from "./Entity" +import { GibletEntity } from './GibletEntity' import { PuddleEntity } from './PuddleEntity' import { WorldContext } from './World' @@ -22,6 +23,8 @@ export class AnimalEntity extends Entity { stepSoundElapsed: number = 0 lastYellElapsed: number = 0 nextYell: number = 1000 + dead: boolean = false + shouldGib: boolean = false constructor(def: AnimalDefinition) { super(`${def.name}.animal.stand.west.0`) @@ -44,6 +47,16 @@ export class AnimalEntity extends Entity { } update(delta: number, ctx: WorldContext) { super.update(delta) + + if (this.dead) { + if (this.shouldGib) { + this.gib(ctx) + this.shouldGib = false + } + this.shouldRemove = true + return + } + this.lastYellElapsed += delta let waterZones = this.zones.filter(v=>v.type==='fluid') @@ -262,6 +275,31 @@ export class AnimalEntity extends Entity { } } } + gib(ctx: WorldContext) { + let p = this.position + p[0] += this.sprite.container.width/2 + p[1] += this.sprite.container.height/2 + this.dead = true + let force = -1 + Math.random() * 2 + let dir = Math.random() * 320 + // 50% head gib + if (Math.random() > 0.5) { + ctx.addEntity(new GibletEntity(`giblets.${this.sprite.spriteKey}.head.default.0`, dir+Math.random()*40, force+Math.random()*10), 'objects', p[0], p[1]) + } + // 44% leg gib per leg + for (let i = 0; i < 4; i++) { + if (Math.random() > 0.66) { + ctx.addEntity(new GibletEntity(`giblets.${this.sprite.spriteKey}.leg.default.0`, dir+Math.random()*40, force+Math.random()*10), 'objects', p[0], p[1]) + } + } + // 35% extra gibs per 8 + for (let i = 0; i < 8; i++) { + if (Math.random() > 0.65) { + ctx.addEntity(new GibletEntity(`giblets.any.chunk${Math.floor(1+Math.random()*4)}.default.0`, dir+Math.random()*40, force+Math.random()*10), 'objects', p[0], p[1]) + } + } + playSound(`action/splat-v${1+Math.floor(Math.random()*7)}`, 0.5) + } } export function isAnimalEntity(o: any): o is AnimalEntity { diff --git a/Engine/src/live/Entity.ts b/Engine/src/live/Entity.ts index 8b0345c..971d46d 100644 --- a/Engine/src/live/Entity.ts +++ b/Engine/src/live/Entity.ts @@ -24,6 +24,7 @@ export class Entity { turnRate: number = 10 zones: Zone[] = [] contacts: Entity[] = [] + shouldRemove: boolean = false constructor(ctor: string) { this.sprite = new SpriteInstance(ctor) diff --git a/Engine/src/live/GibletEntity.ts b/Engine/src/live/GibletEntity.ts new file mode 100644 index 0000000..f530e0c --- /dev/null +++ b/Engine/src/live/GibletEntity.ts @@ -0,0 +1,32 @@ +import * as planck from 'planck' +import { Entity } from "./Entity" +import { WorldContext } from "./World" + +export class GibletEntity extends Entity { + lifetime: number = 10000 + elapsed: number = 0 + constructor(ctor: string, dir: number, force: number) { + super(ctor) + console.log('dir', dir, 'force', force) + let r = dir * (Math.PI/180) + this.velocity[0] = Math.cos(r) * force + this.velocity[1] = Math.sin(r) * force + console.log('velocity', this.velocity) + } + update(delta: number, ctx?: WorldContext) { + super.update(delta) + this.elapsed += delta + + this.velocity[0] *= 0.85 + this.velocity[1] *= 0.85 + + // Eh... let's manually handle velocity + this.x += this.velocity[0] + this.y += this.velocity[1] + + if (this.elapsed >= this.lifetime) { + ctx?.removeEntity(this) + } + } + +} \ No newline at end of file diff --git a/Engine/src/states/Game.ts b/Engine/src/states/Game.ts index f93e5d0..1f56079 100644 --- a/Engine/src/states/Game.ts +++ b/Engine/src/states/Game.ts @@ -14,6 +14,7 @@ import { AnimalEntity, isAnimalEntity } from "../live/AnimalEntity" import { Action, adjustAction } from "../live/Action" import { WorldContext } from "../live/World" import { animals } from "../data/animals" +import { GibletEntity } from "../live/GibletEntity" export interface PIXIMissingColorMatrix extends PIXI.Filter { night(intensity: number, multiply: boolean): void @@ -46,7 +47,15 @@ export function GameState(ctx: ContextI, selectedAnimal: string, selectedSegment }) let worldBody: planck.Body = world.createBody({ type: 'static', + linearDamping: 1, }) + worldBody.setPosition(planck.Vec2(0, 0)) + let worldFixture = worldBody.createFixture({ + shape: planck.Box(1, 1), + friction: 10, + density: 100, + }) + world.on('begin-contact', (contact: planck.Contact) => { let a = contact.getFixtureA().getUserData() let b = contact.getFixtureB().getUserData() @@ -199,7 +208,14 @@ export function GameState(ctx: ContextI, selectedAnimal: string, selectedSegment let x = bounds[0] + Math.floor(Math.random() * bounds[2]) let y = bounds[1] + Math.floor(Math.random() * bounds[3]) - addEntity(new AnimalEntity(animals[animal]), 'objects', x, y) + let entity = new AnimalEntity(animals[animal]) + + setTimeout(() => { + entity.dead = true + entity.shouldGib = true + }, 1000+Math.random()*3000) + + addEntity(entity, 'objects', x, y) } } ctx.app.stage.addChild(rootContainer) @@ -231,9 +247,9 @@ export function GameState(ctx: ContextI, selectedAnimal: string, selectedSegment nightfall(true) } // Run world sim. - while (elapsed >= 1/2) { - world.step(1/2) - elapsed -= 1/2 + while (elapsed >= 1/6) { + world.step(1/6) + elapsed -= 1/6 } // Update/render. /*for (let layer of layers) { @@ -260,6 +276,15 @@ export function GameState(ctx: ContextI, selectedAnimal: string, selectedSegment entity.sprite.container.y = entity.y entity.sprite.container.zIndex = entity.y + (entity.sprite.frame?entity.sprite.frame.originY??0:0) } + // I guess this is okay. + for (let entity of entities) { + if (entity.shouldRemove) { + if (entity instanceof AnimalEntity) { + removeEntity(entity) + } + } + } + //entities = entities.filter(v=>v.shouldRemove) } let addEntity = (entity: Entity, layerTitle: string, x: number, y: number) => {