--########################################################
-- 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