A hackable template for creating small and fast browser games.
at main 87 lines 3.2 kB view raw
1import {mat4_get_translation} from "../../lib/mat4.js"; 2import {Vec3} from "../../lib/math.js"; 3import {path_find} from "../../lib/pathfind.js"; 4import {quat_multiply} from "../../lib/quat.js"; 5import { 6 vec3_add, 7 vec3_distance_squared, 8 vec3_normalize, 9 vec3_transform_position, 10} from "../../lib/vec3.js"; 11import {Entity} from "../../lib/world.js"; 12import {Game} from "../game.js"; 13import {Has} from "../world.js"; 14 15const QUERY = Has.Transform | Has.NavAgent | Has.Move; 16 17export function sys_nav(game: Game, delta: number) { 18 for (let i = 0; i < game.World.Signature.length; i++) { 19 if ((game.World.Signature[i] & QUERY) == QUERY) { 20 update(game, i); 21 } 22 } 23} 24 25function update(game: Game, entity: Entity) { 26 let agent = game.World.NavAgent[entity]; 27 if (agent.Goal !== undefined) { 28 console.time("path_find"); 29 // Search FROM the goal TO the origin, so that the waypoints are ordered 30 // from the one closest to the origin. 31 let path = path_find(agent.NavMesh, agent.Goal.Node, agent.Origin); 32 console.timeEnd("path_find"); 33 34 if (path) { 35 // Discard the first waypoint, which is always the origin node, and 36 // the last waypoint, which is the goal's node. 37 let waypoints = path.slice(1, path.length - 1); 38 agent.Waypoints = waypoints.map((w) => ({ 39 Node: w, 40 Position: agent.NavMesh.Centroids[w], 41 })); 42 // Add the destination's world position as the last waypoint. The 43 // waypoint list has always at least one waypoint, which is 44 // important for cases when the path is empty, i.e. the origin and 45 // the goal were the same node. 46 agent.Waypoints.push(agent.Goal); 47 } 48 agent.Goal = undefined; 49 } 50 51 if (agent.Waypoints) { 52 let transform = game.World.Transform[entity]; 53 let position: Vec3 = [0, 0, 0]; 54 mat4_get_translation(position, transform.World); 55 56 let current_waypoint = agent.Waypoints[0]; 57 let distance_to_current_waypoint = vec3_distance_squared( 58 position, 59 current_waypoint.Position, 60 ); 61 if (distance_to_current_waypoint < 1) { 62 let origin = agent.Waypoints.shift(); 63 if (origin !== undefined) { 64 agent.Origin = origin.Node; 65 } 66 if (agent.Waypoints.length === 0) { 67 agent.Waypoints = undefined; 68 } 69 } 70 71 // Transform the waypoint's position into the agent's self space which 72 // is where sys_move runs. 73 vec3_transform_position(position, current_waypoint.Position, transform.Self); 74 vec3_normalize(position, position); 75 76 let move = game.World.Move[entity]; 77 vec3_add(move.Direction, move.Direction, position); 78 79 if (position[0] < 0) { 80 // The target is on the right. 81 quat_multiply(transform.Rotation, move.LocalRotation, [0, -1, 0, 0]); 82 } else { 83 // The target is on the left or directly behind. 84 quat_multiply(transform.Rotation, move.LocalRotation, [0, 1, 0, 0]); 85 } 86 } 87}