About Monkey 2 › Forums › Monkey 2 Programming Help › Removing from Stack/Stack Assert?
This topic contains 13 replies, has 5 voices, and was last updated by
DruggedBunny
1 year, 3 months ago.
-
AuthorPosts
-
January 11, 2018 at 4:34 am #12802
Am I removing objects correctly from a stack here? I add 10 objects, iterate through to Remove each one, but the final count is 5…
Monkey123456789101112131415161718192021222324252627282930313233#Import "<std>"Using std..Class TestField blah:IntEndFunction Main ()Local stack:Stack <Test> = New Stack <Test>stack.Add (New Test)stack.Add (New Test)stack.Add (New Test)stack.Add (New Test)stack.Add (New Test)stack.Add (New Test)stack.Add (New Test)stack.Add (New Test)stack.Add (New Test)stack.Add (New Test)Print stack.Length ' 10For Local t:Test = Eachin stackstack.Remove (t)NextPrint stack.Length ' 5EndThe code below is the actual code I’m puzzled about, and seems to cause a stack index/length Assert in Debug mode.
See UpdateGame and If Keyboard.KeyHit (Key.Space) — let it run in Debug mode, and it may crash when some cubes fall over the side; if not, hit Space a few times and it should trigger the Assert.
In Release mode, it keeps running, and each hit of Space removes more cubes, showing they’re still in the stack! Yet, hitting space in theory removes all objects from the stack… so what’s going on there?!
Monkey123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282#Import "<std>"#Import "<mojo>"#Import "<mojo3d>"Using std..Using mojo..Using mojo3d..Const SPEW_BOXES:Int = 100 ' How many boxes to add to sceneClass PhysBoxClass PhysParamsField mass:FloatField group:ShortField mask:ShortEndField box:BoxfField model:ModelField collider:BoxColliderField body:RigidBodyField init:PhysParamsMethod New (width:Float = 1, height:Float = 1, depth:Float = 1, mass:Float = 1, material:Material = Null, group:Int = 1, mask:Int = 1)' Store setup params for PhysBox.Start ()init = New PhysParamsinit.mass = massinit.group = groupinit.mask = maskIf Not materialmaterial = New PbrMaterial (Color.Red)Endifbox = New Boxf (-width * 0.5, -height * 0.5, -depth * 0.5, width * 0.5, height * 0.5, depth * 0.5)model = Model.CreateBox (box, 8, 8, 8, material)EndMethod Start ()collider = New BoxCollider (model)body = New RigidBody (model)collider.Box = boxbody.Mass = init.massbody.CollisionGroup = init.groupbody.CollisionMask = init.maskbox = Nullinit = NullEndMethod Move (x:Float, y:Float, z:Float)model.Move (x, y, z)EndMethod Rotate (pitch:Float, roll:Float, yaw:Float, localspace:Bool = False)model.Rotate (pitch, roll, yaw, localspace)EndEndClass Game Extends WindowConst CAMERA_MOVE:Float = 0.05Const CAMERA_BOOST:Float = 4.0Field cam_boost:Float = 1.0Field scene:SceneField cam:CameraField light:LightField ground:PhysBoxField boxes:Stack <PhysBox>Method New (title:String, width:Int, height:Int, flags:WindowFlags)Super.New (title, width, height, flags)SwapInterval = 1CreateArena (25)EndMethod CreateArena:Void (ground_size:Float = 100)SeedRnd (Millisecs ())Local pm:PbrMaterial = New PbrMaterial (New Color (0, 1, 0, 0.25))pm.BlendMode = BlendMode.Alphascene = Scene.GetCurrent ()ground = New PhysBox (ground_size, 1, ground_size, 0, pm)'New PbrMaterial (Color.Green * 0.25))cam = New Cameralight = New Lightscene.AmbientLight = Color.White * 0.75scene.ClearColor = Color.Sky * 0.75cam.FOV = 100cam.Move (0, 20, -20)ground.Move (0, -5, 0)ground.Start ()cam.Near = 0.01cam.Far = 1000light.CastsShadow = Truelight.Range = 1000light.Move (0, 50, 10)cam.PointAt (ground.model)light.PointAt (ground.model)SpewBoxes ()EndMethod SpewBoxes (num:Int = SPEW_BOXES)boxes = New Stack <PhysBox>For Local loop:Int = 1 To numLocal scale:Float = Rnd (0.5, 4.0)Local color:Color = New Color (Rnd (0.4, 1.0), Rnd (0.4, 1.0), Rnd (0.4, 1.0))' Just for clarity in New below...Local dimension:Float = scaleLocal mass:Float = scale' Create new PhysBox...Local pb:PhysBox = New PhysBox (dimension, dimension, dimension, mass, New PbrMaterial (color))' Position PhysBox...pb.Move (Rnd (-10, 10), Rnd (10, 100), Rnd (-10, 10))pb.Rotate (Rnd (360), Rnd (360), Rnd (360))' Start its physics...pb.Start ()boxes.Add (pb)NextEndMethod UpdateBoxes ()For Local pb:PhysBox = Eachin boxesIf pb.model.Y < -20pb.model.Destroy ()boxes.Remove (pb)EndifNextEndMethod UpdateGame ()UpdateBoxes ()If Keyboard.KeyHit (Key.Escape)App.Terminate ()EndifIf Keyboard.KeyHit (Key.S)light.CastsShadow = Not light.CastsShadowEndifIf Keyboard.KeyHit (Key.Space)For Local pb:PhysBox = Eachin boxespb.model.Destroy ()boxes.Remove (pb)Next' SpewBoxes ()EndifIf Keyboard.KeyDown (Key.LeftShift)cam_boost = CAMERA_BOOSTElsecam_boost = 1.0EndifIf Keyboard.KeyDown (Key.A)cam.Move (0.0, 0.0, CAMERA_MOVE * cam_boost)EndifIf Keyboard.KeyDown (Key.Z)cam.Move (0.0, 0.0, -CAMERA_MOVE * cam_boost)EndifIf Keyboard.KeyDown (Key.Left)cam.Rotate (0.0, 1.0, 0.0)EndifIf Keyboard.KeyDown (Key.Right)cam.Rotate (0.0, -1.0, 0.0)EndifIf Keyboard.KeyDown (Key.Up)cam.Rotate (1.0, 0.0, 0.0, True)EndifIf Keyboard.KeyDown (Key.Down)cam.Rotate (-1.0, 0.0, 0.0, True)EndifEndMethod ShadowText:Void (canvas:Canvas, s:String, x:Float, y:Float)canvas.Color = Color.Blackcanvas.DrawText (s, x + 1, y + 1)canvas.Color = Color.Whitecanvas.DrawText (s, x, y)EndMethod RenderText (canvas:Canvas)If Now () < 5ShadowText (canvas, "App will crash in " + (5 - Int (Now ())) + " secs...", 20.0, 140.0)ElseShadowText (canvas, "FPS: " + App.FPS, 20.0, 20.0)ShadowText (canvas, "A/Z + Cursors to move camera", 20.0, 40.0)ShadowText (canvas, "SHIFT to boost", 20.0, 60.0)ShadowText (canvas, "SPACE to spew boxes", 20.0, 80.0)ShadowText (canvas, "S to toggle shadows", 20.0, 100.0)ShadowText (canvas, "Boxes: " + boxes.Length, 20.0, 140.0)EndifEndMethod OnRender (canvas:Canvas) OverrideUpdateGame ()RequestRender ()scene.Update ()scene.Render (canvas, cam)RenderText (canvas)EndEndFunction Run3D (title:String, width:Int, height:Int, flags:WindowFlags = WindowFlags.Center)New AppInstanceNew Game (title, width, height, flags)App.Run ()EndFunction Main ()Run3D ("3D Scene", 960, 540, WindowFlags.Center) ' 1/4 HD!' Run3D ("3D Scene", 1920, 1080, WindowFlags.Fullscreen)EndIs there some sort of delay in updating the stack/stack.Length after removal?
(Realise this is likely me, as usual.)
January 11, 2018 at 1:36 pm #12814Try to remove items inside of ‘foreach’ in Java or C# and you’ll get runtime error “collection was modified due iterating” (text isn’t exactly).
To be able to remove items due iterating you have to use stack.iterator with while loop:
Monkey1234567891011121314151617Local iter:=stack.All ()While Not iter.AtEnd ()Local value:=iter.CurrentIf value=needRemoveiter.Erase ()Elseiter.Bump ()EndifWendJanuary 11, 2018 at 6:27 pm #12818Hmm, thanks, nerobot. It’s quite complex, but seems to do the job anyway. I’ll try understand it!
January 11, 2018 at 7:20 pm #12819Aha, I’ve been having similar issues.
I added a bunch of particles to a stack and tried to remove them almost at the same.
I kept getting some weird errors by doing so.I’m not sure I understand the ‘solution’, but good to know!
But why isn’t Monkey 2 doing this itself?
Is there any benefits to it acting this way?January 11, 2018 at 9:02 pm #12820The problem is to do with removing items from a container while you’re iterating though the same container. It’s a bit like doing this:
Monkey12345678910111213141516171819#Import "<std>"Using std..Function Main()Local stack:=New IntStackFor Local i:=0 Until 10stack.Add( i )NextFor Local i:=0 Until 10Print "Deleting item "+stack[ i ]stack.Erase( i )NextEndThis may or may not things clearer, but the problem here is that after you delete an item, the current item then becomes the next item (ie: all items ‘shift down’) but then the ‘Next’ statement ‘skips over’ that next item so you end up missing every second item! Worse than that, after removing an item, depending on the type of container involved, it may be very hard to even get to the next item as the current item is no longer really valid. For example, with a linked list, after removing an item the ‘next’ and ‘succ’ fields of the link node may (should) not be valid so there’s no way to get to the next item. I ended up fudging around this with lists in monkey2 because the outcry over not being able to remove items while you were iterating through a list from ex-blitz users was just too much to deal with (and because I avoid lists these days anyway). Looks like I fudged stacks too…
The bigger idea here is it’s dangerous to modify a container while you’re iterating through it without being very careful, and the iterator.Erase() approach is one way to do that safely. The compiler can only really do so much to help here without things become very complex/slow as it has to deal with situations like nested eachin loops with the same container (eg: for collision checking) etc. In fact, to do it properly, a container would have to track every iterator to items within the container, which would of course incur significant overhead and be very slow.
It’s just something I don’t do any more, and there are generally lots of alternatives, eg: instead of:
Monkey1234For Local pb:PhysBox = Eachin boxespb.model.Destroy ()boxes.Remove (pb)Next…which wont even work properly due to the ‘skipped items’ issue, you can of course simply go…
Monkey12345For Local pb:PhysBox = Eachin boxespb.model.Destroy ()Nextboxes.Clear()Which works properly and doesn’t involve any potentially slow ‘Remove’ operations.
I also find this useful sometimes (for stacks/deques only):
Monkey12345678While Not stack.Empty'Local item:=stack.Top 'get copy of top itemstack.Pop() 'remove it'item.DestroyItOrWhatever()WendThis also destroys all items in a stack, but it does it in such a way that the stack remains valid at all times so it’s always safe to add items to it at any time in the loop. I use this idea a lot in compilers, as they frequently have to deal with ‘todo’ lists and this is a nice way to process a todo list.
January 11, 2018 at 11:06 pm #12821I ran into this problem when using C#. One of the methods was to go through the list backwards and remove what you want that way.
Apologies if this is not the best method but it is something that worked for me.
January 12, 2018 at 3:26 am #12823Interesting read! I was wondering why it worked with lists (in Blitz), and noticed they were also ‘failing’ in mx2 the way stacks do. (I’d tried switching the above code to a list.)
The pb.Destroy () / boxes.Clear () option works well here for the Space-bar hit, but what would be the best way to handle removing an object mid-iteration, as UpdateBoxes () — minus boxes.Remove (pb) — still crashes, obviously for the reasons you’ve explained, since it’s not emptying the whole stack like Space does.
Thinking about it, I suppose a stack isn’t the best solution for this scenario, ie. removing arbitrary objects from the middle of a collection, since stacks are all about adding/removing at the top of the stack, but what would be better here?
(I just used a stack because I gather they’re quicker than lists!)
That stack-top popping-copying thing is pretty cool, but I guess maybe a map could be a better overall solution?
January 12, 2018 at 3:33 am #12824Are you afraid of iterators?
My example above is an analogue of native Eachin.
I think it’s the fastest and easiest way.
January 12, 2018 at 3:58 am #12825Are you afraid of iterators?
A little bit maybe! Can never quite remember the syntax…
(I’d tried switching the above code to a list.)
Strange, you should be able to remove-while-you iterate through lists, eg:
Monkey1234567891011121314151617181920212223#Import "<std>"Using std..Function Main()Local list:=New IntListFor Local i:=0 Until 10list.Add( i )NextPrint list.Count() '10?For Local it:=Eachin listlist.Remove( it )NextPrint list.Count() '0?EndThis is really easy to ‘hack’ into lists, but not into stacks. Either way, it offends my sensibilities as a gentleman programmer so I don’t do that any more! But I do get why it’s popular, it’s probably the easiest to grasp even if it is inefficient and error prone.
what would be the best way to handle removing an object mid-iteration
There are several ways to approach this, including:
- Use iterator methods Bump() and Erase() to do it the ‘nice’ way.
- Use a separate ‘kill’ list containing items you want to destroy later. Once you’ve gone through the main ‘live’ list, iterate through the kill list and kill anything there from the live list.
- Use some other far out method, eg:
Monkey12345678910111213Local put:=0For Local get:=0 Until stack.Length'update returns false to remove from stack...'If Not stack[get].Update() Continue'still alive...stack[put]=stack[get]put+=1Nextstack.Resize( put )This effectively does a simultaneous iterate/erase/compact pass. It’s based on the idea of ‘double buffering’ containers, another approach where you build the ‘next’ live list while processing the ‘current’ one, and then swap them afterwards.
And last but not least, the recommend way using iterators:
Monkey12345678910111213141516171819202122232425262728293031323334#Import "<std>"Using std..Function Main()Local list:=New IntListFor Local i:=0 Until 10list.Add( i )NextLocal it:=list.All()While Not it.AtEndIf it.Current & 1 'remove odd integers...it.Erase()Elseit.Bump()EndifWendFor Local i:=Eachin listPrint inextEndJanuary 12, 2018 at 4:22 am #12826Very nice explanation to be article-ized.
January 12, 2018 at 7:11 pm #12831Yeah, that’s great, lots of options there. Even the iterator seems to makes sense… at first glance! Will play…
January 14, 2018 at 4:04 pm #12859Just posting working versions with List and Stack (manual iteration) variants… quite different code needed for each! (For quick reference, the Game class’s boxes field is the container in both cases.)
List:
Monkey123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286#Import "<std>"#Import "<mojo>"#Import "<mojo3d>"Using std..Using mojo..Using mojo3d..Const SPEW_BOXES:Int = 100 ' How many boxes to add to sceneClass PhysBoxClass PhysParamsField mass:FloatField group:ShortField mask:ShortEndField box:BoxfField model:ModelField collider:BoxColliderField body:RigidBodyField init:PhysParamsMethod New (width:Float = 1, height:Float = 1, depth:Float = 1, mass:Float = 1, material:Material = Null, group:Int = 1, mask:Int = 1)' Store setup params for PhysBox.Start ()init = New PhysParamsinit.mass = massinit.group = groupinit.mask = maskIf Not materialmaterial = New PbrMaterial (Color.Red)Endifbox = New Boxf (-width * 0.5, -height * 0.5, -depth * 0.5, width * 0.5, height * 0.5, depth * 0.5)model = Model.CreateBox (box, 8, 8, 8, material)EndMethod Start ()collider = New BoxCollider (model)body = New RigidBody (model)collider.Box = boxbody.Mass = init.massbody.CollisionGroup = init.groupbody.CollisionMask = init.maskbox = Nullinit = NullEndMethod Move (x:Float, y:Float, z:Float)model.Move (x, y, z)EndMethod Rotate (pitch:Float, roll:Float, yaw:Float, localspace:Bool = False)model.Rotate (pitch, roll, yaw, localspace)EndEndClass Game Extends WindowConst CAMERA_MOVE:Float = 0.05Const CAMERA_BOOST:Float = 4.0Field cam_boost:Float = 1.0Field scene:SceneField cam:CameraField light:LightField ground:PhysBoxField boxes:List <PhysBox>Method New (title:String, width:Int, height:Int, flags:WindowFlags)Super.New (title, width, height, flags)SwapInterval = 1CreateArena (15)EndMethod CreateArena:Void (ground_size:Float = 100)SeedRnd (Millisecs ())Local pm:PbrMaterial = New PbrMaterial (New Color (0, 1, 0, 0.25))pm.BlendMode = BlendMode.Alphascene = Scene.GetCurrent ()ground = New PhysBox (ground_size, 1, ground_size, 0, pm)'New PbrMaterial (Color.Green * 0.25))cam = New Cameralight = New Lightscene.AmbientLight = Color.White * 0.75scene.ClearColor = Color.Sky * 0.75cam.FOV = 100cam.Move (0, 20, -20)ground.Move (0, -5, 0)ground.Start ()cam.Near = 0.01cam.Far = 1000light.CastsShadow = Truelight.Range = 1000light.Move (0, 50, 10)cam.PointAt (ground.model)light.PointAt (ground.model)SpewBoxes ()EndMethod SpewBoxes (num:Int = SPEW_BOXES)boxes = New List <PhysBox>For Local loop:Int = 1 To numLocal scale:Float = Rnd (0.5, 4.0)Local color:Color = New Color (Rnd (0.4, 1.0), Rnd (0.4, 1.0), Rnd (0.4, 1.0))' Just for clarity in New below...Local dimension:Float = scaleLocal mass:Float = scale' Create new PhysBox...Local pb:PhysBox = New PhysBox (dimension, dimension, dimension, mass, New PbrMaterial (color))' Position PhysBox...pb.Move (Rnd (-10, 10), Rnd (10, 100), Rnd (-10, 10))pb.Rotate (Rnd (360), Rnd (360), Rnd (360))' Start its physics...pb.Start ()boxes.Add (pb)NextEndMethod UpdateBoxes ()For Local pb:PhysBox = Eachin boxesIf pb.model.Y < -20pb.model.Scale = pb.model.Scale * 0.75If pb.model.Scale.x < 0.01pb.model.Destroy ()boxes.Remove (pb)EndifEndifNextEndMethod UpdateGame ()UpdateBoxes ()If Keyboard.KeyHit (Key.Escape)App.Terminate ()EndifIf Keyboard.KeyHit (Key.S)light.CastsShadow = Not light.CastsShadowEndifIf Keyboard.KeyHit (Key.Space)For Local pb:PhysBox = Eachin boxespb.model.Destroy ()boxes.Remove (pb)NextSpewBoxes ()EndifIf Keyboard.KeyDown (Key.LeftShift)cam_boost = CAMERA_BOOSTElsecam_boost = 1.0EndifIf Keyboard.KeyDown (Key.A)cam.Move (0.0, 0.0, CAMERA_MOVE * cam_boost)EndifIf Keyboard.KeyDown (Key.Z)cam.Move (0.0, 0.0, -CAMERA_MOVE * cam_boost)EndifIf Keyboard.KeyDown (Key.Left)cam.Rotate (0.0, 1.0, 0.0)EndifIf Keyboard.KeyDown (Key.Right)cam.Rotate (0.0, -1.0, 0.0)EndifIf Keyboard.KeyDown (Key.Up)cam.Rotate (1.0, 0.0, 0.0, True)EndifIf Keyboard.KeyDown (Key.Down)cam.Rotate (-1.0, 0.0, 0.0, True)EndifEndMethod ShadowText:Void (canvas:Canvas, s:String, x:Float, y:Float)canvas.Color = Color.Blackcanvas.DrawText (s, x + 1, y + 1)canvas.Color = Color.Whitecanvas.DrawText (s, x, y)EndMethod RenderText (canvas:Canvas)ShadowText (canvas, "FPS: " + App.FPS, 20.0, 20.0)ShadowText (canvas, "A/Z + Cursors to move camera", 20.0, 40.0)ShadowText (canvas, "SHIFT to boost", 20.0, 60.0)ShadowText (canvas, "SPACE to spew boxes", 20.0, 80.0)ShadowText (canvas, "S to toggle shadows", 20.0, 100.0)ShadowText (canvas, "Boxes: " + boxes.Count (), 20.0, 140.0)EndMethod OnRender (canvas:Canvas) OverrideUpdateGame ()RequestRender ()scene.Update ()scene.Render (canvas, cam)RenderText (canvas)EndEndFunction Run3D (title:String, width:Int, height:Int, flags:WindowFlags = WindowFlags.Center)New AppInstanceNew Game (title, width, height, flags)App.Run ()EndFunction Main ()Run3D ("3D Scene", 960, 540, WindowFlags.Center) ' 1/4 HD!' Run3D ("3D Scene", 1920, 1080, WindowFlags.Fullscreen)EndStack:
Monkey123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310#Import "<std>"#Import "<mojo>"#Import "<mojo3d>"Using std..Using mojo..Using mojo3d..Const SPEW_BOXES:Int = 100 ' How many boxes to add to sceneClass PhysBoxClass PhysParamsField mass:FloatField group:ShortField mask:ShortEndField box:BoxfField model:ModelField collider:BoxColliderField body:RigidBodyField init:PhysParamsMethod New (width:Float = 1, height:Float = 1, depth:Float = 1, mass:Float = 1, material:Material = Null, group:Int = 1, mask:Int = 1)' Store setup params for PhysBox.Start ()init = New PhysParamsinit.mass = massinit.group = groupinit.mask = maskIf Not materialmaterial = New PbrMaterial (Color.Red)Endifbox = New Boxf (-width * 0.5, -height * 0.5, -depth * 0.5, width * 0.5, height * 0.5, depth * 0.5)model = Model.CreateBox (box, 8, 8, 8, material)EndMethod Start ()collider = New BoxCollider (model)body = New RigidBody (model)collider.Box = boxbody.Mass = init.massbody.CollisionGroup = init.groupbody.CollisionMask = init.maskbox = Nullinit = NullEndMethod Move (x:Float, y:Float, z:Float)model.Move (x, y, z)EndMethod Rotate (pitch:Float, roll:Float, yaw:Float, localspace:Bool = False)model.Rotate (pitch, roll, yaw, localspace)EndEndClass Game Extends WindowConst CAMERA_MOVE:Float = 0.05Const CAMERA_BOOST:Float = 4.0Field cam_boost:Float = 1.0Field scene:SceneField cam:CameraField light:LightField ground:PhysBoxField boxes:Stack <PhysBox>Method New (title:String, width:Int, height:Int, flags:WindowFlags)Super.New (title, width, height, flags)SwapInterval = 1CreateArena (15)EndMethod CreateArena:Void (ground_size:Float = 100)SeedRnd (Millisecs ())Local pm:PbrMaterial = New PbrMaterial (New Color (0, 1, 0, 0.25))pm.BlendMode = BlendMode.Alphascene = Scene.GetCurrent ()ground = New PhysBox (ground_size, 1, ground_size, 0, pm)'New PbrMaterial (Color.Green * 0.25))cam = New Cameralight = New Lightscene.AmbientLight = Color.White * 0.75scene.ClearColor = Color.Sky * 0.75cam.FOV = 100cam.Move (0, 20, -20)ground.Move (0, -5, 0)ground.Start ()cam.Near = 0.01cam.Far = 1000light.CastsShadow = Truelight.Range = 1000light.Move (0, 50, 10)cam.PointAt (ground.model)light.PointAt (ground.model)SpewBoxes ()EndMethod SpewBoxes (num:Int = SPEW_BOXES)boxes = New Stack <PhysBox>For Local loop:Int = 1 To numLocal scale:Float = Rnd (0.5, 4.0)Local color:Color = New Color (Rnd (0.4, 1.0), Rnd (0.4, 1.0), Rnd (0.4, 1.0))' Just for clarity in New below...Local dimension:Float = scaleLocal mass:Float = scale' Create new PhysBox...Local pb:PhysBox = New PhysBox (dimension, dimension, dimension, mass, New PbrMaterial (color))' Position PhysBox...pb.Move (Rnd (-10, 10), Rnd (10, 100), Rnd (-10, 10))pb.Rotate (Rnd (360), Rnd (360), Rnd (360))' Start its physics...pb.Start ()boxes.Add (pb)NextEndMethod UpdateBoxes ()Local iter:Stack <PhysBox>.IteratorLocal pb:PhysBoxiter = boxes.All ()While Not iter.AtEndpb = iter.CurrentIf pb.model.Y < -20pb.model.Scale = pb.model.Scale * 0.75If pb.model.Scale.x < 0.01pb.model.Destroy ()iter.Erase ()Elseiter.Bump ()EndifElseiter.Bump ()EndifWendEndMethod UpdateGame ()UpdateBoxes ()If Keyboard.KeyHit (Key.Escape)App.Terminate ()EndifIf Keyboard.KeyHit (Key.S)light.CastsShadow = Not light.CastsShadowEndifIf Keyboard.KeyHit (Key.Space)Local pb:PhysBoxLocal iter:Stack <PhysBox>.Iteratoriter = boxes.All ()While Not iter.AtEndpb = iter.Currentpb.model.Destroy ()iter.Erase ()Wend' For Local pb:PhysBox = Eachin boxes' pb.model.Destroy ()' boxes.Remove (pb)' NextSpewBoxes ()EndifIf Keyboard.KeyDown (Key.LeftShift)cam_boost = CAMERA_BOOSTElsecam_boost = 1.0EndifIf Keyboard.KeyDown (Key.A)cam.Move (0.0, 0.0, CAMERA_MOVE * cam_boost)EndifIf Keyboard.KeyDown (Key.Z)cam.Move (0.0, 0.0, -CAMERA_MOVE * cam_boost)EndifIf Keyboard.KeyDown (Key.Left)cam.Rotate (0.0, 1.0, 0.0)EndifIf Keyboard.KeyDown (Key.Right)cam.Rotate (0.0, -1.0, 0.0)EndifIf Keyboard.KeyDown (Key.Up)cam.Rotate (1.0, 0.0, 0.0, True)EndifIf Keyboard.KeyDown (Key.Down)cam.Rotate (-1.0, 0.0, 0.0, True)EndifEndMethod ShadowText:Void (canvas:Canvas, s:String, x:Float, y:Float)canvas.Color = Color.Blackcanvas.DrawText (s, x + 1, y + 1)canvas.Color = Color.Whitecanvas.DrawText (s, x, y)EndMethod RenderText (canvas:Canvas)ShadowText (canvas, "FPS: " + App.FPS, 20.0, 20.0)ShadowText (canvas, "A/Z + Cursors to move camera", 20.0, 40.0)ShadowText (canvas, "SHIFT to boost", 20.0, 60.0)ShadowText (canvas, "SPACE to spew boxes", 20.0, 80.0)ShadowText (canvas, "S to toggle shadows", 20.0, 100.0)ShadowText (canvas, "Boxes: " + boxes.Length, 20.0, 140.0)EndMethod OnRender (canvas:Canvas) OverrideUpdateGame ()RequestRender ()scene.Update ()scene.Render (canvas, cam)RenderText (canvas)EndEndFunction Run3D (title:String, width:Int, height:Int, flags:WindowFlags = WindowFlags.Center)New AppInstanceNew Game (title, width, height, flags)App.Run ()EndFunction Main ()Run3D ("3D Scene", 960, 540, WindowFlags.Center) ' 1/4 HD!' Run3D ("3D Scene", 1920, 1080, WindowFlags.Fullscreen)End(Found a cooler remove effect than alpha!)
January 14, 2018 at 4:41 pm #12860You cat to simplify a bit logic with iterator:
Monkey123456789101112131415161718192021222324252627282930' current variantIf pb.model.Y < -20pb.model.Scale = pb.model.Scale * 0.75If pb.model.Scale.x < 0.01pb.model.Destroy ()iter.Erase ()Elseiter.Bump ()EndifElseiter.Bump ()Endif' new variantIf pb.model.Y < -20pb.model.Scale = pb.model.Scale * 0.75If pb.model.Scale.x < 0.01pb.model.Destroy ()iter.Erase ()ContinueEndifEndifiter.Bump ()January 14, 2018 at 10:47 pm #12863Nice, thanks nerobot.
-
AuthorPosts
You must be logged in to reply to this topic.