ScriptENGINE provides waypoint navigating functions using the
A* algorithm to determine an optimal path between
two waypoints based upon the 'cost' of each waypoint connection.
The navigator algorithm will try to find a path that minimses the cost.
The waypoints connection costs are numbers.
--------------------------- --------------------------- -- Waypoints example -- Copyright (c) 2007-09 Capricorn 76 Pty. Ltd. -- -- Waypoints can be used for navigation, -- camera tracking, or as place holders in your world. -- -- ScriptENGINE provides waypoint navigating functions using the -- A* algorithm to determine an optimal path between -- two waypoints based upon the 'cost' of each waypoint connection. -- -- The navigator algorithm will try to find a path that minimses the cost. -- The waypoints connection costs are numbers. -- -- Assign costs to your waypoint connections according to -- how difficult you expect the navigation between the two -- waypoints should be. -- -- NOTE: -- The ./Demos/runDemo.e76script is a utility script used to run all the examples. -- It loads the world, calls the OnWorldLoad(), OnWorldUnload() functions, and runs the graphics engine loop, waiting for the user to press escape. --------------------------- --------------------------- local startingWaypointId = nil; local goalWaypointId = nil; local subMouseButton = nil; local GUI_PATH_ID_START = 2000; -- The waypoint path is highlighted using GUI labels. The label identifiers start from this constant --------------------------- -- PRIVATE FUNCTION -- Add the Waypoint Path Step to the GUI --------------------------- function _addWaypointPathStep(idx, waypointId) ------------------------ -- Create a new text box showing the waypoint path index. -- Place it where the waypoint is. ------------------------ local pos = IGraphics:getScreenPosFrom3DPos(IWorld:getEntityPosition(waypointId), IWorld:getActiveCameraId()); local rect = IMisc:rectCreate(IMisc:pointGetX(pos) - 0.02, IMisc:pointGetY(pos) - 0.02, IMisc:pointGetX(pos) + 0.025, IMisc:pointGetY(pos) + 0.025); local id = GUI_PATH_ID_START + idx; if (IGraphics:createText(id, tostring(idx), rect, true, false, true, '1 0 0 1')) then IGraphics:setStaticTextAlignment(id, GUI_JUSTIFY_CENTER, GUI_JUSTIFY_CENTER); end end ------------------------ -- PRIVATE FUNCTION -- Clean the old waypoint path data ------------------------ local function _clearOldPath() local idx = 1; while (IGraphics:controlExists(GUI_PATH_ID_START + idx)) do IGraphics:removeControl(GUI_PATH_ID_START + idx); idx = idx + 1; end end --------------------------- -- PRIVATE FUNCTION -- Use the A* waypoint processing -- to calculate the optimal path between -- the starting and goal waypoints --------------------------- local function _doAStarProcessing() if (startingWaypointId) then ------------------------ -- Remove the previous text boxes we added to the screen ------------------------ _clearOldPath(); _addWaypointPathStep(1, startingWaypointId); ------------------------ -- If we have a start and end waypoint, then calculate a path ------------------------ if (goalWaypointId) then print('----------------\n' .. 'Calculating A* path between ' .. IWorld:getEntityName(startingWaypointId) .. ' and ' .. IWorld:getEntityName(goalWaypointId) .. '...'); _clearOldPath(); ------------------------ -- Create a navigator. -- This id can be stored in your entity's databag and reused -- instead of recreating it every time. ------------------------ nav = IWorld:createWaypointNavigator(); -- We can add multiple starting waypoints, -- and the navigator will determine the best one to use IWorld:addWaypointNavigatorStart(nav, startingWaypointId); -- Must have one goal waypoint only IWorld:setWaypointNavigatorGoal(nav, goalWaypointId); ------------------------ -- Perform the search ------------------------ if (IWorld:doWaypointNavigatorSearch(nav)) then print( 'PATH FOUND.', 'Total path cost:', IWorld:getWaypointNavigatorSolutionCost(nav), 'Total path steps:', IWorld:getWaypointNavigatorSolutionCount(nav)); -- Iterate over the solution waypoints IWorld:moveWaypointNavigatorSolutionStart(nav); local idx = 1; while (IWorld:isWaypointNavigatorSolutionValid(nav)) do currentWaypointId = IWorld:getWaypointNavigatorSolutionCurrentId(nav); print('Waypoint', idx, ':', IWorld:getEntityName(currentWaypointId)); _addWaypointPathStep(idx, currentWaypointId); idx = idx + 1; IWorld:moveWaypointNavigatorSolutionNext(nav); end else print( 'NO VALID PATH FOUND'); end IWorld:destroyWaypointNavigator(nav); end end end --------------------------- -- runDemo.e76script calls this function when the world is loaded --------------------------- function OnWorldLoad(worldName) --print('OnWorldLoad'); --------------------------- -- Load constants that are used in this example --------------------------- IApp:loadScript(IApp:getExeFilePath() .. './Constants/constantsGuiAlignments.e76script'); --------------------------- -- Load example's GUI --------------------------- OnWorldLoadGui(); --------------------------- -- We want to show the waypoints and connections in run-mode -- so we set their edit-mod property on. --------------------------- IWorld:forEachWaypoint('OnWaypointRunMode'); --------------------------- -- Subscribe to mouse button events --------------------------- subMouseButton = IEvents:subscribeMouseButton('OnMouseButton'); end function OnWaypointRunMode(waypointId) -- Change the editmode property of the waypoint -- and readd it to the scene IWorld:setEntityEditMode(waypointId, true); IWorld:addWaypoint(waypointId); end --------------------------- -- Load GUI specific to this example --------------------------- function OnWorldLoadGui() IGraphics:loadGui('help'); end --------------------------- -- runDemo.e76script calls this function when the world is unloaded --------------------------- function OnWorldUnload(worldName) --print('OnWorldUnload'); --------------------------- -- Unsubscribe to events. -- We will no longer will notified of the events. --------------------------- IEvents:unsubscribe(subMouseButton); end --------------------------- -- Mouse button callback handler --------------------------- function OnMouseButton(eventType, mouseX, mouseY, mouseWheel, userData) --------------------------- -- Left button clicked. Select starting waypoint. --------------------------- if (IMouse:leftButtonClicked(eventType)) then -- Only allow waypoints to be selected by using a filter. startingWaypointId = IGraphics:rayCastMousePositionFilter(IWorld:getWaypointTypeId()); if (startingWaypointId) then print('Starting waypoint selected:', IWorld:getEntityName(startingWaypointId)); _doAStarProcessing(); end return true; -- We handled the event; --------------------------- -- Right button clicked. Select ending waypoint. -- Calculate waypoint path and display it. --------------------------- elseif (IMouse:rightButtonClicked(eventType)) then -- Only allow waypoints to be selected by using a filter. goalWaypointId = IGraphics:rayCastMousePositionFilter(IWorld:getWaypointTypeId()); if (goalWaypointId) then print('Goal waypoint selected:', IWorld:getEntityName(goalWaypointId)); _doAStarProcessing(); end return true; -- We handled the event; end end
Copyright © 2006-23 Sep 2009 Capricorn 76 Pty. Ltd. (created on Wed Sep 23 16:49:12 2009)