A hackable template for creating small and fast browser games.
at main 72 lines 2.4 kB view raw
1/** 2 * # SpatialNode2D 3 * 4 * The `SpatialNode2D` component allows the entity to be part of the 2D scene 5 * graph. 6 * 7 * Only entities with `SpatialNode2D` can be parented to other entities, or be 8 * parents of other entities. 9 */ 10 11import {mat2d_create} from "../../lib/mat2d.js"; 12import {Mat2D} from "../../lib/math.js"; 13import {Entity} from "../../lib/world.js"; 14import {FLOATS_PER_INSTANCE} from "../../materials/layout2d.js"; 15import {Game} from "../game.js"; 16import {Has, World} from "../world.js"; 17 18export interface SpatialNode2D { 19 /** Absolute matrix relative to the world. */ 20 World: Mat2D; 21 /** World to self matrix. */ 22 Self: Mat2D; 23 Parent?: Entity; 24 /** Ignore parent's rotation and scale? */ 25 IsGyroscope: boolean; 26} 27 28/** 29 * Add `SpatialNode2D` to an entity. 30 * 31 * In order to be a parent of other entities, or to be a child of another entity, 32 * the entity must also have the `SpatialNode2D` component. It's also required 33 * if you're going to need to switch between the world space and the entity's 34 * self space, or if you're going to query the entity's parent. 35 * 36 * Entities with `LocalTransform2D` and `SpatialNode2D` have their model matrix 37 * computed in sys_transform2d() on the CPU, making them slower than entities 38 * with only `LocalTransform2D`, but more fully-featured. 39 * 40 * @param is_gyroscope Ignore parent's rotation and scale? 41 */ 42export function spatial_node2d(is_gyroscope = false) { 43 return (game: Game, entity: Entity) => { 44 game.World.Signature[entity] |= Has.SpatialNode2D | Has.Dirty; 45 game.World.SpatialNode2D[entity] = { 46 World: game.World.InstanceData.subarray( 47 entity * FLOATS_PER_INSTANCE, 48 entity * FLOATS_PER_INSTANCE + 6, 49 ), 50 Self: mat2d_create(), 51 IsGyroscope: is_gyroscope, 52 }; 53 }; 54} 55 56/** 57 * Yield ascendants matching a component mask. Start at the current entity. 58 * 59 * @param world World object which stores the component data. 60 * @param entity The first entity to test. 61 * @param mask Component mask to look for. 62 */ 63export function* query_up(world: World, entity: Entity, mask: Has): IterableIterator<Entity> { 64 if ((world.Signature[entity] & mask) === mask) { 65 yield entity; 66 } 67 68 let parent = world.SpatialNode2D[entity].Parent; 69 if (parent !== undefined) { 70 yield* query_up(world, parent, mask); 71 } 72}