Reorganize; add collision zones

This commit is contained in:
Ketchetwahmeegwun T. Southall 2022-01-29 18:25:51 -08:00
parent 6f6c6628fc
commit fefb6b3f41
5 changed files with 240 additions and 206 deletions

View File

@ -0,0 +1,4 @@
export interface Action {
type: string
priority: number
}

68
Engine/src/live/Entity.ts Normal file
View File

@ -0,0 +1,68 @@
import * as planck from 'planck'
import { SpriteInstance } from '../shared/sprites'
export class Entity {
sprite: SpriteInstance
body?: planck.Body
velocity: [number, number] = [0, 0]
acceleration: number = 0.5
maxSpeed: number = 4
direction: number = 0
turnRate: number = 10
constructor(ctor: string) {
this.sprite = new SpriteInstance(ctor)
}
update(delta: number) {
// 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) {
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) {
if (this.body) {
let p = this.body.getPosition()
this.body.setPosition(
planck.Vec2(
p.x,
v,
)
)
} else {
this.sprite.container.y = v
}
}
}

View File

@ -0,0 +1,119 @@
import * as planck from 'planck'
import { Action } from "./Action"
import { Entity } from "./Entity"
export class PlayerEntity extends Entity {
action?: Action
constructor(ctor: string) {
super(ctor)
}
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.
let shouldMove = false
switch(this.action.type) {
case 'west':
if (this.direction !== 0) {
if (this.direction < 180) {
this.direction -= this.turnRate
} else {
this.direction += this.turnRate
}
}
shouldMove = true
break
case 'east':
if (this.direction !== 180) {
if (this.direction < 180) {
this.direction += this.turnRate
} else {
this.direction -= this.turnRate
}
}
shouldMove = true
break
case 'north':
if (this.direction !== 90) {
if (this.direction < 90 || this.direction > 270) {
this.direction += this.turnRate
} else {
this.direction -= this.turnRate
}
}
shouldMove = true
break
case 'south':
if (this.direction !== 270) {
if (this.direction > 90 && this.direction < 270) {
this.direction += this.turnRate
} else {
this.direction -= this.turnRate
}
}
shouldMove = true
break
}
if (this.direction > 360) {
this.direction = 0
} else if (this.direction < 0) {
this.direction = 360
}
if (shouldMove) {
let r = this.direction * (Math.PI/180)
if (Math.abs(this.velocity[0]) < this.maxSpeed) {
this.velocity[0] -= Math.cos(r) * this.acceleration
}
if (Math.abs(this.velocity[1]) < this.maxSpeed) {
this.velocity[1] -= Math.sin(r) * this.acceleration
}
let cardinal = this.getCardinal()
if (this.sprite.subsetKey !== cardinal) {
this.sprite.setCtor(`${this.sprite.spriteKey}.${this.sprite.animationKey}.${this.sprite.setKey}.${cardinal}.${this.sprite.frameIndex}`)
}
}
}
//
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]))
}
getCardinal(): string {
const degreesPerDirection = 360 / 8
const angle = this.direction + degreesPerDirection / 2
if (angle >= 0 * degreesPerDirection && angle < 1 * degreesPerDirection) {
return 'w'
} else if (angle >= 1 * degreesPerDirection && angle < 2 * degreesPerDirection) {
return 'nw'
} else if (angle >= 2 * degreesPerDirection && angle < 3 * degreesPerDirection) {
return 'n'
} else if (angle >= 3 * degreesPerDirection && angle < 4 * degreesPerDirection) {
return 'ne'
} else if (angle >= 4 * degreesPerDirection && angle < 5 * degreesPerDirection) {
return 'e'
} else if (angle >= 5 * degreesPerDirection && angle < 6 * degreesPerDirection) {
return 'se'
} else if (angle >= 6 * degreesPerDirection && angle < 7 * degreesPerDirection) {
return 's'
}
return 'sw'
}
}
export function isPlayerEntity(o: any): o is PlayerEntity {
return o.act
}

13
Engine/src/live/Zone.ts Normal file
View File

@ -0,0 +1,13 @@
import * as planck from 'planck'
import { SegmentZone } from '../data/segment'
export class Zone {
fixture: planck.Fixture|undefined
type: 'solid'|'fluid'
points: [number, number][]
constructor(z: SegmentZone) {
this.type = z.type
this.points = z.points.map(v=>[v[0], v[1]])
}
}

View File

@ -7,201 +7,15 @@ import { DecorationInstance } from "../shared/decors"
import { SpriteInstance, sprites } from "../shared/sprites"
import { ShapeCircle, ShapePoints } from "../data/sprite"
import { SegmentZone } from "../data/segment"
import { Zone } from "../live/Zone"
import { Entity } from "../live/Entity"
import { isPlayerEntity, PlayerEntity } from "../live/PlayerEntity"
import { Action } from "../live/Action"
interface Action {
type: string
priority: number
}
class Zone {
fixture: planck.Fixture|undefined
type: 'solid'|'fluid'
points: [number, number][]
constructor(z: SegmentZone) {
this.type = z.type
this.points = z.points.map(v=>[v[0], v[1]])
}
}
class Entity {
sprite: SpriteInstance
body?: planck.Body
velocity: [number, number] = [0, 0]
acceleration: number = 0.5
maxSpeed: number = 4
direction: number = 0
turnRate: number = 10
constructor(ctor: string) {
this.sprite = new SpriteInstance(ctor)
}
update(delta: number) {
// 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) {
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) {
if (this.body) {
let p = this.body.getPosition()
this.body.setPosition(
planck.Vec2(
p.x,
v,
)
)
} else {
this.sprite.container.y = v
}
}
}
class PlayerEntity extends Entity {
action?: Action
constructor(ctor: string) {
super(ctor)
}
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.
let shouldMove = false
switch(this.action.type) {
case 'west':
if (this.direction !== 0) {
if (this.direction < 180) {
this.direction -= this.turnRate
} else {
this.direction += this.turnRate
}
}
shouldMove = true
break
case 'east':
if (this.direction !== 180) {
if (this.direction < 180) {
this.direction += this.turnRate
} else {
this.direction -= this.turnRate
}
}
shouldMove = true
break
case 'north':
if (this.direction !== 90) {
if (this.direction < 90 || this.direction > 270) {
this.direction += this.turnRate
} else {
this.direction -= this.turnRate
}
}
shouldMove = true
break
case 'south':
if (this.direction !== 270) {
if (this.direction > 90 && this.direction < 270) {
this.direction += this.turnRate
} else {
this.direction -= this.turnRate
}
}
shouldMove = true
break
}
if (this.direction > 360) {
this.direction = 0
} else if (this.direction < 0) {
this.direction = 360
}
if (shouldMove) {
let r = this.direction * (Math.PI/180)
if (Math.abs(this.velocity[0]) < this.maxSpeed) {
this.velocity[0] -= Math.cos(r) * this.acceleration
}
if (Math.abs(this.velocity[1]) < this.maxSpeed) {
this.velocity[1] -= Math.sin(r) * this.acceleration
}
let cardinal = this.getCardinal()
if (this.sprite.subsetKey !== cardinal) {
this.sprite.setCtor(`${this.sprite.spriteKey}.${this.sprite.animationKey}.${this.sprite.setKey}.${cardinal}.${this.sprite.frameIndex}`)
}
}
}
//
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]))
}
getCardinal(): string {
const degreesPerDirection = 360 / 8
const angle = this.direction + degreesPerDirection / 2
if (angle >= 0 * degreesPerDirection && angle < 1 * degreesPerDirection) {
return 'w'
} else if (angle >= 1 * degreesPerDirection && angle < 2 * degreesPerDirection) {
return 'nw'
} else if (angle >= 2 * degreesPerDirection && angle < 3 * degreesPerDirection) {
return 'n'
} else if (angle >= 3 * degreesPerDirection && angle < 4 * degreesPerDirection) {
return 'ne'
} else if (angle >= 4 * degreesPerDirection && angle < 5 * degreesPerDirection) {
return 'e'
} else if (angle >= 5 * degreesPerDirection && angle < 6 * degreesPerDirection) {
return 'se'
} else if (angle >= 6 * degreesPerDirection && angle < 7 * degreesPerDirection) {
return 's'
}
return 'sw'
}
}
function isPlayerEntity(o: any): o is PlayerEntity {
return o.act
export interface Layer {
title: string
container: PIXI.Container
decorations: DecorationInstance[]
}
export function GameState(ctx: ContextI): StateI {
@ -213,7 +27,8 @@ export function GameState(ctx: ContextI): StateI {
})
let rootContainer = new PIXI.Container()
let decorations: DecorationInstance[] = []
let playLayer: Layer
let layers: Layer[] = []
let entities: Entity[] = []
let zones: Zone[] = []
@ -226,9 +41,19 @@ export function GameState(ctx: ContextI): StateI {
rootContainer.height = w.height
rootContainer.scale.set(2, 2)
for (let l of w.layers) {
let container = new PIXI.Container()
container.width = w.width
container.height = w.height
let layer: Layer = {
title: l.title,
container: new PIXI.Container(),
decorations: [],
}
layer.container.width = w.width
layer.container.height = w.height
if (l.title === 'objects') {
playLayer = layer
layer.container.sortableChildren = true
}
layers.push(layer)
for (let d of l.decorations) {
let di = new DecorationInstance(d.decor, d.decoration)
@ -255,11 +80,14 @@ export function GameState(ctx: ContextI): StateI {
di.container.position.y--
}
}
container.addChild(di.container)
decorations.push(di)
if (l.title === 'objects') {
di.container.zIndex = di.container.position.y + di.container.height/4
}
layer.container.addChild(di.container)
layer.decorations.push(di)
}
rootContainer.addChild(container)
rootContainer.addChild(layer.container)
}
for (let z of w.zones) {
@ -267,7 +95,6 @@ export function GameState(ctx: ContextI): StateI {
}
// Add bogus entity
//addEntity(new PlayerEntity('animals.deer.animal.west.0'), 0, 0)
addEntity(new PlayerEntity('bogus-arrows.player.normal.w.0'), 0, 0)
ctx.app.stage.addChild(rootContainer)
@ -288,8 +115,10 @@ export function GameState(ctx: ContextI): StateI {
elapsed -= 1/60
}
// Update/render.
for (let decoration of decorations) {
decoration.update(delta)
for (let layer of layers) {
for (let decoration of layer.decorations) {
decoration.update(delta)
}
}
for (let entity of entities) {
if (isPlayerEntity(entity)) {
@ -302,13 +131,14 @@ export function GameState(ctx: ContextI): StateI {
// I guess...
entity.sprite.container.x = entity.x
entity.sprite.container.y = entity.y
entity.sprite.container.zIndex = entity.y + (entity.sprite.frame?entity.sprite.frame.originY:0)
}
}
let addEntity = (entity: Entity, x: number, y: number) => {
if (entities.find(v=>v===entity)) return
entities.push(entity)
rootContainer.addChild(entity.sprite.container)
playLayer.container.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) {
@ -338,7 +168,7 @@ export function GameState(ctx: ContextI): StateI {
}
let removeEntity = (entity: Entity) => {
entities = entities.filter(v=>v!==entity)
rootContainer.removeChild(entity.sprite.container)
playLayer.container.removeChild(entity.sprite.container)
if (entity.body) {
world.destroyBody(entity.body)
entity.body = undefined