@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
166 lines (124 loc) • 4.4 kB
JavaScript
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) {
}
}