blitz-research/monkey2

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!