import {h} from "preact"
import * as preact from "preact"
import * as cannon from "cannon"
import * as babylon from "babylonjs"
import {GameOptions, GameContext} from "./game-interfaces"
import {Ticker} from "../ticker"
import {Manager} from "../manager"
import {Viewport} from "../viewport"
import {Conductor} from "../conductor"
import {Overlay} from "../overlay/components/overlay"
import {Service} from "../toolbox/toolbox-interfaces"
import {OverlayStore} from "../overlay/stores/overlay-store"
import {StatisticsStore} from "../overlay/stores/statistics-store"
/**
* Standard monarch game
*/
export class Game implements Service {
readonly manager: Manager
private readonly viewport: Viewport
private readonly logicTicker: Ticker
constructor(options: GameOptions) {
const {overlayElement, canvas, mode, entityClasses, gravity} = options
// babylon engine as the foundation
const engine = new babylon.Engine(canvas, true, undefined, true)
const scene = new babylon.Scene(engine)
// cannon physics enabled
const physicsPlugin = new babylon.CannonJSPlugin()
const physicsWorld: cannon.World = physicsPlugin.world
physicsWorld.allowSleep = true
physicsWorld.broadphase = new cannon.SAPBroadphase(physicsWorld)
scene.enablePhysics(babylon.Vector3.FromArray(gravity), physicsPlugin)
// viewport handles render loop and pointer lock
const viewport = this.viewport = new Viewport({
window,
canvas,
scene,
engine
})
// 2d overlay
const statisticsStore = new StatisticsStore()
const overlayStore = new OverlayStore({statisticsStore})
const {mainMenuStore} = overlayStore
preact.render(
,
undefined,
overlayElement
)
// conductor keeps gamestate and entity replication
const conductor = new Conductor({
mode,
entityClasses,
context: {
scene,
window,
canvas,
engine,
physicsWorld,
overlayStore,
mainMenuStore
}
})
// make the logic ticker
this.logicTicker = this.makeLogicTicker({
viewport,
conductor,
statisticsStore,
durationBetweenTicks: 0,
timeBetweenStatRecordings: 0
})
// expose the state manager
this.manager = conductor.manager
}
start() {
this.logicTicker.start()
this.viewport.start()
}
stop() {
this.logicTicker.stop()
this.viewport.stop()
}
destructor() {
this.logicTicker.destructor()
this.viewport.destructor()
}
private makeLogicTicker({
viewport,
conductor,
statisticsStore,
durationBetweenTicks,
timeBetweenStatRecordings
}: {
viewport: Viewport
conductor: Conductor
statisticsStore: StatisticsStore
durationBetweenTicks?: number
timeBetweenStatRecordings?: number
}) {
let statmark = 0
let ticker
return ticker = new Ticker({
tickAction: tick => {
conductor.logic(tick)
if (ticker && tick.timeline - statmark > timeBetweenStatRecordings) {
statisticsStore.recordTickerStats(ticker)
statisticsStore.recordViewportStats(viewport)
statmark = tick.timeline
}
},
durationBetweenTicks
})
}
}