UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

166 lines (124 loc) 4.4 kB
import { Cache } from "../../../../../core/cache/Cache.js"; import { SignalBinding } from "../../../../../core/events/signal/SignalBinding.js"; import { passThrough } from "../../../../../core/function/passThrough.js"; import { strictEquals } from "../../../../../core/function/strictEquals.js"; import Vector2 from "../../../../../core/geom/Vector2.js"; import { clamp } from "../../../../../core/math/clamp.js"; import { ResourceAccessKind } from "../../../../../core/model/ResourceAccessKind.js"; import { ResourceAccessSpecification } from "../../../../../core/model/ResourceAccessSpecification.js"; import { System } from "../../../../ecs/System.js"; import { obtainTerrain } from "../../../../ecs/terrain/util/obtainTerrain.js"; import { buildCameraTargetSampler } from "../../../../input/ecs/util/TerrainCameraTargetSampler.js"; import TopDownCameraController from "./TopDownCameraController.js"; import { TopDownCameraLander } from "./TopDownCameraLander.js"; /** * * @param {Terrain} terrain * @param {Cache<number,Sampler2D>} cache */ function getSampler(terrain, cache) { let sampler = cache.get(terrain.id); if (sampler === null) { //build new sampler const heightSampler = terrain.samplerHeight; if (heightSampler === null) { return null; } sampler = buildCameraTargetSampler({ heightSampler }); cache.put(terrain.id, sampler); } return sampler; } const v2_scratch = new Vector2(); /** * * @param {TopDownCameraLander} lander * @param {TopDownCameraController} controller * @param {Terrain} terrain * @param {Cache<number,Sampler2D>} samplerCache */ function land(lander, controller, terrain, samplerCache) { const sampler = getSampler(terrain, samplerCache); if (sampler === null) { //no sampler return; } /** * * @type {Vector3} */ const target = controller.target; terrain.mapPointWorld2Grid(target, v2_scratch); v2_scratch.divide(terrain.size); const x = clamp(v2_scratch.x * sampler.width, 0, sampler.width - 1); const y = clamp(v2_scratch.y * sampler.height, 0, sampler.height - 1); const value = sampler.sampleChannelBilinear(x, y, 0); target.setY(value); } export class TopDownCameraLanderSystem extends System { constructor() { super(); /** * * @type {Cache<number,Sampler2D>} */ this.samplerCache = new Cache({ maxWeight: 2, keyHashFunction: passThrough, keyEqualityFunction: strictEquals }); this.dependencies = [TopDownCameraLander, TopDownCameraController]; this.components_used = [ ResourceAccessSpecification.from(TopDownCameraController,ResourceAccessKind.Read|ResourceAccessKind.Write) ]; /** * @private * @type {Array} */ this.data = []; } /** * * @param {TopDownCameraLander} lander * @param {TopDownCameraController} controller * @param {number} entity */ link(lander, controller, entity) { const doLand = () => { const em = this.entityManager; const ecd = em.dataset; if (ecd === null) { return; } /** * * @type {Terrain} */ const terrain = obtainTerrain(ecd); if (terrain === null) { return; } //TODO add scheduling of landing if any of the prerequisites are missing land(lander, controller, terrain, this.samplerCache); }; const binding = new SignalBinding(controller.target.onChanged, doLand); binding.link(); doLand(); this.data[entity] = binding; } /** * * @param {TopDownCameraLander} lander * @param {TopDownCameraController} controller * @param {number} entity */ unlink(lander, controller, entity) { const bindings = this.data[entity]; if (bindings !== undefined) { bindings.unlink(); delete this.data[entity]; } } update(timeDelta) { } }