ReleaseChildren()

Blitz3D Forums/Blitz3D Programming/ReleaseChildren()

K(Posted 2013) [#1]
Function ReleaseChildren(entity)
 For k=1To CountChildren(entity)
  EntityParent GetChild(entity,k),0
 Next
End Function

What's wrong with this code? Always fails to get rid of them all.


Kryzon(Posted 2013) [#2]
Heh, cool trick. I was under the same impression for a while, then it hit me.

1) When you release a child, ALL the children stack goes down one level.

2) If you keep the CountChildren function directly as the "To" parameter in the FOR loop, it will update the final value every cycle and won't behave properly. When k = [half the original amount of children], CountChildren() will also yield [half the original amount of children] and so the loop will stop because the "From" value equals the "To", even though there are half children left to be unlinked.

So it should be like this:
Function ReleaseChildren(entity)
	Local childAmount = CountChildren(entity)
	
	For k = 1 To childAmount ;Always the same 'To' value.
		EntityParent GetChild(entity, 1), 0 ;Always the same child index.
	Next
End Function


Last edited 2013


K(Posted 2013) [#3]
Okay, thank you very much. I spent two hours trying to work something else up. I've been tip-toeing around the finer points of my quad system interacting with my particle system.


Bobysait(Posted 2013) [#4]
you can use countchildren in a while statement
While countchildren(entity):EntityParent getchild(entity,1),0:wend


or reverse the loop (start from the end)
for i = CountChildren(entity) to 1 step -1
   EntityParent getChild(entity,i),0
next



Yasha(Posted 2013) [#5]
I hope you're storing those child entities' pointers somewhere, or that's a lot of lost entities cluttering up your scene.


Bobysait(Posted 2013) [#6]
That's true, and the topic is named "ReleaseChildren".
Actually, it does not release anything, it just detach children from the parents.

Function ReleaseChildren(entity%)
   While CountChildren(entity)
      FreeEntity GetChild(entity,1)
   Wend
End Function

This code will really release the children.


Matty(Posted 2013) [#7]
@Bobysait - not really necessary...free the root parent should also free the child entities.....


Kryzon(Posted 2013) [#8]
Good call on that While statement, it's very elegant.


Bobysait(Posted 2013) [#9]
@Matty : as he's looking for a "Release children" function, he might probably want the root to be kept alive.


Axel Wheeler(Posted 2013) [#10]
So actually there were two problems at the same time (as there so often are). One was the decreasing value of CountChildren(), and one was that once the first child is released, the next child becomes child number 1, so if you increment k you are skipping every other child. (I guess they're different ends of the same problem). So the FreeEntity must always free child number 1, or always the last child (same as the CountChildren() value). These are basically BobySait's solutions.

I would think it would have been better to just have the To expression set to a fixed value in Blitz - i.e. called only at the beginning of the loop. I'm sure there are theoretical uses for recalculating it each pass, but they must be dwarfed by the number of bugs it causes. Can anyone think of a valid use of this behavior? Beyond academic? And it's taking extra cycles to call the function each pass.

I can't blame Blitz, of course; apparently it's consistent with other languages. I'm just wondering why it's done that way. They could always have a RFor command (Recalculated For) for those folks who really want it.

EDIT: Corrected RIF to RFOR


Axel Wheeler(Posted 2013) [#11]
Just to follow up on those wasted cycles, I just ran a test comparing a For loop done both ways. With 100000 iterations, it took 0 ms to run the loop with the To value precalculated, it took 143084 ms to run it with the calculation done each time.

The thing is, so many people don't know that it evaluates the expression each step; I have known it and forgotten it. it's not obvious from the syntax, nor is it in the documentation of the If or To commands (which is documented separately, interestingly).

I mean, we often see examples of "For i =1 to CountSurfaces()" and the like. I do it all the time. These are actually poorly written. The value should be precalculated.

Anyway, I'll stop wingeing now!

Here's my test (with a smaller value):




Bobysait(Posted 2013) [#12]
Actually for surface management, I always store local values for the For/Next loop
for exemple, it allows to go from vertice 0 to N-1 without the need of the "-1" for each loop

But for something like a "DetachChildren" thing, I wish it is not called often in the program ... I can't see a robust engine requiring to unparent entites on each loop (each child will have its global matrix "re-calculated" so as its children) it is IMHO a trick, but for sure, it is all but a good code.
So : when you have some functions that you won't call very often, you don't really care about the accuracy. (actually, it's a waste of time for the coder, nothing more)

but anyway, if you want a precalculated thing :

Function DetachChildren(entity,newparent=0)
 Local nc = countchildren(entity)
 for i = 1 to nc
   entityparent getchild(entity,1),newparent
 next
end function


it's robust, pretty accurate and allows to "re-parent" to an other entity at the same time ;)



by the way :
in a "For ...= To " loop, the second condition is checked at each loop, BUT the "start" value isn't

it's almost the same for every languages
for (iterator=startvalue; ExitCondition;Iterator_Iterate)

startvalue is fixed, Exitcondition is checked, iterator_iterate is fixed (in blitz, it is a transparent value, default is +1, but you can specify it with Step CONST_VALUE)

start=1
For i = start To 2
	start=start-1
	n=n+1
Next
Print n
WaitKey
End


Here, you can see, if you modify start, the loop won't change, because once the loop is initialized, the start variable becomes useless.

endvalue=2
For i = 1 To endvalue
	endvalue=endvalue-1
	n=n+1
Next
Print n
WaitKey
End

but when you modified the exit condition of the For statement, you modified it in realtime
-> here, the result is "1" where it should have been "2".

This is actually very convinient and a clever way to do lots of stuff without the needs of special If ... Then Exit inside the loop.


Axel Wheeler(Posted 2013) [#13]
(I corrected RIF to RFOR in my earlier post which is what I meant).

Bobysait

This is actually very convinient and a clever way to do lots of stuff without the needs of special If ... Then Exit inside the loop.


As far as modifying the exit condition during the loop, I haven't seen any code on here where anybody has used such a technique (although I certainly haven't seen everything in the code archives by a big stretch. But I've seen plenty of variations on For..To Count...()

Thanks for the great examples. I get that the exit condition must be checked each time through the loop, but even in the description of For in most languages there seems to be no explicit statement or warning that the expression in that condition will be re-evaluated, only that it will be checked.

http://msdn.microsoft.com/en-us/library/ch45axte.aspx

http://docs.oracle.com/javase/tutorial/java/nutsandbolts/for.html


K(Posted 2013) [#14]
Hello Fellas, I'm back for a quick stop in... surprised to see this on top. This is a means of keeping particles in play when emitters are deleted. I.e. fire from the fireball 'bullet'.

Regarding Yasha's concern, the parent pointers are stored in .Bullet system, where the particle pointers are in the .Particle system, and may perchance be entities registerd in the .Quad system. Since Bullets and Particles may encounter different event criterion to terminate, the need to separate roots from children allows for more streamlined, one-size-fits every combo of Particle with Bullet/Puzzle node scenario.

Hope that clears up confusion.
-K


Axel Wheeler(Posted 2013) [#15]
Hi K.

Are .Bullet, .Quad and .Particle your own labels for your systems, or are you referring to libraries in the code archives and such?

I would tend to avoid parenting particles, quads, whatever to anything else, since that way madness lies. For bullets that need to keep track of their target, I only store the target itself in the bullet type, and forget about the source, which is irrelevant. Info like the damage it does is copied into the bullet type on creation.

Then I only have to check that the target exists before checking for collision. (This is based on my decision not to do full collision checking for every possible target. Just takes too long. Only the intended target can be hit. But don't tell the other targets that ... :)


Kryzon(Posted 2013) [#16]
I think he means .Bullet etc. as in 'user types'.

"b.Bullet = New Bullet" and such.


Bobysait(Posted 2013) [#17]
As far as modifying the exit condition during the loop, I haven't seen any code on here where anybody has used such a technique (although I certainly haven't seen everything in the code archives by a big stretch. But I've seen plenty of variations on For..To Count...()


Actually, in blitz, it's probably not very usefull, but in C/C++ it is.
I think Blitz at compile time is interpreted in some language (probably C or some Object thing) where the For/Next is translated as something like "for(i=start;i<end;i++)" then the "exit-condition" is computed for each loop because of its behavior in the interpreted thing.
Don't know if I'm clear ...


Axel Wheeler(Posted 2013) [#18]
Very clear. Both of you. Thanks. This is a useful thread.