Collider doesn't follow model when the movement comes from a component
Closed this issue · 6 comments
This one took me a while to track down:
In the code below, if the model movement comes from a component, the collider ignores it. However, If I move the model in the window's "OnRender" method, it works fine.
After running it, try commenting out the line that adds the component, and uncommenting the two lines in the OnRender method that do the same.
Namespace myapp3d
#Import "<std>"
#Import "<mojo>"
#Import "<mojo3d>"
Using std..
Using mojo..
Using mojo3d..
Class MyWindow Extends Window
Const res := New Vec2i( 1280, 720 )
Const flags:= WindowFlags.Resizable
Const title := "Simple mojo3d app"
Field _scene:Scene
Field _camera:Camera
Field _light:Light
Field _ground:Model
Field _obj:Model
Method New()
Super.New( title ,res.X, res.Y, flags )
End
Method OnCreateWindow() Override
'create (current) scene
_scene=New Scene
_scene.ClearColor = New Color( 0.2, 0.6, 1.0 )
_scene.AmbientLight = _scene.ClearColor * 0.25
_scene.FogColor = _scene.ClearColor
_scene.FogNear = 1.0
_scene.FogFar = 200.0
'create camera
_camera=New Camera( Self )
_camera.AddComponent<FlyBehaviour>()
_camera.Move( 0,2.5,-15 )
_camera.FOV = 35
'create light
_light=New Light
_light.CastsShadow=True
_light.Rotate( 45, 45, 0 )
'create ground
Local groundBox:=New Boxf( -100,-1,-100,100,0,100 )
Local groundMaterial:=New PbrMaterial( Color.Lime )
_ground=Model.CreateBox( groundBox,1,1,1,groundMaterial )
_ground.CastsShadow=False
'create obj and physics components
Local objMaterial:=New PbrMaterial( Color.Red, 0.05, 0.2 )
Local box := New Boxf( -.75, -.75, -0.2, .75, .75, 0.2 )
_obj = Model.CreateBox( box, 1, 1, 1, objMaterial )
_obj.Move( 0,1,0 )
Local body := _obj.AddComponent<RigidBody>()
body.Mass = 0
Local collider := _obj.AddComponent<BoxCollider>()
collider.Box = box
'This is the movement component. The collider doesn't seem to follow the transformation provided by this component
_obj.AddComponent<TestMovement>()
End
Method OnRender( canvas:Canvas ) Override
RequestRender()
_camera.View = Self
'However, if you remove the component and transform the object here, it works fine.
' _obj.LocalRy += 1.0
' _obj.LocalX = Sin(Microsecs()/1000000.0)*5
Local ray := _camera.MousePick()
If ray
_obj.Color = Color.White * 100.0
Else
_obj.Color = Color.Black
End
_scene.Update()
_camera.Render( canvas )
canvas.Color = Color.Black
canvas.DrawText( "Hover mouse over obj to see MousePick work (box glows red)", 10, 10 )
canvas.DrawText( "When the movement is generated by a component, the collider seems to stay at the initial placement.", 10, 30 )
End
Method OnMeasure:Vec2i() Override
Return res
End
End
Function Main()
New AppInstance
New MyWindow
App.Run()
End
Class TestMovement Extends Behaviour
Field intensity := 5.0
Method New( e:Entity )
Super.New( e )
End
Method OnUpdate( elapsed:Float ) Override
Entity.LocalRy += 1.0
Entity.LocalX = Sin(Microsecs()/1000000.0) * intensity
End
End
Cheers.
I think the problem is that you're manually moving it, rather than using the physics engine (ApplyForce, ApplyTorque, etc). You basically can't move a physics object after attaching a collider.
If you need to reposition outside of the physics engine, you have to destroy the rigidbody and re-create it.
EDIT: I believe that's a Bullet limitation, BTW, rather than mx2.
Remembered after posting this (and going to work!), Mark noted he'd try at some point to see if there was a way to separate colliders and rigidbodies, though wasn't sure if it was possible -- I think the rigidbody was the problem here.
It doesn't look like you would technically need the rigidbody for this action, just the collider, presumably, but are forced to include a rigidbody, and these can't be manually repositioned.
/from memory
This all makes sense.
Just to add one more wrinkle, though: in my components I have a "OnLateUpdate", and if I place the movement code there it works just fine! Using the built it "OnEndUpdate" from the component class doesn't work, though.
There's something about the execution order that makes my OnLateUpdate work, but I can't figure out what. Both those methods run after the main update, I can't see why they yield different results. Maybe something about the execution order in the components themselves, since rigid body and collider are also components...
Anyway, removing the need for rigid bodies when all you need are the collisions (not the physics response) would be great!
Just to be clear, I wanted to point out that it does work - as long as you update the movement outside of a component. The issue is related to components only, it looks like.
D'oh! Setting it to kinematic should be enough.
Will try tonight and close if it works. Thanks!