Problem with impulses on Scene startup
Hi Mark,
Ran into weird problem with Thrust game, where I have to call Scene.Start followed up Scene.Update in order for impulses applied to my gems on startup to work. (They must be called prior to applying impulses, specifically.)
Without doing this, they simply don't appear on screen, though are still present/accessible in-source.
I think I've narrowed it down to this sample, although the same Start/Update fix doesn't work here, but it should be enough to show something's not quite right.
In Debug mode, this will work as expected -- spawn some cubes and apply a fixed impulse.
In Release mode, the cubes don't appear.
In Thrusting Game, after the above 'fix', they intentionally keep spinning at a fixed rate while playing, and I cancel out gravity so they hover.
If you comment out the call below to ApplyTorqueImpulse, or replace with a call to ApplyTorque (which doesn't have the same fixed-rate effect I'm after), they do then appear in Release as expected, just without the spin.
I'm not sure why my Start/Update fix works in Thrusting and not here, but it seems like doing this is necessary prior to applying any kind of impulse in Thrusting, in Release mode.
Debug mode 'fixes' Thrusting without needing the Start/Update thing.
(Something to do with how Scene and Entity.Start work, in conjunction with the instant timing needed for Impulse to apply??)
Anyway, this at least demos the "entity-missing-when-impulse-applied" thing, so hopefully if you can figure that out, the rest will fall into place...
Again, works as expected in Debug.
' Debug: Works
' Release: No cubes unless you comment out this line under ' START LOOP
' c.body.ApplyTorqueImpulse (New Vec3f (1.0, 1.0, 1.0))
' Only seems to apply to impulses (inc. ApplyImpulse)... ApplyTorque works as expected (but doesn't apply fixed spin immediately)...
' Also see comment in Update ()
#Import "<std>"
#Import "<mojo3d>"
Using std..
Using mojo..
Using mojo3d..
Class Cube
Field coll:BoxCollider
Field body:RigidBody
Method New (loop:Int)
Local box:Boxf = New Boxf (-0.5, -0.5, -0.5, 0.5, 0.5, 0.5)
Local cube:Model = Model.CreateBox (box, 4, 4, 4, New PbrMaterial (Color.Red))
cube.Move (loop * 2 - loop * 0.5, 0, 5)
coll = cube.AddComponent <BoxCollider> ()
body = cube.AddComponent <RigidBody> ()
body.Mass = 1.0
End
End
Class Game Extends Window
Field scene:Scene
Field camera:Camera
Field light:Light
Field cubelist:List <Cube>
Method New (title:String, width:Int, height:Int, flags:WindowFlags)
Super.New (title, width, height, flags)
cubelist = New List <Cube>
scene = Scene.GetCurrent ()
camera = New Camera
light = New Light
camera.Move (0, 0, -5)
' START LOOP
For Local loop:Int = 1 To 10
Local c:Cube = New Cube (loop)
c.body.ApplyTorqueImpulse (New Vec3f (1.0, 1.0, 1.0)) ' Comment me out to work in Release!
cubelist.AddLast (c)
Next
End
Method Update ()
If Keyboard.KeyHit (Key.Escape) Then App.Terminate ()
' Comment out ApplyTorque line above and hit I just after running -- this works too...
If Keyboard.KeyHit (Key.I)
For Local c:Cube = Eachin cubelist
c.body.ApplyTorqueImpulse (New Vec3f (1.0, 1.0, 1.0)) ' Comment me out to work in Release!
Next
Endif
End
Method OnRender (canvas:Canvas) Override
Update ()
scene.Update ()
scene.Render (canvas)
RequestRender ()
End
End
Function Main ()
Local width:Int = 640
Local height:Int = 480
Local flags:WindowFlags = WindowFlags.Center
New AppInstance
New Game ("", width, height, flags)
App.Run ()
End
After testing that, try the thing mentioned in method Update (), as that shows it works once the scene is up and running, which may be another pointer in the right direction...
Just looking at this now and I get the opposite - works in release but not in debug. Can you confirm?
On Tue, Jun 26, 2018 at 10:16 AM DruggedBunny [email protected] wrote:
Hi Mark,
Ran into weird problem with Thrust game, where I have to call Scene.Start followed up Scene.Update (or call Update twice -- as it calls Start) in order for impulses applied to my gems on startup to work.
Without doing this, they simply don't appear on screen, though are still present/accessible in-source.
I think I've narrowed it down to this sample, although the same Start/Update fix doesn't work here, but it should be enough to show something's not quite right.
In Debug mode, this will work as expected -- spawn some cubes and apply a fixed impulse. In Thrusting Game, after the fix, they keep spinning at a fixed rate while playing. (I cancel out gravity so they hover.)
In Release mode, the cubes don't appear.
However, if you comment out the call to ApplyTorqueImpulse, or replace with a call to ApplyTorque (which doesn't have the same fixed-rate effect), they do appear in Release as expected, just without the spin.
I'm not sure why my Start/Update fix works in Thrusting, but it seems like doing this is necessary prior to applying any kind of impulse.
(Something to do with how Scene and Entity.Start work, in conjunction with the instant timing needed for Impulse to apply??)
Anyway, this at least demos the "entity-missing-when-impulse-applied" thing, so hopefully if you can figure that out, the rest will fall into place...
Again, works as expected in Debug.
' Debug: Works
' Release: No cubes unless you comment out this line under ' START LOOP
' c.body.ApplyTorqueImpulse (New Vec3f (1.0, 1.0, 1.0))
' Only seems to apply to Impulse (inc. ApplyImpulse)... ApplyTorque works as expected (but doesn't apply fixed spin immediately)...
' Also see comment in Update ()
#Import "
" #Import " " Using std.. Using mojo.. Using mojo3d..
Class Cube
Field coll:BoxCollider Field body:RigidBody
Method New (loop:Int)
Local box:Boxf = New Boxf (-0.5, -0.5, -0.5, 0.5, 0.5, 0.5) Local cube:Model = Model.CreateBox (box, 4, 4, 4, New PbrMaterial (Color.Red)) cube.Move (loop * 2 - loop * 0.5, 0, 5) coll = cube.AddComponent <BoxCollider> () body = cube.AddComponent <RigidBody> () body.Mass = 1.0End
End
Class Game Extends Window
Field scene:Scene Field camera:Camera Field light:Light
Field cubelist:List <Cube>
Method New (title:String, width:Int, height:Int, flags:WindowFlags)
Super.New (title, width, height, flags) cubelist = New List <Cube> scene = Scene.GetCurrent () camera = New Camera light = New Light camera.Move (0, 0, -5) ' START LOOP For Local loop:Int = 1 To 10 Local c:Cube = New Cube (loop) c.body.ApplyTorqueImpulse (New Vec3f (1.0, 1.0, 1.0)) ' Comment me out to work in Release! cubelist.AddLast (c) NextEnd
Method Update ()
If Keyboard.KeyHit (Key.Escape) Then App.Terminate () ' Comment out ApplyTorque line above and hit I just after running -- this works too... If Keyboard.KeyHit (Key.I) For Local c:Cube = Eachin cubelist c.body.ApplyTorqueImpulse (New Vec3f (1.0, 1.0, 1.0)) ' Comment me out to work in Release! Next EndifEnd
Method OnRender (canvas:Canvas) Override
Update () scene.Update () scene.Render (canvas) RequestRender ()End
End
Function Main ()
Local width:Int = 640 Local height:Int = 480 Local flags:WindowFlags = WindowFlags.Center
New AppInstance
New Game ("", width, height, flags)
App.Run ()
End
After testing that, try the thing mentioned in method Update (), as that shows it works once the scene is up and running, may be another pointer in the right direction...
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/blitz-research/monkey2/issues/399, or mute the thread https://github.com/notifications/unsubscribe-auth/ADU3QlA3c_Tg1sw5NSqVF_WLR0MT0P1dks5uAWE2gaJpZM4U28IX .
Just checked -- nope, definitely working in Debug, and not in Release for me!
I'm building with MSVC and x64 here. I'll start other module formats building (x86 and MinGW) and see if any different...
Seems like some subtle timing problem, maybe something to do with how impulses take place instantly and might need a few scene updates to kick in? Only seems to affect impulses (ApplyTorqueImpulse, ApplyImpulse).
Suspect if you can fix your results to work in both, that will sort it!
Will change thread title back...
Try it with this:
Edit imports/level.monkey2 -> New, just before End:
...
New Pad (93.0, 38.0, -365.0,, Color.Lime)
SpaceGemAdded ()
space_gems_total = SpaceGemCount
' Scene.Update doesn't work unless called twice! Gems remain hidden...
' Start () or a call to Scene.Update () -- which calls Start () -- works:
Game.GameScene.Start ()
Game.GameScene.Update () ' Fixes missing physics bodies at startup;
' Believe bodies need update BEFORE applying impulses!
' Without Start (), another call to Scene.Update () is required...
' Game.GameScene.Update ()
SpaceGem.Start () ' Applies torque impulse to start spinning immediately
End
Comment out Game.GameScene.Start () or Game.GameScene.Update () and see if the gems are missing in Debug or Release. Missing in Release for me.
Also, if you comment out .Start (), try adding the second commented-out .Update () line, which also fixes it here.
The weird thing for me is that it was working a few days back with only a single .Update prior to calling *Impulse () and I don't believe I changed anything before it went wrong! Must have done, but it seemed to come out of the blue, just didn't work one day...
Ok, possible fix now up in develop branch.
On Wed, Jun 27, 2018 at 12:46 PM DruggedBunny [email protected] wrote:
Just checked -- nope, definitely working in Debug, and not in Release for me!
I'm building with MSVC and x64 here. I'll start other module formats building (x86 and MinGW) and see if any different...
Seems like some subtle timing problem, maybe something to do with how impulses take place instantly and might need a few scene updates to kick in? Only seems to affect impulses (ApplyTorqueImpulse, ApplyImpulse).
Suspect if you can fix your results to work in both, that will sort it!
Will change thread title back...
— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/blitz-research/monkey2/issues/399#issuecomment-400507642, or mute the thread https://github.com/notifications/unsubscribe-auth/ADU3Qg7jY7pcil7mts5WC2YKAHwN0jumks5uAtX1gaJpZM4U28IX .
OK, will go update...
...and another last minute push!
On Wed, Jun 27, 2018 at 12:58 PM DruggedBunny [email protected] wrote:
OK, will go update...
— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/blitz-research/monkey2/issues/399#issuecomment-400509340, or mute the thread https://github.com/notifications/unsubscribe-auth/ADU3Qtvs-3s3xvhr3XJSts_BFLe-EY_Bks5uAtizgaJpZM4U28IX .
Yes! That looks to have done it -- above test works in both modes, Thrust works in both without Scene.Update/Start call and without my SpaceGem.Start hack (ie. I can just apply impulse when New'd).
My SmokeParticles have gone weird, but were probably just 'working' based off the broken behaviour, so will try sort that tomorrow.
Thanks, Mark, amazingly quick fix!
Ah, smoke just needed impulse value decimated. Dunno how that was working before, must again have been accidentally working off the broken startup!
thrust = New Vec3f (0.0, -0.3 * multi, 0.0)
Been round and cleared the level without any problems!
This one looks to be resolved, but sort of off the back of this, I became obsessed (while in and out of sleep) with the idea of having an OnSceneUpdate (or just OnUpdate) method attached to Entity.
It would be pretty darn tidy not to need a standalone list for any type of entity you want to revisit each update (eg. the gems, smoke particles), instead just having a smoke.OnUpdate callback (component?) where you could define what happens in OnUpdate in the class definition itself.
No need to find somewhere to stick in a SmokeParticle.List, a SpaceGemList, etc, and manually iterate through each one at each update.
Might it have performance implications, though?
This is really what components are for, eg: you create a GemComponent, PlayerComponent, and use 'AddComponent' to attach them to models or pivots or whatever.
All the crap you already had in your 'BoxBody' etc. classes can go in here too. Components can 'see' other components by using 'Entity.RigidBody' (or Entity.GetComponent) etc so you can also drop many of the fields you had.
If you want to try this, best to probably extend Behaviour instead of Component to start with as this takes care of a bunch of stuff for you.
On Wed, Jun 27, 2018 at 7:22 PM DruggedBunny [email protected] wrote:
This one looks to be resolved, but sort of off the back of this, I became obsessed (while in and out of sleep) with the idea of having an OnSceneUpdate (or just OnUpdate) method attached to Entity.
It would be pretty darn tidy not to have to set up a standalone list for any type of entity you want to revisit each update (eg. the gems, smoke particles), instead just having a smoke.OnUpdate callback (component?) where you could update them in the class itself.
No need to find somewhere to stick in a SmokeParticle.List, a SpaceGemList, etc, and manually iterate through each one at each update.
Might it have performance implications, though?
— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/blitz-research/monkey2/issues/399#issuecomment-400569605, or mute the thread https://github.com/notifications/unsubscribe-auth/ADU3QnWl_EOI2wek0vGXH8Yuov61Xxmqks5uAzLLgaJpZM4U28IX .
Hmm, OK, will look into that -- I'm not using those old BoxBody etc things any more (the ToyBox thing), as AddComponent really simplified setup of physics objects.
How would you link that in with Scene.Update, though, is there some sort of callback available already?
I was thinking of something like:
' Main loop
Method Render ()
scene.Update () ' Calls OnSceneUpdate on all Entities
' Etc
End
Class SmokeParticle
Method OnSceneUpdate () ' Called by scene.Update
ApplyForce
ReduceAlpha
If alpha < 0 Then Destroy ()
End
End
Hence no need to manually manage lists of different entities, each on just gets called automatically and can carry out its own update, removal, etc.
Is that doable via Components?
Er, I guess SmokeParticle isn't an Entity, duh, but could potentially extend Model there I imagine...
Components have an OnUpdate method, have a look at FlyBehaviour in mojo3d for an example of writing a 'flyable' component. There are also methods for updating visiblity, and there will be more methods added in in future.
On Thu, Jun 28, 2018 at 12:40 AM DruggedBunny [email protected] wrote:
Er, I guess SmokeParticle isn't an Entity, duh, but could potentially extend Model there I imagine...
— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/blitz-research/monkey2/issues/399#issuecomment-400657449, or mute the thread https://github.com/notifications/unsubscribe-auth/ADU3QlMjQEu_cOi4gQKQfFsUCk5d_pThks5uA31LgaJpZM4U28IX .
Ah, sounds good, will give it a go.
I did mess about with Components, and got something basic working, but calling component.OnUpdate passes in elapsed:Float, and over time my spacegems were slowly floating away, whereas they weren't obviously doing so when manually iterating through a list during OnRender (simply applying negative gravity), so I guess it comes down to when the update happens.
I wasn't able to fix this using component.OnUpdate's elapsed param (and suspect it would not be possible anyway due to minor timing errors), so thought I'd try giving them a Collider with no RigidBody, manually doing model.Rotate instead, which would be all I need.
However, as the entity.Collided () lambda passes in the other colliding RigidBody, I think this fails because I don't have a RigidBody attached to my entity -- I get no collision.
Should it be possible to detect pure collisions using only the Collider?
(All a bit of a mess just now, but see imports/spacegem.monkey2, line 43/44 -- expecting to see "Hi" printed on collision with gem... )
Is there any way you can produce a one file version of the problem with Component.OnUpdate. The project's become kind of hard to navigate around...
In theory, if you're doing this:
Method OnRender() UpdateMyGame() 'my update logic... Scene.Update() Scene.Render() End
It should be basically the same as implementing Component.OnUpdate and just ignoring elapsed param (assuming UpdateMyGame ignores elapsed time too of course). Scene.Update() is what is (or should be) calling Component.OnUpdate, so they should roughly be the same thing.
Or is this not how your update code works?
On Wed, Jul 11, 2018 at 11:38 PM DruggedBunny [email protected] wrote:
I did mess about with Components, and got something basic working, but calling component.OnUpdate passes in elapsed:Float, and over time my spacegems were slowly floating away, whereas they weren't obviously doing so when manually iterating through a list during OnRender (simply applying negative gravity), so I guess it comes down to when the update happens.
I wasn't able to fix this using component.OnUpdate's elapsed param (and suspect it would not be possible anyway due to minor timing errors), so thought I'd try giving them a Collider with no RigidBody, manually doing model.Rotate instead, which would be all I need.
However, as the entity.Collided () lambda passes in the other colliding RigidBody, I think this fails because I don't have a RigidBody attached to my entity -- I get no collision.
Should it be possible to detect pure collisions using only the Collider?
thrusting.zip https://github.com/blitz-research/monkey2/files/2184226/thrusting.zip
(All a bit of a mess just now, but see imports/spacegem.monkey2, line 43/44 -- expecting to see "Hi" printed on collision with gem... )
— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/blitz-research/monkey2/issues/399#issuecomment-404138685, or mute the thread https://github.com/notifications/unsubscribe-auth/ADU3QsXOTD_I54mB4DfNdEZsEn0xzDWhks5uFeOegaJpZM4U28IX .
Ok, found OnRender and UpdateGame but I can't see where you process the gems list.
But it looks like your basic update logic should work with Component.OnUpdate. If you were to make GameMenu, Player, HUD and perhaps even CurrentLevel all subclasses of Behaviour, they could all be automatically OnUpdated for you inside Scene.OnUpdate. This also makes them very reusable and quite easy to serialize.
As for colliders, bullet seems to need the rigidbody for collisionmask/collisiongroup, but I'll look into it again soon-ish.
On Thu, Jul 12, 2018 at 10:32 AM Mark Sibly [email protected] wrote:
Is there any way you can produce a one file version of the problem with Component.OnUpdate. The project's become kind of hard to navigate around...
In theory, if you're doing this:
Method OnRender() UpdateMyGame() 'my update logic... Scene.Update() Scene.Render() End
It should be basically the same as implementing Component.OnUpdate and just ignoring elapsed param (assuming UpdateMyGame ignores elapsed time too of course). Scene.Update() is what is (or should be) calling Component.OnUpdate, so they should roughly be the same thing.
Or is this not how your update code works?
On Wed, Jul 11, 2018 at 11:38 PM DruggedBunny [email protected] wrote:
I did mess about with Components, and got something basic working, but calling component.OnUpdate passes in elapsed:Float, and over time my spacegems were slowly floating away, whereas they weren't obviously doing so when manually iterating through a list during OnRender (simply applying negative gravity), so I guess it comes down to when the update happens.
I wasn't able to fix this using component.OnUpdate's elapsed param (and suspect it would not be possible anyway due to minor timing errors), so thought I'd try giving them a Collider with no RigidBody, manually doing model.Rotate instead, which would be all I need.
However, as the entity.Collided () lambda passes in the other colliding RigidBody, I think this fails because I don't have a RigidBody attached to my entity -- I get no collision.
Should it be possible to detect pure collisions using only the Collider?
thrusting.zip https://github.com/blitz-research/monkey2/files/2184226/thrusting.zip
(All a bit of a mess just now, but see imports/spacegem.monkey2, line 43/44 -- expecting to see "Hi" printed on collision with gem... )
— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/blitz-research/monkey2/issues/399#issuecomment-404138685, or mute the thread https://github.com/notifications/unsubscribe-auth/ADU3QsXOTD_I54mB4DfNdEZsEn0xzDWhks5uFeOegaJpZM4U28IX .
Another thing to try is overriding Component.OnBeginUpdate() instead. OnUpdate() is actually called after physics is updated, whereas OnBeginUpdate() is called before so is more similar to your update logic.
On Thu, Jul 12, 2018 at 10:43 AM Mark Sibly [email protected] wrote:
Ok, found OnRender and UpdateGame but I can't see where you process the gems list.
But it looks like your basic update logic should work with Component.OnUpdate. If you were to make GameMenu, Player, HUD and perhaps even CurrentLevel all subclasses of Behaviour, they could all be automatically OnUpdated for you inside Scene.OnUpdate. This also makes them very reusable and quite easy to serialize.
As for colliders, bullet seems to need the rigidbody for collisionmask/collisiongroup, but I'll look into it again soon-ish.
On Thu, Jul 12, 2018 at 10:32 AM Mark Sibly [email protected] wrote:
Is there any way you can produce a one file version of the problem with Component.OnUpdate. The project's become kind of hard to navigate around...
In theory, if you're doing this:
Method OnRender() UpdateMyGame() 'my update logic... Scene.Update() Scene.Render() End
It should be basically the same as implementing Component.OnUpdate and just ignoring elapsed param (assuming UpdateMyGame ignores elapsed time too of course). Scene.Update() is what is (or should be) calling Component.OnUpdate, so they should roughly be the same thing.
Or is this not how your update code works?
On Wed, Jul 11, 2018 at 11:38 PM DruggedBunny [email protected] wrote:
I did mess about with Components, and got something basic working, but calling component.OnUpdate passes in elapsed:Float, and over time my spacegems were slowly floating away, whereas they weren't obviously doing so when manually iterating through a list during OnRender (simply applying negative gravity), so I guess it comes down to when the update happens.
I wasn't able to fix this using component.OnUpdate's elapsed param (and suspect it would not be possible anyway due to minor timing errors), so thought I'd try giving them a Collider with no RigidBody, manually doing model.Rotate instead, which would be all I need.
However, as the entity.Collided () lambda passes in the other colliding RigidBody, I think this fails because I don't have a RigidBody attached to my entity -- I get no collision.
Should it be possible to detect pure collisions using only the Collider?
thrusting.zip https://github.com/blitz-research/monkey2/files/2184226/thrusting.zip
(All a bit of a mess just now, but see imports/spacegem.monkey2, line 43/44 -- expecting to see "Hi" printed on collision with gem... )
— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/blitz-research/monkey2/issues/399#issuecomment-404138685, or mute the thread https://github.com/notifications/unsubscribe-auth/ADU3QsXOTD_I54mB4DfNdEZsEn0xzDWhks5uFeOegaJpZM4U28IX .
Thanks for having a look, Mark, will look into what you've said here, since you seem confident it should work! Yes, bit tricky to follow, no doubt... I'll narrow it down if/when I get stuck again...
Regarding the missing gem list, I was using the Component thing (commented-out under spacegem.monkey2 as Class SpaceGemComponent) to manage them, instead of using a list, ie. create the gems, then use component.OnUpdate to visit each one -- that worked really well, but I was getting the floating-away effect.
I actually found plain Component easier to grasp than Behaviour (after eventually narrowing down the minimum I needed), but will have another look at Behaviour too. This might have been because I really just wanted the OnUpdate functionality to skip maintaining a separate list.
For what it's worth, I ended up with this generic version, attaching the SpaceGem object under ao:MyClass so I could access its members from the Entity/Component update:
Class CustomComponent Extends Component
Private
Const COMPONENT_PRIORITY:Int = 0
Const COMPONENT_TYPE:ComponentType = New ComponentType ("CustomComponent", COMPONENT_PRIORITY, ComponentTypeFlags.Singleton)
Field ao:MyClass ' Attached object (modify/delete to suit) -- see AttachedOject property
Method OnUpdate (elapsed:Float) Override
' eg.
Entity.GetComponent <RigidBody> ()?.ApplyForce (Game.GameScene.World.Gravity * New Vec3f (1.0, -1.0, 1.0))
AttachedObject?.DoSomething ()
End
Public
Method New (entity:Entity)
Super.New (entity, COMPONENT_TYPE)
AddInstance ()
End
Property AttachedObject:MyClass () ' Modify/delete to suit
Return ao
Setter (new_ao:MyClass)
ao = new_ao
End
End
Probably missing something, though... was just an experiment in ditching management of manual lists!
Realistically these gems don't need physics, so I can always go back to simple models with distance checks if all else fails, just seems more consistent and feels more accurate when collecting...
Thanks again, you've obviously spent a fair bit of time looking at this. I'll dig into FlyBehaviour again... at least it sounds like this 'should' work, and I can at least produce a stripped-down version if not...
Looks like FlyBehaviour is very similar to the above, just takes care of the ComponentType/priority stuff, so I'll use Behaviour instead! Going to start SpaceGem from scratch and see how it goes...
EDIT: Ah, I now see how you stick the stuff that would otherwise be my SpaceGem object into the Behaviour instead...
Hi Mark,
You might find this of interest -- this example shows that applying force (negative gravity here) to a body at different update points gives slightly different, but significant, results. OnBeginUpdate seems to give the result I wanted, though, so going to try plugging that into SpaceGem...
#Import "<std>"
#Import "<mojo3d>"
Using std..
Using mojo..
Using mojo3d..
Const APPLY_IN_ONRENDER:Int = 1 ' Main loop ' Floats upwards
Const APPLY_IN_ONUPDATE:Int = 2 ' Behaviour.OnUpdate ' Floats downwards
Const APPLY_IN_ONBEGIN:Int = 3 ' Behaviour.OnBeginUpdate ' Rock solid!
' Apply gravity at this point:
Const APPLY_WHEN:Int = APPLY_IN_ONRENDER
' Note to self:
' body.btBody.setGravity (New bullet.btVector3 (0.0, 0.0, 0.0))
' ^ this called *every update* slowly settles to no movement
Class SpaceGemBehaviour Extends Behaviour
Public
Method New (entity:Entity)
Super.New (entity)
model = Cast <Model> (entity)
AddInstance ()
End
Method AddBody (box:Boxf)
body = New RigidBody (model)
body.Mass = 1.0
collider = New BoxCollider (model)
collider.Box = box
' Spin me!
'body.ApplyTorqueImpulse (New Vec3f (0.1, 0.2, 0.4))
End
Method OnBeginUpdate () Override
If APPLY_WHEN = APPLY_IN_ONBEGIN
body.ApplyForce (Game.GameScene.World.Gravity * New Vec3f (1.0, -1.0, 1.0))
Endif
End
Method OnUpdate (elapsed:Float) Override
If APPLY_WHEN = APPLY_IN_ONUPDATE
body.ApplyForce (Game.GameScene.World.Gravity * New Vec3f (1.0, -1.0, 1.0))
Endif
End
' Private
Field model:Model
Field body:RigidBody ' Bullet physics body
Field collider:BoxCollider ' Bullet physics collider
End
Class Game Extends Window
' Basic 3D scene requirements...
Global GameScene:Scene
Field camera:Camera
Field light:Light
Field gem:Model
Field gembehaviour:SpaceGemBehaviour
Method New (title:String, width:Int, height:Int, flags:WindowFlags)
Super.New (title, width, height, flags)
GameScene = Scene.GetCurrent () ' Important!
camera = New Camera
camera.Move (0, 0, -5)
light = New Light
Local box:Boxf = New Boxf (-0.5, -0.5, -0.5, 0.5, 0.5, 0.5)
gem = Model.CreateBox (box, 2, 2, 2, New PbrMaterial (Color.Red))
gembehaviour = gem.AddComponent <SpaceGemBehaviour> ()
gembehaviour.AddBody (box)
End
Method OnRender (canvas:Canvas) Override
If Keyboard.KeyHit (Key.Escape) Then App.Terminate ()
If APPLY_WHEN = APPLY_IN_ONRENDER
gembehaviour.body.ApplyForce (Game.GameScene.World.Gravity * New Vec3f (1.0, -1.0, 1.0))
Endif
GameScene.Update ()
GameScene.Render (canvas)
RequestRender ()
End
End
Function Main ()
' Windowed mode...
Local width:Int = 640
Local height:Int = 480
Local flags:WindowFlags = WindowFlags.Center
New AppInstance
New Game ("", width, height, flags)
App.Run ()
End
I think my model and body fields are probably redundant, as I think I can access Entity and (from there) the attached RigidBody, so will try strip this down a bit...
Anyway, it shows the effect of applying the force at different times!
OnBeginUpdate has solved my SpaceGems thing, anyway... think I now just need to spawn a final Orb to collect and fly through a suspiciously CreateTorus-shaped SpacePortal to finish it off! (OK, bit more tweaking, tidying up, etc too... )
Just ran into an interesting Debug vs Release quirk with the above code, with OnUpdate replaced by this version (adds hit-Space-to-delete-model)...
Method OnUpdate (elapsed:Float) Override
If APPLY_WHEN = APPLY_IN_ONUPDATE
body.ApplyForce (Game.GameScene.World.Gravity * New Vec3f (1.0, -1.0, 1.0))
Endif
If Keyboard.KeyHit (Key.Space)
model.Destroy ()
Endif
End
It works in Release mode, but causes Invalid stack iterator in Debug mode.
I imagine this shouldn't actually work anyway (deleting the entity the behaviour is attached to, from within the behaviour).
You can't pass any data in on AddComponent or New Behaviour, so other than bundling data into fields within the Behaviour, I'm not sure how to do this... and can't then delete the entity from OnUpdate when it's no longer needed.
My understanding is that Behaviour should just be adding actions to Entity, but in the example above, I need to access the RigidBody, so have to sort of hack it in after adding the Behaviour... (see AddBody).
Like I say, this nasty hackery seems to work in Release here, but not in Debug... model.Destroy () causes the exception.
Is there a better way to wrap up non-Entity stuff with behaviours (eg. RigidBody and other object data) than what I'm attempting here?
Best workaround I could come up with for deleting entities from within Behaviour.OnUpdate:
[EDIT: Seems to work well, having updated game to use this.]
#Import "<std>"
#Import "<mojo3d>"
Using std..
Using mojo..
Using mojo3d..
#Rem
Method:
1) Use MarkEntity (entity) to mark for deletion in Behaviour.OnUpdate () (add to list)
2) Use RemoveMarkedEntities () to remove marked entities in Game.OnRender (after scene.Update ())
Game.MarkEntity (entity:Entity)
Game.RemoveMarkedEntities ()
#End
' Note to self:
' body.btBody.setGravity (New bullet.btVector3 (0.0, 0.0, 0.0))
' ^ this called *every update* slowly settles to no movement
Class SpaceGemBehaviour Extends Behaviour
Public
Method New (entity:Entity)
Super.New (entity)
model = Cast <Model> (entity)
AddInstance ()
End
Method AddBody (box:Boxf)
body = New RigidBody (model)
body.Mass = 1.0
collider = New BoxCollider (model)
collider.Box = box
' Spin me!
body.ApplyTorqueImpulse (New Vec3f (0.1, 0.2, 0.4))
End
Method OnBeginUpdate () Override
body.ApplyForce (Game.GameScene.World.Gravity * New Vec3f (1.0, -1.0, 1.0))
End
Method OnUpdate (elapsed:Float) Override
If Keyboard.KeyHit (Key.Space)
Game.MarkEntity (Entity) ' Mark for deletion in main loop (RemoveMarkedEntities)...
Destroy () ' Sets local entity ref to Null but doesn't remove model from scene AFAICT
'body.Destroy () ' Crash
body = Null
Endif
End
' Private
Field model:Model
Field body:RigidBody ' Bullet physics body
Field collider:BoxCollider ' Bullet physics collider
End
Class Game Extends Window
' Basic 3D scene requirements...
Global GameScene:Scene
Global MarkedEntities:List <Entity>
Field camera:Camera
Field light:Light
Field gem:Model
Field gembehaviour:SpaceGemBehaviour
Function MarkEntity (entity:Entity)
Game.MarkedEntities.AddLast (entity)
End
Function RemoveMarkedEntities ()
For Local entity:Entity = Eachin Game.MarkedEntities
entity?.Destroy ()
Game.MarkedEntities.Remove (entity)
Next
End
Method New (title:String, width:Int, height:Int, flags:WindowFlags)
Super.New (title, width, height, flags)
GameScene = Scene.GetCurrent () ' Important!
MarkedEntities = New List <Entity>
camera = New Camera
camera.Move (0, 0, -5)
light = New Light
Local box:Boxf = New Boxf (-0.5, -0.5, -0.5, 0.5, 0.5, 0.5)
gem = Model.CreateBox (box, 2, 2, 2, New PbrMaterial (Color.Red))
gembehaviour = gem.AddComponent <SpaceGemBehaviour> ()
gembehaviour.AddBody (box)
End
Method OnRender (canvas:Canvas) Override
If Keyboard.KeyHit (Key.Escape) Then App.Terminate ()
GameScene.Update ()
RemoveMarkedEntities ()
GameScene.Render (canvas)
RequestRender ()
End
End
Function Main ()
' Windowed mode...
Local width:Int = 640
Local height:Int = 480
Local flags:WindowFlags = WindowFlags.Center
New AppInstance
New Game ("", width, height, flags)
App.Run ()
End
Yes, Destroy with entites/components will probably need to be delayed until 'end of update' when executed inside of update. Outside of update it can occur immediately.
I might also pinch unity's idea of 'Destroy( delay:Float=0 )' which allows you to destroy something after some time has elapsed.
Will get onto this stuff for next release!
Also, have you check out the monkey2 discord channel? That seems to be the place to go for monkey2 chat these days.
On Wed, Jul 18, 2018 at 11:18 AM DruggedBunny [email protected] wrote:
Just ran into an interesting Debug vs Release quirk with the above code, with OnUpdate replaced by this version (adds hit-Space-to-delete-model)...
Method OnUpdate (elapsed:Float) Override If APPLY_WHEN = APPLY_IN_ONUPDATE body.ApplyForce (Game.GameScene.World.Gravity * New Vec3f (1.0, -1.0, 1.0)) Endif If Keyboard.KeyHit (Key.Space) model.Destroy () Endif EndIt works in Release mode, but causes Invalid stack iterator in Debug mode.
I imagine this shouldn't actually work anyway (deleting the entity the behaviour is attached to, from within the behaviour), but is there a better way to wrap up non-Entity stuff with behaviours?
You can't pass any data in on AddComponent or New Behaviour, so other than bundling data into fields within the Behaviour, I'm not sure how to do this... and can't then delete the entity from OnUpdate when it's no longer needed.
My understanding is that Behaviour should just be adding actions to Entity, but in the example above, I need to access the RigidBody, so have to sort of hack it in after adding the Behaviour... (see AddBody).
Like I say, this nasty hackery seems to work in Release here, but not in Debug... model.Destroy () causes the exception.
— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/blitz-research/monkey2/issues/399#issuecomment-405758321, or mute the thread https://github.com/notifications/unsubscribe-auth/ADU3QkwhPlnPgNUknYlkvTueZrjGtQKNks5uHnDRgaJpZM4U28IX .
Hi Mark,
When you get back to this, these are the points from this thread I'd highlight (realise it's got a bit sprawling/wordy on my part!)...
Detect pure collisions (no RigidBodies)
Debug vs Release mode difference (crash) with component.Destroy
Marking/Destroying entities from within component.OnUpdate
On the last point, this seems to work really well in my game -- turns out that, almost all of the time, the list of marked entities holds exactly 1 entity, due to the timing of New and the fixed rate at which the objects 'decay' (eg. fade out).
If I try New'ing 4 SmokeParticles instead of 1, the list holds 4 particles pretty much all the time. Seems fairly predictable/low impact.
Destroy () could potentially include the marking portion so this doesn't appear as a separate step.
Oh, yeah, Discord -- not tried it as I'm not into the whole realtime chat thing, always felt awkward about it (same with IRC, Facebook messages, etc), preferring to operate at my own speed, ie. come back to things later, but might have a look...
Er, see highlights above!
Just tooling around with this now and would like permission to clean up a few things:
-
Change Entity.Collided to RigidBody.Collided. This is where it should be IMO, as there's no reason for Entity to have to 'know' about rigidbodies like this.
-
Remove OnBeginUpdate() and change OnUpdate() to execute before physics update - we can add an OnEndUpdate or OnAfterUpdate later if need be, but IMO OnUpdate should be before physics update and I goofed here.
And whadya mean you're no good at facebook! Yor're way better than me, I can't even 'face' it these days!
On Sun, Jul 22, 2018 at 10:47 PM DruggedBunny [email protected] wrote:
Er, see highlights above!
— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/blitz-research/monkey2/issues/399#issuecomment-406856873, or mute the thread https://github.com/notifications/unsubscribe-auth/ADU3QngZME_j9jHX0DM_9pHDGi16ZEuIks5uJFg6gaJpZM4U28IX .
Ha, I hate Facebook, just can't get away now.
Yeah, no problem for me to update these things... actually got a fair bit done to the game (bit more controllable too), but these changes won't cause me any more than a couple of minutes' work (he says).