Notifications
Clear all

[Closed] random not working correctly

Hi, I have a simple script here which does basically create 10 Spheres with random radius between two point helpers.

(
	clearListener()
	if $a != undefined do delete $a
	if $b != undefined do delete $b
	
	local a = point pos:[0,0,0] name:"a" wirecolor:red
	local b = point pos:[50,50,50] name: "b" wirecolor:red


	
	function macher  = (
		delete $Kugel*

		for i=1 to 10 do (
			kugel = sphere radius: (random 1.0 10.0) pos: (random a.pos b.pos) wirecolor:green name:"Kugel"
			
			counter =  i as string
			kugelname = "Kugel"
			kugel.name = kugelname+counter
		)
	)
	
	macher()
	
	when transform a changes do (macher())
	when transform b changes do (macher())
)

Now when i press ctrl-E it all works fine.

But as soon as i change the position of one pint helper, all spheres gets created at 0,0,0 istead of random point between those two points.

3 Replies

funny if you type $.pos = [100.0,100.0,100.0] in the listener with point b selected it works

Welcome to the wonderful world of change handlers!

First of all, I would not advise doing what you are doing. Instead of recreating the spheres on each change of the point helpers, why don’t you just update their positions and radii? It also solves your problem with the zero positions. What I think happens is that when you create an object inside a function called by the when construct, Max’ undo buffer is in a special state. In fact, the function is being called twice for every slight change in the mouse position – once when the last change is undone, once when the new change is applied. Example: Point helper is at 50,50,50. You move it with the mouse to 51,50,50 – your macher() function is called twice and the new position is 51,50,50. You now move further to 52,50,50 – Max calls an undo and brings the Point back to 50,50,50 (and calls your function) and then it updates the position to 52,50,50 (and calls your function). You continue to move the mouse and Max keeps on doing an undo and a redo, calling your function twice. You can see this by adding debug prints to macher().
Looks like the new positions of the spheres just don’t stick around when the undo buffer is being manipulated that way, because you are creating new objects within the function. So the undo buffer gets their initial positions 0,0,0 and discards the changes you made to the position controller.

Whenever you use a when() construct, it is a good idea to supply a handleAt:#redrawViews
statement to ensure that the function is only called when the viewports are finally redrawn, otherwise you can get the multiple calls described above. If you handle at #redrawViews, the spheres won’t be moved around at all while you are moving the mouse until you release the mouse button. Then they will snap in place as they should. But this is optional.

Also note that you don’t need two when constructs to monitor the two helpers, one can do the job too.

Here is an updated version of your code that just changes the positions without recreating the spheres:

(
	clearListener()
	if $a != undefined do delete $a
	if $b != undefined do delete $b
	
	local a = point pos:[0,0,0] name:"a" wirecolor:red
	local b = point pos:[50,50,50] name: "b" wirecolor:red


	function macher  = (
		delete $Kugel*

		for i=1 to 10 do (
			kugel = sphere radius: (random 1.0 10.0) pos: (random a.pos b.pos) wirecolor:green name:"Kugel"
			kugelname = "Kugel"
			counter =  i as string
			kugel.name = kugelname+counter
		)
	)
	
	function updater =
	(
		for o in $Kugel* do 
		(
			o.radius = (random 1.0 10.0) 
			o.pos = (random a.pos b.pos)
		)
	)
	
	macher()
	
	when transform #(a,b) changes do (updater()) 
	--when transform #(a,b) changes handleAt:#redrawViews do (updater())	 --alternative
)

Thanks Bobo, that helped me a lot