1 (edited by Conard 2007-04-11 10:05:18)

Topic: Terrain collisions

I'm trying to have a model walk over a terrain, but I ran into a problem, the player seems to get stuck on very little slopes of the terrain.
In the Irrlicht forums there were some people with the same problem, but I still couldn't get it fixed.

Here is a simple example I threw together:

SuperStrict
Framework BRL.Blitz
Import BRL.StandardIO
Import Irrlicht.Core

' player cube
Global player:ISceneNode

' for handling user input
Type MyEventReceiver Extends IEventReceiver

    Field Terrain:ISceneNode

    Method setTerrain(terr:ISceneNode)
        Terrain=terr
    EndMethod

    Method OnEvent:Int(event:SEvent)

        ' check If user presses the key 'W' or 'D'
        If event.getEventType()=EET_KEY_INPUT_EVENT
        
            Local key:Int=event.getKeyInputKey()
            
            Select key
                ' move forward
                Case EKEY_KEY_W  
                    Local p:vector3df=player.getPosition()
                    Local v:vector3df=_VECTOR3DF(p.getX(),p.getY(),p.getZ()+20)
                    player.setPosition(v)
                    Return True    
                ' move backward    
                Case EKEY_KEY_S
                    Local p:vector3df=player.getPosition()
                    Local v:vector3df=_VECTOR3DF(p.getX(),p.getY()-0.2,p.getZ()-20)
                    player.setPosition(v)
                    Return True                
            EndSelect            
        EndIf
        
        Return False
    EndMethod

    Function generate:IEventReceiver()
        Return New MyEventReceiver
    EndFunction
EndType

Local device:IrrlichtDevice=IrrlichtDevice.create(EDT_OPENGL , _DIMENSION2DI(800,600))
If device.handle=0 Then Return 

Local driver:IVideoDriver=device.getVideoDriver()
Local smgr:ISceneManager=device.getSceneManager()
Local env:IGUIEnvironment=device.getGUIEnvironment()

Local camera:ICameraSceneNode=smgr.addCameraSceneNodeFPS(Null,100.0,1200.0)
camera.setPosition(_VECTOR3DF(1900*2,255*2,3700*2))

Local terrain:ITerrainSceneNode=smgr.addTerrainSceneNodeFromFile("terrain-heightmap.bmp")
terrain.SetScale(_VECTOR3DF(40, 4.4, 40))
terrain.setMaterialFlag(EMF_LIGHTING, False)
terrain.setMaterialTexture(0, driver.getTexture("terrain-texture.jpg"))

Local selector:ITriangleSelector=smgr.createTerrainTriangleSelector(terrain, 0)
terrain.setTriangleSelector(selector)
selector.drop()

player=smgr.addCubeSceneNode()
player.setPosition(_VECTOR3DF(1900*2,255*2,3700*2))
player.setScale(_VECTOR3DF(4.0,8.0,4.0))

Local anim:ISceneNodeAnimator=smgr.createCollisionResponseAnimator( ..
    selector, player, _VECTOR3DF(18,36,18), _VECTOR3DF(0,-.1,0), _VECTOR3DF(0,10,0))
player.addAnimator(anim)

Local receiver:IEventReceiver=IEventReceiver.create(MyEventReceiver.generate)
device.setEventReceiver(receiver)

While (device.run())
    
    'start drawing everything
    driver.beginScene(True,True,_SCOLOR(255,30,80,200))
    
    smgr.drawAll()
    env.drawAll()
    
    driver.endScene()
    
Wend

device.drop()

It uses a heightmap 'terrain-heightmap.bmp' and a texture 'terrain-texture.jpg' wich are located in the Irrlicht media folder. (don't mind the lack of commands, I threw this together rather quickly tongue)

Does anyone know how I can fix this?

Thanks in advantage.

Re: Terrain collisions

greetings smile  my box is stuttering simply due to the key input, but i dont seem to get stuck at all with the above code.  i know of the reports you have seen on the irrlicht forums though.  are you using the windows or mac version?

Re: Terrain collisions

I am using the mac version.
Normally I would use your SmoothEventReceiver, but at the time I wrote that code the addons waren't updated yet, using the SmoothEvenReceiver makes you walk smooth as supposed smile.
Also, you will only get stuck on small slopes, so you really have to walk forward a fair bit 'till you notice it (yea I could have better edited the player position).

Re: Terrain collisions

i will check it out tonight when i try out the mac version.   did you need the .nib file and if so, where did you place it?

5 (edited by Conard 2007-04-11 16:25:53)

Re: Terrain collisions

Re: Terrain collisions

i have now replicated the problem on all 3 OS.  i know its not a mod issue so im not sure how well im going to be able to help.  i will try though.

on a side note, are you running PPC processor?  did you have to ranlib the libIrrlichtMac.a?

Re: Terrain collisions

Re: Terrain collisions

Ok, but note that this is not something that came with the 1.3 update, it was there before. I might be able to fix it using a physics engine for collisions, but I don't really feel like implenting Newton just for collisions with terrain.

Re: Terrain collisions

ah thx Conard.  i was looking for differences between v1.2 and v1.3.  did you post the Q at the irrlicht forums?  if not, i see someone else just reported the exact same issue.

Re: Terrain collisions

11 (edited by Conard 2007-04-14 12:51:50)

Re: Terrain collisions

It turns out that the Irrlicht collision system just isn't advanced enough to do this. If you want terrain collision detection, you will need to write your own functions. Here is the code I use:

Global gravity = 0.1
Global groundoffset:vector3df = _VECTOR3DF(0, 0, 0)

 Function getHeight:Float(dev1:IrrlichtDevice , ground:ITriangleSelector , pos:vector3df , maxHeight:Float)
    Local colMan:ISceneCollisionManager = dev1.getSceneManager().getSceneCollisionManager()
    Local yAxis:vector3df = (_VECTOR3DF(0 , maxHeight , 0))
    Local tmppos:vector3df = (_VECTOR3DF(pos.getX() , pos.getY() - yAxis.getY() , pos.getZ()))
    Local ray:line3df = Line3df.createFromVects(pos , tmppos)
    Local ptoCol:vector3df = (_VECTOR3DF(0, 0, 0))
    Local triangle:triangle3df = triangle3df.create()
    
    If(colMan.getCollisionPoint(ray , ground , ptoCol , triangle)    )
        Return ptoCol.getY()
    Else
        Return maxHeight
    EndIf
EndFunction


Function ApplyGravity(msecs)
 Local pos1:vector3df
 pos1 = myMesh.getPosition()
 pos1.setY(pos1.getY() + 100000)
 Local momentum

 Local THeight:Float = getHeight(myDevice, myFloor, pos1, 110000)
 Local XHeight:Float = getHeight(myDevice, myFloor, _VECTOR3DF(pos1.getX()-1, pos1.getY(), pos1.getZ()), 110000)
 Local ZHeight:Float = getHeight(myDevice, myFloor, _VECTOR3DF(pos1.getX(), pos1.getY(), pos1.getZ()-1), 110000)
 pos1.setY(pos1.getY() - 100000)
 momentum = momentum + gravity * msec / 1000.0

 If(pos1.getY() < (THeight + groundOffset.getY()))
  pos1.setY(THeight + GroundOffset.getY())
  momentum = 0
  ' this should prevent climbing steep slopes
  If(THeight < XHeight-1) pos1.setX(pos1.getX() + walkSpeed/10.0)
  If(THeight > XHeight+1) pos1.setX(pos1.getX() - walkSpeed/10.0)
  If(THeight < ZHeight-1) pos1.setZ(pos1.getZ() + walkSpeed/10.0)
  If(THeight > ZHeight+1) pos1.setZ(pos1.getZ() - walkSpeed/10.0)
 EndIf

 myMesh.setPosition(pos1)
 myMesh.updateAbsolutePosition()
EndFunction

ps. this is some code I found on the Irrlicht forums that I converted.

Re: Terrain collisions

thanks Conard!  it would be neat to wrap this up into a new collisionresponseanimator specifically for terrain colliding.