UNPKG

hytopia

Version:

The HYTOPIA SDK makes it easy for developers to create massively multiplayer games using JavaScript or TypeScript.

115 lines (98 loc) 5.11 kB
import { startServer, Entity, PathfindingEntityController, PlayerEntity, PlayerEvent, Quaternion, RigidBodyType, ColliderShape, } from 'hytopia'; import worldMap from './assets/map.json'; startServer(world => { world.loadMap(worldMap); // Spawn our zombie that will pathfind around the map const zombie = new Entity({ controller: new PathfindingEntityController(), name: 'Zombie', modelUri: 'models/npcs/zombie.gltf', modelLoopedAnimations: [ 'walk' ], modelScale: 0.5, rigidBodyOptions: { enabledRotations: { x: false, y: true, z: false }, ccdEnabled: true, }, }); // Spawn somewhere in front of the player zombie.spawn(world, { x: 4, y: 3, z: -6 }, Quaternion.fromEuler(0, 180, 0)); // rotate 180 degrees around Y, facing the player spawn point. // Enter /pathfind to make the zombie pathfind to the player let pathfindMarkers: Entity[] = []; world.chatManager.registerCommand('/pathfind', (player, args) => { // Get the entity of the palyer that entered the command const playerEntities = world.entityManager.getPlayerEntitiesByPlayer(player); const playerEntity = playerEntities[0]; const playerPosition = playerEntity.position; // Remove all existing pathfind markers, which we use in the example just to visualize the path taken. pathfindMarkers.forEach(marker => marker.despawn()); pathfindMarkers = []; // Pathfind the zombie to the player const pathfindingController = zombie.controller as PathfindingEntityController; // .pathfind() is synchronous and returns immediately soon as a path is found or not, but before the entity has reached the target. const succeeded = pathfindingController.pathfind(playerPosition, 3, { // all possible options for example debug: true, // Setting true will console log pathfinding result info maxFall: 5, // The maximum fall distance (in blocks) the entity can fall when considering a path. maxJump: 2, // The maximum height (in blocks) the entity will jump when considering a path, the controller will apply the jumps automatically while pathfinding. maxOpenSetIterations: 400, // A performance optimization value. A lower value will make pathfinding faster but may fail for longer paths, a higher value can make pathfinding take longer but will work better for longer paths. verticalPenalty: -1, // A behavior control. The more negative the value, the more the entity will prefer taking a route that requires jumping and falling, even going out of its way to do so. A more positive value will prefer avoiding jumps and falls unless absolutely necessary. pathfindAbortCallback: () => { // Invoked when maxOpenSetIterations is reached and pathfinding aborts. console.log('Pathfinding aborted'); }, pathfindCompleteCallback: () => { // Invoked when the entity associated with the PathfindingEntityController finishes pathfinding and is now at the target coordinate. console.log('Pathfinding complete'); }, waypointMoveCompleteCallback: () => { // Invoked when the entity associated with the PathfindingEntityController finishes moving to a calculate waypoint of its current path. console.log('Waypoint reached'); }, waypointMoveSkippedCallback: () => { // Invoked when the entity associated with the PathfindingEntityController skips a waypoint because it exceeded the waypointTimeoutMs. console.log('Waypoint skipped'); }, waypointTimeoutMs: 2000, // The timeout in milliseconds for a waypoint to be considered reached. Defaults to 2000ms divided by the speed of the entity. }); // .pathfind() will return true if the algorithm found a path and began traversing it. console.log(`Path found successfully?: ${succeeded}`); // Spawn visual markers for the path pathfindingController.waypoints.forEach(waypoint => { const pathfindMarker = new Entity({ modelUri: 'models/items/cookie.gltf', rigidBodyOptions: { type: RigidBodyType.FIXED, colliders: [ { shape: ColliderShape.BLOCK, halfExtents: { x: 0.5, y: 0.5, z: 0.5 }, isSensor: true, }, ], }, }); pathfindMarker.spawn(world, waypoint); pathfindMarkers.push(pathfindMarker); }); }); // Spawn a player entity when a player joins the game. world.on(PlayerEvent.JOINED_WORLD, ({ player }) => { const playerEntity = new PlayerEntity({ player, name: 'Player', modelUri: 'models/players/player.gltf', modelLoopedAnimations: [ 'idle' ], modelScale: 0.5, }); world.chatManager.sendPlayerMessage(player, 'To make the zombie pathfind to you, enter: /pathfind', '00FF00'); playerEntity.spawn(world, { x: 4, y: 3, z: 1 }); }); // Despawn all player entities when a player leaves the game. world.on(PlayerEvent.LEFT_WORLD, ({ player }) => { world.entityManager.getPlayerEntitiesByPlayer(player).forEach(entity => entity.despawn()); }); });