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 { 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
|
||||
|
|
Loading…
Reference in New Issue
Block a user