COLLISION AGAINST THE TERRAIN

The secret tool to define collision of the avatar against anything is the method modelsUnderRay of the Director API. Its declaration is:

alist = myworld.modelsUnderRay(locationVector , directionVector  , 5, #detailed)

The method returns a array of arrays. Each line of the main array has details of the objects found under a ray drawn from the position specified by locationVector and pointing in the direction of directionVector. The max number of objects/models to be found is 5 in our declaration but can be changed.

For each object found we have a array with properties that can be called by name:


      alist[i].name  -         the name of the object found 
      alist[i].distance -      the distance from the  position 
                               of the avatar to the point of 
                               intersection with the object.
      alist[i].isectposition - is a vector representing the  
                               position of the  intersection.
      alist[i].isectNormal -   is the  normal vector to the mesh 
                               at the point of intersection.

Do you remember what is a normal to a surface? OK. Congratulations. Good hight school :-)

The idea is to create a method seekfloor that has the parameters:

This method returns an array with 3 elements:

This "return" is received at each loop and we need to translate and rotate the avatar.

Play the demo. All the codes are after the demo. Walking, look back to see that you are on the floor, going up or down.

OK.Play the demo (remember: the code is in this page, after the demo)


THE CODE:

The setupscript is the same.

In the avatarobj script we have the new method:

 
property fwvect
property upvect  

property distanceforward 
property steer  
property ang, xvect,avatarheight  
global myworld 

on new me
   
  upvect = vector(0, 1,0)
  fwvect = vector(0,0,1)
  xvect = vector(1,0,0)
  distanceforward = 0
  steer = 0
  myworld.model("avatar").visibility = #none
  myworld.model("avatar").translate(vector(0,0,0),#world) -- put it at a height above the ground
  
  --for collision versus terrain
  xvect = vector(1,0,0)
  ang = 0 
  avatarheight = 15
  --
  
  return me
  
end


on control me
  if keypressed(126) then   
    acc = 0.025
  else
    acc = 0
   end if 
  
  if keypressed(123) then   
    turn = 2
    
  else
    if keypressed(124) then   
      turn = -2
      
    else
      turn = 0
    end if
  end if 
  
  distanceforward = distanceforward + acc - 0.015
  
  if distanceforward < 0 then distanceforward = 0 
  if keypressed(125) then  distanceforward = - 0.8 
  if distanceforward > 0.8 then distanceforward = 0.8
  
  steer = (steer + turn)*0.8
  if steer < -5.0 then steer = -5.0
  if steer > 5.0 then steer = 5.0  
  
  myworld.model("avatar").transform.rotate(myworld.model("avatar").worldposition, upvect, steer)
  
  rotator = transform()
  rotator.rotate(vector(0,0,0), upvect, steer) 
  fwvect = rotator*fwvect
  movement = ( fwvect*distanceforward )
  myworld.model("avatar").translate(movement ,#world)
  
  --for collision versus  terrain
   
  floordetails = seekfloor("avatar", "land", "world", avatarheight, upvect) 
  
  ang = 0
  
  if floordetails[1] = 0 then
   myworld.model("avatar").translate(-movement ,#world)
  else
    if floordetails[2] <> 0 then
      xvect = floordetails[2]
      ang = floordetails[3] 
    end if
  end if  
  myworld.model("avatar").transform.rotate(myworld.model("avatar").worldposition, xvect, ang)
  
end

on seekfloor modelname, floorname, worldname, modelheight, directionvector
   
  flag = 0
  tiltangle = 0
  tiltvector = 0
  
  alist = myworld.modelsUnderRay(myworld.model(modelname).worldposition - directionvector*100  ,directionvector,5, #detailed)  
  
  repeat with i = 1 to count(alist)
    if alist[i].model.name contains floorname  then
       
      a = alist[i].isectposition
      
      av = vector(0,(-myworld.model(modelname).worldposition.y + alist[i].isectposition.y +modelheight ), 0)
      myworld.model(modelname).translate(av, #world)
       
      ay = -directionvector
      
      tiltangle = -ay.anglebetween(alist[i].isectnormal)
      tiltvector = alist[i].isectnormal.perpendicularto(ay)
      flag = 1
      
      exit repeat     
    end if
  end repeat
  
  return [flag, tiltvector, tiltangle]  
end

The cameraobj script and all the other are the same of the previous lesson.




PREVIOUS LESSON NEXT LESSON
T. CONTENTS HOMEPAGE