MXS -- Some wierd stuff happening

Hi,
(especially Zhaltkis and Theodox)

I have done this script of Rubik’s cube game in max. I am doing this like selecting the cubes on position basis, and rotating them by picking the directions arrow objects. It works good for the first time and in a weird way from the second time onwards i think. I think the center cube of the selected array is rotated by 90 in y axis. Or some thing else… any suggestions to fix the problem.

the code goes like this

Undo off
Rollout rubixCube "Rubix Cube"
(
	local objs_ifCol = #()
	local objs_ifRow = #()
	local objs_ifCol_Y = #()
	----- UI Elements -----
	group "Instructions"
	(
		label msg "Click on any cube and" 
		label msg1 "click on Arrow Objects to rotate"
		)
	group "Direction"
	(
		radiobuttons vnh labels:#("Vertical", "Horizontal")
		)
	group "Rotation Direction"
	(
		pickbutton pickbtn "Pick directional arrow" 
		)
	----- Colors for the cubes --------
	local colArr = #(red,green,blue,black,white,orange)
	----- Creating The Rubix Cube -----
	fn rubixCub = 
	(
		for i=0 to 2 do
		(
			for j = 0 to 2 do
			(
				for k = 0 to 2 do
				(
					local cuBox = box width:15 length:15 height:15
					cuBox.pos =  [i*15,j*15,k*15]
					cuBox.material = meditMaterials [1]
					convertTopoly cuBox
					polyop.chamferEdges cuBox #{1..12} 0.25
					centerpivot cuBox
					)
				)
			)
		rubCubMat = meditMaterials [1] = multiMaterial numsubs:6 -- Assigning Multi Sub Object Material
		for i =1 to rubCubMat.numsubs do
		(
			rubCubMat.material[i].shaderType = 0
			rubCubMat.material[i].diffuse = colArr[i]
			rubCubMat.material[i].specularLevel = 50
			rubCubMat.material[i].glossiness = 60
			)
		select $*
		$.material = rubCubMat
		/*objForRot = for o in selection collect o
		(
			for i = 1 to objForRot.count do
			(
				rotate objForRot[i] (angleAxis (i*90)[1,0,0])
				)
			)*/
		group selection name:"cubGrp"
		$cubGrp.pos = [0,0,20]
		ungroup $cubGrp
		deselect $*		
		)
	fn dirArrows = 
	(
		for i in 0 to 3 do
		(
			arws= helix radius1:5 radius2:0 height:15 prefix:"Arw_" turns:10 sides:3
			arws.pivot = [0,0,0]
			arws.render_displayRenderMesh = true
			arws.Thickness = .5
			move arws [0,60,20]
			in coordsys world arws.rotation  = (eulerAngles 0 0 (i*90))
			in coordsys local arws.rotation = (eulerangles 90 0 0)
			)
		)
	fn SelCubes = 
	(
		if ($ != undefined) then
		(
			selobjX = $.pos.x
			selobjY = $.pos.y
			selobjz = $.pos.z
			objs_ifRow = for o in geometry where o.pos.z == selobjZ collect o
			objs_ifCol = for o in geometry where o.pos.x == selobjX collect o
			objs_ifCol_Y= for o in geometry where o.pos.y == selobjY collect o
			)
		else messagebox "Please Select a cube"
		)
	on rubixCube open do
	(
		rubixCub ()
		dirArrows ()		
		)
	on pickbtn picked obj do
	(
		SelCubes()
		case vnh.state of
		(
			1:(
					if ($Arw_001 == obj) then 
					(
						select objs_ifCol
						in coordsys world rotate objs_ifCol (angleAxis 90 [-1,0,0])
						deselect $
						)
					if ($Arw_003 == obj) then 
					(
						select objs_ifCol
						in coordsys world rotate objs_ifCol (angleAxis 90 [1,0,0])
						deselect $
						)
					if ($Arw_002 == obj) then 
					(
						select objs_ifCol_Y
						in coordsys world rotate objs_ifCol_Y (angleAxis 90 [0,1,0])
						deselect $
						)
					if ($Arw_004 == obj) then 
					(
						select objs_ifCol_Y
						in coordsys world rotate objs_ifCol_Y (angleAxis 90 [0,-1,0])
						deselect $
						)
					)
			2:(
					if ($Arw_001 == obj) then 
					(
						select objs_ifRow
						in coordsys world rotate objs_ifRow (angleAxis 90 [0,0,1])
						deselect $
						)
					if ($Arw_003 == obj) then 
					(
						select objs_ifRow
						in coordsys world rotate objs_ifRow (angleAxis 90 [0,0,-1])
						deselect $
						)
					if ($Arw_002 == obj) then 
					(
						select objs_ifRow
						in coordsys world rotate objs_ifRow (angleAxis 90 [0,0,1])
						deselect $
						)
					if ($Arw_004 == obj) then 
					(
						select objs_ifRow
						in coordsys world rotate objs_ifRow (angleAxis 90 [0,0,-1])
						deselect $
						)
					)		
			)
		)
	on rubixCube close do
	(
		delete objects
		)
	)
	
createDialog rubixCube width:200
	

hmm… tough to visualize the way this works without a copy of max. Maybe you should use a small tolerance instead of == in the functions which pick objects by X, Y or Z rank? If the rotation matrix has too much floating point error you might not be picking all the cubes you want. A debug print on every selection would confirm that, at least.

Yes, I tried not exactly debugging thru print but commented off the unselect so made sure the cubes are selected perfectly. It has some problem some where regarding the rotation i believe. Or by the tiniest chance that the problem lies with the materials… :frowning:

Well, you are rotating the objects around their respective pivots, rotate them about the center instead. I’ve taken the liberty of simplifying it a bit (not sure why but the polyop.chamferEdges command kept throwing errors on me, anyway I switched to a modifier instead). Also the UI is quite a bit rough around the edges but the idea should be clear:

try destroyDialog rubixCube catch()
rollout rubixCube "Rubik's Cube" width:200
(
	group "Instructions"
	(
		label msg "Click on any cube and
click on Arrow Objects to rotate" height:30 align:#left
	)
	radioButtons rbAxis "Rotation Axis: " columns:1 labels:#("X", "Y", "Z") align:#left across:2
	radioButtons rbDirection "Rotation Direction: " columns:1 labels:#("Clockwise", "Counterclockwise")
	button btnRotate "Rotate" offset:[0,10] width:150 height:25

	local axes = #(x_axis, y_axis, z_axis)
	local colors = #(red, green, blue, black, white, orange)
	local rubikMat = multiMaterial numSubs:6
	local baseMat = standardMaterial shaderType:0 specularLevel:50 glossiness:60
	local baseBox = createInstance box width:15 length:15 height:15 fillet:1
	local chamferMod = meshSmooth name:"Chamfer" iterations:1 subdivMethod:0 strength:0 relax:0.1 isolineDisplay:false
	local center, boxes = #()

	fn getBoxes val axisIndex =
		for b in boxes where close_enough b.pos[axisIndex] val 10 collect b

	fn getDirection =
		3 - 2 * rbDirection.state

	on rubixCube open do
	(
		center = dummy prefix:"RubixCube" boxSize:[15,15,15]

		for i = 1 to 6 do
			(rubikMat[i] = copy baseMat).diffuse = colors[i]

		for i = -1 to 1 do
			for j = -1 to 1 do
				for k = -1 to 1 do
					append boxes (box prefix:"Rubik" baseObject:baseBox pos:[i*15,j*15,k*15-7.5] material:rubikMat parent:center)

		centerPivot boxes
		addModifier boxes[1] chamferMod
	)

	on rubixCube close do
		try delete (#() + center) catch()

	on btnRotate pressed do
	(
		if selection.count != 1 do
			return messageBox "Select one box only."

		local obj = selection[1]

		if findItem boxes obj == 0 do
			return messageBox "Select only the boxes."

		local axis = rbAxis.state
		local rot = quat (getDirection() * 90) axes[axis]
		local objs = getBoxes obj.pos[axis] axis
		about center rotate objs rot
	)
)
createDialog rubixCube

Ah…Thanks alot Sword Slayer. Works fine. :slight_smile:

And yeah SwordSlayer, can u pls explain the fn getDirection() I am unable to get what it is actually doing.

[QUOTE=KiTechie;23318]And yeah SwordSlayer, can u pls explain the fn getDirection() I am unable to get what it is actually doing.[/QUOTE]

I can try to clarify it.

In this case it could also have been (approximately) written as:


fn getDirection = if rbDirection.state == 1 then 1 else -1

rbDirection is a radiobutton, this one has 2 states/labels: “Clockwise” and “Counterclockwise”. For a radiobutton the .state value holds the index of which of the options is picked; “Clockwise” is 1 “Counterclockwise” is 2, if there was a third one it would’ve had 3 and so on; (if none was picked, it would be 0).
The way Swordslayer did the function is through simple arithmetic: 3 - 21 = 1 (CW) or 3 - 22 = -1 (CCW).

If you look at where it is used below you will see it’s for rotating either 190 = 90 degrees (CW) or -190 = -90 degrees (CCW):


local rot = quat (getDirection() * 90) axes[axis]

That was a good explanation along with your own code as example. Thanks Zhalktis. This code by Swordslayer and the way he puts out the logic with minimal code is osome. Learnt a lot from this. Thanks a bunch guys. :slight_smile: