Sample Code

check out my article on Herding AI: http://www.roguebasin.com/index.php/Denizen_Herding_Behavior
---------------sample code:
Here is the code for propogating sounds throughout the gameworld:
Intensity is a variable usally from 1-50
activator is an "object" - whoever is making the sound in the game world.
x,y, and z i s where the sound starts from.

The code works by taking "steps outward" from the center of the sound and making an entry in the "soundscape" with relevant information about the intensity of the sound and who made the sound.

Currently, it also checks the soundactivate function of whatever object it "hits" so a ghoul can "wake up" and start pathfinding towards the object that made the noise.

In the future, this code will also check for any "sound blocking" objects that stop the propogation of the sound to surrounding squares, like walls.

function funcs.makesound(intensity,activator,x,y,z)
-- print("Making a sound .."..intensity.." from "..activator["name"].." X "..x.." Y "..y.." Z "..z)
 local objectloc = data.objectloc
 local working, future = {}, {{x,y,z}}
 local soundscape = data.soundscape
 local finished = {}
 local insert = table.insert
 local tiles = data.tiles
 local checkforedgeofmap = funcs.checkforedgeofmap
 finished[x] = {}
 finished[x][y] = {}
 finished[x][y][z] = 1
  soundscape[x][y][z][activator] = soundscape[x][y][z][activator] or {} --for moveenemytowards
  insert(soundscape[x][y][z][activator],{["strength"] = intensity})
 local counter = intensity
 while(counter <= intensity and counter >= 1) do
 counter = counter - 1
 working,future = future, {}
 local x,y,z
 for k,v in pairs(working) do
  for x = v[1]- 1,v[1] + 1 do
   finished[x] = finished[x] or {}
  for y = v[2] -1,v[2] + 1 do
   finished[x][y] = finished[x][y] or {}
  for z = v[3] - 1,v[3] + 1 do
   if z < data.amountofzlevels and z >= 1 and (not checkforedgeofmap(x,y)) and (not finished[x][y][z]) and (not tiles[x][y][z]["filled"]) and (not tiles[x][y][z]["open"]) then
    finished[x][y][z] = 1
    insert(future,{x,y,z})
    for k2,ob in pairs (objectloc[x][y][z]) do
      if ob["soundactivate"] then
        for k3,v3 in pairs(ob["soundactivate"]) do
           if k3 < counter then v3(ob,activator) end
        end
      end
    end
    soundscape[x][y][z][activator] = soundscape[x][y][z][activator] or {} --for moveenemytowards
    insert(soundscape[x][y][z][activator],{["strength"] = counter})

-------------------------------------------------------------------------------------------------------
This code needs some cleaning up, it has a few meaningless variables here and there and I wrote it strenuously and with many revisions.  It works well, though, and the heuristic can be altered easily enough.  When funcs.astarpathfind is called, it returns a table with a chart of what squares are what distance from the destination, so actually, I pathfind backwards, from the destination to the creature who's moving, who just has to move onto the next square with the least distance to get to his destination.

This is my "A-star pathfinding code":

function funcs.checkforblockpassageofpath(x,y,z)
 local tiles = data.tiles
 if not tiles[x] or not tiles[x][y] or not tiles[x][y][z] then return true end
 if tiles[x][y][z]["filled"] or tiles[x][y][z]["open"] then return true end
 return false end

function funcs.astarpathfind(startx,starty,startz,endx,endy,endz,ob)
 if startx == endx and starty == endy and startz == endz then return false end
 local working = {} --node list
-- local closed = {} --node list
 local insert = table.insert
 local min = math.min
 local mapsizex = data.levelsizex
 local mapsizey = data.levelsizey
 local distances = {}
 local future = {}
 local getdistance = funcs.getdistance
 local blocking = funcs.checkforblockpassageofpath
 local impossible = (mapsizex * mapsizey) + 1
 --seed the working table
 distances[startx] = {}
 distances[startx][starty] = {}
 distances[startx][starty][startz] = 0
-- print("Startx "..startx)
-- print("Starty "..starty)
-- print("endx "..endx)
-- print("endy "..endy)
-- print("---------")
 insert(future,{startx,starty,startz,0,funcs.getastarheuristic(ob,startx,starty,startz,endx,endy,endz)})
 while(true) do
  for k,v in pairs(future) do/
   insert(working,v)
  end
  future = {}

 --Now,get the one with the best heuristic.
  local lowestfvalue = impossible --or lowestfvalue (dumb pathfind)
  local savedspot
  local savedk
--  print("Lowest F value "..lowestfvalue)
  for k,v in pairs(working) do --4 is distance, 5 is heuristic
--   print ("WORKING "..working[k][4] + working[k][5])
--   print("LOWEST F "..lowestfvalue)
   if working[k][4] + working[k][5] < lowestfvalue then
    lowestfvalue = working[k][4] + working[k][5]
    savedspot = v
    savedk = k
--    print("New lowest f value "..lowestfvalue)
   end
  end
  working[savedk] = nil
   --iterate over that one
  for x = savedspot[1] - 1,savedspot[1] + 1 do
  for y = savedspot[2] -1,savedspot[2]+1 do
  for z = savedspot[3] -1,savedspot[3] + 1 do
   distances[x] = distances[x] or {}
   distances[x][y] = distances[x][y] or {}
   distances[x][y][z] = distances[x][y][z] or impossible
   local newdistance = min(distances[x][y][z], savedspot[4] + getdistance(x,y,savedspot[1],savedspot[2]))
--   if not closed[savedspot] then
    if not blocking(x,y,z) then
     if newdistance < distances[x][y][z] then -- adds or readds a spot to the array
--     print("Updating X "..x.." Y "..y)
     local myh = funcs.getastarheuristic(ob,x,y,z,endx,endy,endz)
     insert(future, {x,y,z,newdistance,myh})
     distances[x][y][z] = newdistance
     end
    end


    if x == endx and y == endy and z == endz then
     --print("Correct Return")
     return distances
    end
--   end --ends closedcheck
   end--ends for y
   end --ends for x
   end --ends for z
--The following visualizes the pathfind data
-- print("Path X "..savedspot[1].." Y "..savedspot[2])
-- print("DIST "..savedspot[4])
-- print("HEUR "..savedspot[5])
-- slang.gotorc(savedspot[2]+data.mapoffsety,savedspot[1]+data.mapoffsetx)
-- slang.setcolor(math.random(1,15))
-- slang.writechar("*")
-- slang.refresh()
-- funcs.displaymessage(1,1,"Press a key")
-- funcs.getkey()
 end --ends while true
print("shouldnt have gotten to here.")
os.exit()
end


function funcs.getastarheuristic(ob,x,y,z,x2,y2,z2) --was processer heavy possibly.
 local distanceguess= 10 * funcs.manhattandistance(x,y,x2,y2)
 return distanceguess
end

No comments:

Post a Comment