Game Development Community

Dynamic Orientation/Rotation

by Paul /*Wedge*/ DElia · in Torque Game Engine · 03/19/2004 (10:12 pm) · 10 replies

Is there any way strictly through script to change the direction an object is facing? I've tried setting the orientation of Item Shapebase objects and StaticShape objects I'm dynamically creating, but they always have the default orientation of "0 0 1". Trying to change the .rotation propery of the object rotates the bounding box, but the object itself remains unchanged.

I'm annoyed enough setSkin only works for ShapeBase objects so now I have to use 10 .dts objects instead of 1 for my dynamic damage display... I reallllllly don't want to have to use 20 .dts objects so I can get it facing both ways now.

#1
03/19/2004 (11:00 pm)
It sounds like you're having some serious problems getting the ShapeBase stuff to work. It does work, let me assure you.

You are specifying a rotation, right? That rotation field stores a vector and then a rotation in degrees around it. So if you wanted to rotate around the Z axis (ie, up), you'd say "0 0 1 90".

setSkin can also work, though you might have to debug or tweak a bit.
#2
03/20/2004 (12:10 am)
Argh!!! If only that wasn't the first time I've forgotten that... about the rotation that is. But you can't use setSkin on a StaticShape, can you? I've gotten it working on players (ShapeBase type), but not on a StaticShape.

Anyway... so how would you derive such an angle from a vector then? That's all I really need to do to make my RPG style damage function complete =).
function DamageDisplay(%obj, %damage)
{
	//Final Fantasy damage cap =)
	if(%damage > 9999)
		%damage = 9999;
	
	//decimal damage values make a big mess 
	%damage = mFloor(%damage);
	
	%length = strlen(%damage);
	for(%i = 0; %i < %length; %i++)
	{
		
		//get the number texture (they are named set0, set1, etc.)
		%numset = "set" @ getSubStr(%damage, %i, 1);
		
		//This could be derived from a custom value of the player datablock for specific values
		%offsetZ = 2;
		
		//I dunno if this is the best way to do it, but this assures the numbers will be centered and aligned
		%offsetBase = (%length - (%i+0.5)) - %length/2;
		
		//facing vector of the damaged object
		//assuming it has an EyeVector...
		%vec=VectorNormalize(%obj.getEyeVector());
		
		
		//get the angle the  numbers need to rotate to be facing properly
		%vecX = firstWord(%vec);
		%vecY = firstWord(restWords(%vec));
		%vec = VectorNormalize(%vecX SPC %vecY SPC "0");
		%angle = mRadToDeg(mAtan(%vecX, %vecY));
		error("facing velocity is" SPC %vec);
		      
	      //get a perpendicular vector to the eye vector for scaling the x,y offsets
	      //I got this code from a thread on the forums
	      %zAngle=mDegToRad(-90); 
	      %matrix=MatrixCreateFromEuler( "0 0" SPC %zAngle);
	      %resultVector=MatrixMulVector(%matrix, %vec);
	      %offset = VectorScale(VectorNormalize(%resultVector), %offsetBase );
	      %offsetX = firstWord(%offset);
	      %offsetY = firstWord(restWords(%offset));
	      %offsetX = mCeil(%offsetX*10)/10;
	      %offsetY = mCeil(%offsetY*10)/10;
	      %finaloffset = VectorAdd(%offsetX SPC %offsetY SPC %offsetZ, "0 0 0");
	      
	      //create the actual number
	      %effect = new StaticShape()
	      {
		 datablock = NumberDisplayBase;
		 rotation = "0 0 1" SPC %angle;         
	      };
	      
	      //apply proper number texture
	      %effect.setSkinName(%numset);
	      
	      //apply position
	      %effect.setTransform(VectorAdd(%obj.getWorldBoxCenter(), %finaloffset));
	      
	      
	      //now repeat for the backfacing numbers
	      //mostly the same with a couple changes where noted	      
	      
		
		//inverse rotation for backside
		if(%angle >= 0)
			%angle -= 180;
		else
			%angle += 180;
		//%angle -=180 should work regardless, but you're only supposed to use angle values in 180 ranges I think?
      
	      //reverse display order, so offset goes other direction
	      %zAngle=mDegToRad(90); 
	      %matrix=MatrixCreateFromEuler( "0 0" SPC %zAngle);
	      %resultVector=MatrixMulVector(%matrix, %vec);
	      %offset = VectorScale(VectorNormalize(%resultVector), %offsetBase);
	      %offsetX = firstWord(%offset);
	      %offsetY = firstWord(restWords(%offset));
	      %offsetX = mCeil(%offsetX*10)/10;
	      %offsetY = mCeil(%offsetY*10)/10;
	      %finaloffset = VectorAdd(%offsetX SPC %offsetY SPC %offsetZ, "0 0 0");
	            
	      %reverseeffect = new StaticShape()
	      {
		 datablock = NumberDisplayBase;
		 rotation = "0 0 1" SPC %angle;         
	      };
	      %reverseeffect.setSkinName(%numset);	   
	      %reverseeffect.setTransform(VectorAdd(%obj.getWorldBoxCenter(), %finaloffset));
				
	}	         
	 
}
#4
03/20/2004 (11:58 am)
Yeah I know how to get setSkin working, I went back and tried it with a safer naming convention, and it's working fine now. What I really need to know is how to derive a Z-rotation from the eyeVector of the object, so I can align the values properly.
#5
03/20/2004 (2:32 pm)
The math is a bit tricker. You might have luck looking for a conversion function on the internet.
#6
03/20/2004 (9:46 pm)
Can you set the object to be a billboard? That should keep it aligned with the eye vector but I'm not sure how to do this with torque. I'm just getting started with scripting in torque.

To get an axis angle rotation that will transform (0 0 1) to (eye), just do:

%axis = vectorCross( "0 0 1", %eye );
%ang = mAsin( VectorLen( %axis ) );
%axis = VectorNormalize( %axis );

But a better way is to build a matrix:

%front = %eye
%up = "0 1 0";
%right = VectorNormalize( vectorCross( %up, %front ));
%up = vectorCross( %front, %right);
%matrix = ( %right @ " 0 " @
%up @ " 0 " @
%front @ " 0 " @
"0 0 0 1" );

But I'm not if there is a way to set the node's rotation from a matrix. I haven't tried this code so there I might have the axes mixed up or something, but you get the idea. You also have to make some special cases for when %eye is very close to "0 0 1" in the first example or "0 1 0" in the second example.

Sorry this is pretty vague, hope it helps.

Joel
#7
03/20/2004 (10:20 pm)
I used billboards originally, but obviously if you are looking at those from the wrong side, the numbers get reversed. So I just decided to have it draw once in front and once reversed, even though it won't be effacing everyone, it will always at least be correct.

And I got it working now, I'm an idiot. 3-d scares me, so I was overthinking what is really just basic 2-d math I've used countless times before. If I want to get the proper aligned facing value all I need to do is:
%vec=%obj.getEyeVector();
%vecX = firstWord(%vec);
%vecY = firstWord(restWords(%vec));
%angle = mRadToDeg(mAtan(%vecX, %vecY));
Derive the angle from the x-y values of the eye vector. Duh.

OK yay the final code is up above, this is the biggest thing I've written entirely on my own so far =).

3/21/04 - Fixed a problem with bad alignments when you looking up or down. Optimized code a little.
#8
03/21/2004 (11:13 am)
Congrats ;)
#9
03/25/2004 (10:24 pm)
Oooook I got a new question on the topic. I'm trying to make an opening door. I've seen the resource on it, but that just uses a predone animation and faked collision. I'm trying to actually rotate the door open. I have a very basic setup for it right now... and it half works. The collision of the door rotates, but visually it appears to have never moved! The bounding box doesn't change either, unlike when you rotate an object in the editor. Do I have to call an update function or something to force an update of it's rotation visually?
#10
03/26/2004 (11:42 pm)
Yay figured it out! I can just re-set the position every iteration like:
%obj.setTransform(%obj.getPosition());
and then it updates the rotation value too!