Reorganize; add collision zones
This commit is contained in:
parent
6f6c6628fc
commit
fefb6b3f41
4
Engine/src/live/Action.ts
Normal file
4
Engine/src/live/Action.ts
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
export interface Action {
|
||||||
|
type: string
|
||||||
|
priority: number
|
||||||
|
}
|
68
Engine/src/live/Entity.ts
Normal file
68
Engine/src/live/Entity.ts
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
119
Engine/src/live/PlayerEntity.ts
Normal file
119
Engine/src/live/PlayerEntity.ts
Normal 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
13
Engine/src/live/Zone.ts
Normal 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]])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -7,201 +7,15 @@ import { DecorationInstance } from "../shared/decors"
|
||||||
import { SpriteInstance, sprites } from "../shared/sprites"
|
import { SpriteInstance, sprites } from "../shared/sprites"
|
||||||
import { ShapeCircle, ShapePoints } from "../data/sprite"
|
import { ShapeCircle, ShapePoints } from "../data/sprite"
|
||||||
import { SegmentZone } from "../data/segment"
|
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 {
|
export interface Layer {
|
||||||
type: string
|
title: string
|
||||||
priority: number
|
container: PIXI.Container
|
||||||
}
|
decorations: DecorationInstance[]
|
||||||
|
|
||||||
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 function GameState(ctx: ContextI): StateI {
|
export function GameState(ctx: ContextI): StateI {
|
||||||
|
@ -213,7 +27,8 @@ export function GameState(ctx: ContextI): StateI {
|
||||||
})
|
})
|
||||||
|
|
||||||
let rootContainer = new PIXI.Container()
|
let rootContainer = new PIXI.Container()
|
||||||
let decorations: DecorationInstance[] = []
|
let playLayer: Layer
|
||||||
|
let layers: Layer[] = []
|
||||||
let entities: Entity[] = []
|
let entities: Entity[] = []
|
||||||
let zones: Zone[] = []
|
let zones: Zone[] = []
|
||||||
|
|
||||||
|
@ -226,9 +41,19 @@ export function GameState(ctx: ContextI): StateI {
|
||||||
rootContainer.height = w.height
|
rootContainer.height = w.height
|
||||||
rootContainer.scale.set(2, 2)
|
rootContainer.scale.set(2, 2)
|
||||||
for (let l of w.layers) {
|
for (let l of w.layers) {
|
||||||
let container = new PIXI.Container()
|
let layer: Layer = {
|
||||||
container.width = w.width
|
title: l.title,
|
||||||
container.height = w.height
|
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) {
|
for (let d of l.decorations) {
|
||||||
let di = new DecorationInstance(d.decor, d.decoration)
|
let di = new DecorationInstance(d.decor, d.decoration)
|
||||||
|
@ -255,11 +80,14 @@ export function GameState(ctx: ContextI): StateI {
|
||||||
di.container.position.y--
|
di.container.position.y--
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
container.addChild(di.container)
|
if (l.title === 'objects') {
|
||||||
decorations.push(di)
|
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) {
|
for (let z of w.zones) {
|
||||||
|
@ -267,7 +95,6 @@ export function GameState(ctx: ContextI): StateI {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add bogus entity
|
// Add bogus entity
|
||||||
//addEntity(new PlayerEntity('animals.deer.animal.west.0'), 0, 0)
|
|
||||||
addEntity(new PlayerEntity('bogus-arrows.player.normal.w.0'), 0, 0)
|
addEntity(new PlayerEntity('bogus-arrows.player.normal.w.0'), 0, 0)
|
||||||
|
|
||||||
ctx.app.stage.addChild(rootContainer)
|
ctx.app.stage.addChild(rootContainer)
|
||||||
|
@ -288,8 +115,10 @@ export function GameState(ctx: ContextI): StateI {
|
||||||
elapsed -= 1/60
|
elapsed -= 1/60
|
||||||
}
|
}
|
||||||
// Update/render.
|
// Update/render.
|
||||||
for (let decoration of decorations) {
|
for (let layer of layers) {
|
||||||
decoration.update(delta)
|
for (let decoration of layer.decorations) {
|
||||||
|
decoration.update(delta)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (let entity of entities) {
|
for (let entity of entities) {
|
||||||
if (isPlayerEntity(entity)) {
|
if (isPlayerEntity(entity)) {
|
||||||
|
@ -302,13 +131,14 @@ export function GameState(ctx: ContextI): StateI {
|
||||||
// I guess...
|
// I guess...
|
||||||
entity.sprite.container.x = entity.x
|
entity.sprite.container.x = entity.x
|
||||||
entity.sprite.container.y = entity.y
|
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) => {
|
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)
|
playLayer.container.addChild(entity.sprite.container)
|
||||||
// I guess this is a fair enough place to create physics and add it to the entity.
|
// I guess this is a fair enough place to create physics and add it to the entity.
|
||||||
let spriteShape = entity.sprite.getBodyShape()
|
let spriteShape = entity.sprite.getBodyShape()
|
||||||
if (spriteShape) {
|
if (spriteShape) {
|
||||||
|
@ -338,7 +168,7 @@ export function GameState(ctx: ContextI): StateI {
|
||||||
}
|
}
|
||||||
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)
|
playLayer.container.removeChild(entity.sprite.container)
|
||||||
if (entity.body) {
|
if (entity.body) {
|
||||||
world.destroyBody(entity.body)
|
world.destroyBody(entity.body)
|
||||||
entity.body = undefined
|
entity.body = undefined
|
||||||
|
|
Loading…
Reference in New Issue
Block a user