--########################################################

-- THIS SCRIPT WAS WRITTEN BY BEN BOWES FEB 2004         #

-- I FOUND A VERY FAST WAY OF CODING COLLISIONS IN A 3D  #

-- WORLD USING 2D CODE. USE IT HOWEVER YOU WISH          #

--########################################################

--

--       INSTRUCTIONS (a total of 4 steps)

--

--########################################################

-- (1 / 4) On file menu -> Insert/Media Element/Shockwave 3D.

--         name it "w" and place it on the stage

--

-- (2 / 4) COPY AND PASTE THIS AND PUT IT INTO A

--        "BEHAVIOR SCRIPT" then drag it onto the timeline                       

--########################################################

 

global oData

on exitFrame me

  go the frame

end

on beginsprite me

  -- This data is an example data list which would usually be exported from my level editor

  tRoomData =\

[#faces:[[1,1,1,1,0,0],[1,0,0,1,0,0],[1,1,0,1,0,0],[1,1,1,1,1,1],[1,1,0,0,0,1],[1,1,1,1,1,1]],#tiles:[[1,1],[1,2],[1,3],[1,4],[1,5],[1,6],[2,1],[2,2],[2,3],[2,4],[2,5],[2,6],[3,1],[3,2],[3,3],[3,4],[3,5],[3,6],[4,1],[4,2],[4,3],[4,4],[4,5],[4,6],[5,1],[5,2],[5,3],[5,4],[5,5],[5,6],[6,1],[6,2],[6,3],[6,4],[6,5],[6,6]], #BotCount:90]

  -- init *ROOT* script

  oData = script("data container").new(tRoomData)

end

 

on endsprite me

  the actorlist = []

  the timeoutlist = []

  clearglobals

end

 

 

-- ##########################################################

-- Instructions: (3 / 4)

-- COPY AND PASTE THIS SCRIPT INTO A PARENT SCRIPT AND NAME

-- IT "data container" (NB: use exact spelling)            

-- ##########################################################

property pBotName

 

on new me, tRoomData -- room + height data

 

  pBotName = 0 -- unique name generator

  -- get simple collision areas eg: 1 = has a face, 0 = no face

  tAreaFaces = tRoomData[#faces]

  -- add all tiles initually

  tTileCheckList = tRoomData[#tiles]

  -- how many bots

  tBotCount = tRoomData[#BotCount]

 

  --setup world

 

  w = member("w")

  w.resetworld()

  w.camera[1].colorBuffer.clearValue = rgb( 192, 192, 192 )

  w.camera[1].transform.position= vector( 60.1042, 3.40958e3, 4.95288e3 )

  w.camera[1].transform.rotation= vector( -46.5000, -25.0000, 0.0000 )

 

  -- CREATE UNIVERSAL WORLD COMPONENTS

 

  tTileRes = w.newmodelresource("tileres", #plane)

  tTileRes.length = 500

  tTileRes.width = 500

  tProbeRes = w.newmodelresource("probe", #box)

  tProbeRes.length = 20

  tProbeRes.width = 20

  tProbeRes.height = 20

  tAvatarRes = w.newmodelresource("avatar", #box)

  tAvatarRes.length = 50

  tAvatarRes.width = 50

  tAvatarRes.height = 120

  w.shader[1].texture = void -- Default texture

  w.shader[1].renderstyle = #wire -- Default texture

  tProbeShad = w.newshader("probe", #standard)

  tProbeShad.texture = void

  tProbeShad.diffuse = rgb(0,200,0)

 

  -- Build bot instances

 

  repeat with i = 1 to tBotCount

    pBotName = pBotName + 1

    pName = symbol("Bot"&pBotName) -- create unique bot prop-name

    -- birth Bot object

    add the actorlist,script("bot").new(tAreaFaces,tTileCheckList, w, pName, tTileRes)

  end repeat

  return me

 

end

 

 

 

-- ##########################################################

-- Instructions: (4 / 4)

-- COPY AND PASTE THIS SCRIPT INTO A PARENT SCRIPT AND NAME

-- IT "bot" (NB: use exact spelling)           

-- ##########################################################

 

property pProbe --probe model

property pProbePos -- probe models position

property pArea -- the rect() check list

property w -- sw3d member reference

property pAvatar -- avatar model, probes parent

property pTS -- size of the areas or tiles

property pTileRes -- universal res for making tiles

property pTileModelList -- this instances current check area

property pAreaFaces -- face list or walkable list

property pTileCheckList -- the areas to make into tiles and areas

property pRot -- rotation value either + or -

property pCounter -- used by toggleRot(me)

property pBotName -- unique name

property pVectArea -- 3d equivelent

property pSpeed

-----------------------------------------------------------------

--       INIT INSTANCES AND ASSIGN VALUES

-----------------------------------------------------------------

 

on new me, tAreaFaces, tTileCheckList, tWorld, tBotName, tTileRes

  pSpeed = random(10, 30)

  pTileRes = tTileRes

  pBotName = string(tBotName)

  w = tWorld -- 3d member

  pAreaFaces = tAreaFaces -- the walkable tiles

  pTileCheckList = tTileCheckList -- amount of tiles this fellow checks

  pTileModelList = [] -- visually displays the pArea (rect() areas)

  pVectArea = []

  pArea = [] -- list of rect() areas to check

  pTS = 500 -- width of areas

  me.initworld() -- create initual dummy scene so avatar can check modelsUnderRay()

  pProbe = w.model("probe"&pBotName)

  pAvatar = w.model("avatar"&pBotName)

  pCounter = 150 -- used by toggleRot(me)

  me.setTiles(pTileCheckList) -- make initual tiles (pTileCheckList initial value is all #faces)

  -- check tile below, dont need to check that often 

  timeout("checkTiles"&pBotName).new(1000,#checkTiles,me)

  -- check for collisions...often

  timeout("checkCollisions"&pBotName).new(42, #checkCollisions, me)

  return me

end

 

on initworld me -- make avatar and probe models

  -- create an avatar

  res = w.modelresource("avatar")

  avatar = w.newmodel("avatar"&pBotName, res)

  -- create an area probe

  pres = w.modelresource("probe")

  probe = w.newmodel("probe"&pBotName, pres)

  probe.shaderlist = w.shader[2]

  probe.transform.position = avatar.transform.position

  -- make it a child of the avatar

  avatar.addchild(probe)

  -- then translate the avatar and probe

  rX = random(51,449)

  rZ = random(50,2500)

  avatar.translate(rX,res.height/2,rZ)

  probe.translate(0,0,100) -- forward z 100

end

 

------------------------------------------------------------------------

--   DISPLAY TILE AREAS AND SET RECT() AREAS. every 1000 ms

------------------------------------------------------------------------

on checkTiles me

  -- clear list before we add items via finding the nearest tiles

  pTileCheckList = []

  -- send a ray down,  returns the current tile position of the avatar

  tCurrentTile = me.getCurrentPos()

  if tCurrentTile <> void then 

    -- look at the tiles around the current

    repeat with tValue = 1 to 8

      t = me.findoffset(tCurrentTile, tValue)

      -- if it is within the bounds of the current 6 tile square area

      if t[1] > 0 and t[1] < 7 then 

        if t[2] > 0 and t[2] < 7 then

          -- and it has a face we need to check then

          if pAreaFaces[t[1]] [t[2]] = 1 then

            -- add it to the list of models we want to create

            add pTileCheckList, t

          end if

        end if

      end if

    end repeat

    -- current tile is not included in the offset so add it aswell

    add pTileCheckList, tCurrentTile

    -- send all the models we want to make to the oWorld object

    me.setTiles(pTileCheckList)

  end if

end

 

 

 

on setTiles me, tL --tL = pTileCheckList list positions eg [[1,1],[1,2],etc]

  me.deleteTileList() -- remove current display and rect() areas

  repeat with i = 1 to tL.count

    tLeft = (tL[i][2]-1)*pTS -- tile coords = list value[1 or 2] - 1

    tTop = (tL[i][1]-1)*pTS  -- eg (3 - 1) * 500

    tVTS = pTS/2   

    --*************************************************************

    --  pVectArea,[vector(tSize), vector(tCenter             )]

    --  add pVectArea,[vector(tVTS,0,tVTS), vector(tLeft+tVTS,0,tTop+tVTS)]

    add pArea, rect(tLeft, tTop, tL[i][2]*pTS, tL[i][1]*pTS)

    --*************************************************************

    -- set up Tiles

    me.initTiles(tLeft, tTop, string(tL[i]))  

  end repeat

end

 

on initTiles me, tLeft, tTop, tName-- create models to desribe the rect() aabb area

  -- has it already been made by another instance ?

  if w.model(string(tName)) = void then

    -- else make it

    m = w.newmodel(string(tName), pTileRes)

    m.translate(tLeft + (pTS / 2) , 0 ,tTop + (pTS / 2))

    m.rotate(90,0,0)

    -- add the name of model to the tile list

    add pTileModelList,tName

  end if

end

 

on deleteTileList me

  -- clear all *current* tile models and references to them

  repeat with a = 1 to pTileModelList.count

    w.deletemodel(string(pTileModelList[a]))

    pTileModelList.deleteone(pTileModelList[a])

  end repeat

  --*****************************************************************

  --  pVectArea = []-- clear all *vector()* areas to check

  pArea = [] -- clear all *rect()* areas to check

  --*****************************************************************

end

 

on getCurrentPos me -- shoot a simple ray to find tiles model name below

  tRayDir = -(pAvatar.getworldtransform().Yaxis)

  tRayDir.normalize()

  tModPos = pAvatar.getworldtransform().position

  hit = w.modelsunderray(tModPos, tRayDir, 1, #simple)

  if hit <> [] then return value(hit[1].name) -- return model name

end

 

 

 

on findoffset me, tCTile, tValue

  -- return list positions (+ or - 1) in all directions at an offset of 1

  case (tValue) of

    1:return[tCTile[1]-1,tCTile[2]-1]

    2:return[tCTile[1]  ,tCTile[2]-1]

    3:return[tCTile[1]+1,tCTile[2]-1]

    4:return[tCTile[1]-1,tCTile[2]  ]

    5:return[tCTile[1]+1,tCTile[2]  ]

    6:return[tCTile[1]-1,tCTile[2]+1]

    7:return[tCTile[1]  ,tCTile[2]+1]

    8:return[tCTile[1]+1,tCTile[2]+1]

  end case

end

-------------------------------------------------------------------

--   CHECK FOR COLLISIONS AND RESOLVE THEM USING 2D RECT() CODE

-------------------------------------------------------------------

 

on checkCollisions me

  pCounter = pCounter + 1 -- used by togglerot(me)

  pProbePos = pProbe.worldposition -- grab current position of the probe

  -- reset both to false before check

  tTranslate = false

  tRotate = false

 

  -- report rect() collision and translate if posible or rotate instead

  repeat with i = 1 to pArea.count

    if testCollisions (me, pProbePos, pArea[i]) = true then

      tTranslate = true

      -- decide random left or right if counter > value...

      me.togglepRot()

      tRotate = false

      exit repeat

    else

      tRotate = true

    end if

  end repeat

  -- do whatever based on true of false above

  if tRotate then pAvatar.rotate(0,pRot,0)

  if tTranslate then pAvatar.translate(0,0,pSpeed)

end

 

-- THE RECT() HACK COLLISION CHECKER

on testCollisions me, tVector, tArea

  p = point(tVector[1],tVector[3])

  return inside(p, tArea)

end

 

--   A 2D VECTOR() EQUIVILENT

--on insideAABB (me, tVector, tSize, tCenter)

--  tDelta = tVector - tCenter

--  if (tSize.x - abs(tDelta.x)) < 0 then return (FALSE)

--  if (tSize.z - abs(tDelta.z)) < 0 then return (FALSE)

--  return (TRUE)

--end

 

on togglepRot me

  if pCounter > 70 then

    case(random(2))of

      1:pRot = 7

      2:Rot = -7

    end case

    pCounter = 0

  end if

end