GE Lua Documentation

Press F to search!

findSpawnPoint

Definition


-- @/lua/ge/extensions/gameplay/traffic/trafficUtils.lua:462

local function findSpawnPointOnRoute(startPos, startDir, minDist, maxDist, targetDist, options) -- returns a spawn point, from a route that starts at the origin
  -- all args are optional, will use camera transform by default
  options = options or {}
  startPos, startDir, minDist, maxDist, targetDist = getDefaultValues(startPos, startDir, minDist, maxDist, targetDist)

  local spawnData = {pos = vec3(), dir = vec3()}
  local valid = false
  local mapNodes = map.getMap().nodes
  local currDist = minDist

  options.gap = options.gap or 20
  options.usePrivateRoads = options.usePrivateRoads and true or false
  options.minDrivability = options.minDrivability or M.defaults.drivability
  options.minRadius = options.minRadius or M.defaults.halfWidth
  options.pathRandomization = options.pathRandomization or 0.5

  if M.debugMode then
    log('I', logTag, string.format('Spawn search params: minDist = %d, maxDist = %d, targetDist = %d', minDist, maxDist, targetDist))
  end

  route:clear()
  route.dirMult = 1

  --[[
  ---- ROUTE SEARCH ----
  A path will be generated along the road ahead, and points between the minimum distance and maximum distance will be tested and validated.
  ]]--

  local n1, n2 = map.findClosestRoad(startPos)
  if n1 then
    p1:set(mapNodes[n1].pos)
    p2:set(mapNodes[n2].pos)
    tempDir:setSub2(p2, p1)
    if tempDir:dot(startDir) < 0 then -- if true, swap the nodes
      n1, n2 = n2, n1
      p1:set(mapNodes[n1].pos)
      p2:set(mapNodes[n2].pos)
    end

    if options.route then
      -- perhaps this should exist outside of the initial if statement?
      route:setupPathMultiWaypoints(options.route)
    else
      -- spawn point is along path in direction set by startDir, with possible branching
      local path = map.getGraphpath():getRandomPathG(n1, startDir, maxDist, options.pathRandomization, 1, false)
      --route:setupPathMultiWaypoints(path)
      for _, wp in ipairs(path) do
        table.insert(route.path, {pos = map.getMap().nodes[wp].pos, wp = wp, linkCount = map.getNodeLinkCount(wp)}) -- optimized route path creation
      end
      route:calcDistance()
    end

    if M.debugMode then
      if route.path[1] then
        log('I', logTag, string.format('Spawn search route length: %0.2f', route.path[1].distToTarget))
      else
        log('W', logTag, 'Failed to generate valid route')
      end
    end

    local firstDist = minDist
    if route.path[1] and route.path[2] then
      local xnorm = clamp(startPos:xnormOnLine(route.path[1].pos, route.path[2].pos), 0, 1)
      firstDist = firstDist + (route.path[1].distToTarget - route.path[2].distToTarget) * xnorm
    end

    local road = route:stepAhead(firstDist, true) or {} -- if nil, uses previous values as safety
    n1 = road.n1 or n1
    n2 = road.n2 or n2
    spawnData.pos:set(road.pos or firstPos)
    spawnData.dir:set((mapNodes[n2].pos - mapNodes[n1].pos):normalized())
  else
    return spawnData, valid
  end

  repeat
    if checkRoad(n1, n2, options) then
      p1:set(mapNodes[n1].pos)
      p2:set(mapNodes[n2].pos)

      if currDist >= targetDist or checkRayCast(spawnData.pos, startPos) then
        if checkSpawnPoint(spawnData.pos, nil, minDist) then
          spawnData.n1, spawnData.n2 = n1, n2
          valid = true

          if M.debugMode then
            log('I', logTag, string.format('Spawn point found at distance: %d', math.floor(spawnData.pos:distance(startPos))))
          end
        end
      end
    end

    if not valid then
      local gap = options.gap
      if options.safeGap then -- uses speed limit to determine gap
        local link = mapNodes[n1].links[n2] or mapNodes[n2].links[n1]
        if link and link.speedLimit then
          gap = clamp(link.speedLimit * 1.08, 20, 50)
        end
      end
      local road = route:stepAhead(gap) or {}
      if road then
        n1 = road.n1 or n1
        n2 = road.n2 or n2
        spawnData.pos:set(road.pos)
        spawnData.dir:set((mapNodes[n2].pos - mapNodes[n1].pos):normalized())
      end
    end

    currDist = currDist + options.gap
  until (valid or currDist > maxDist)

  if not valid and M.debugMode then
    log('W', logTag, 'Failed to validate spawn point (route method)')
  end

  return spawnData, valid
end

Callers