Game Development Community

SetTransform and schedule problems

by Brian Carlson · in Technical Issues · 12/28/2005 (4:00 pm) · 16 replies

Hi, I am really having trouble with schedule and setTransform. I want to use schedule to call a function at a certain time interval. For example, every second, turn a box, or move it. I own Torque, but it's just too much to grasp right now, so I'm working on understanding the examples in the 3DGPAi1 book. There's an example called Turnshape, but it's not actually smooth or consistant, plus its an endless loop which I don't want. I've modified it to repeat a scheduled call to the turnShape within for loop. Here's most of my code:

function TurnShape(%shape, %angle)
{
%xfrm = %shape.getTransform();
%lx = getword(%xfrm,0); // first, get the current transform values
%ly = getword(%xfrm,1);
%lz = getword(%xfrm,2);
%rx = getword(%xfrm,3);
%ry = getword(%xfrm,4);
%rz = getword(%xfrm,5);
%angle += 0.1;
%rd = %angle; //set the rotation angle
%shape.setTransform(%lx SPC %ly SPC %lz SPC %rx SPC %ry SPC %rz SPC %rd);
}

function DoTurnTest()
{
%shape = InsertTestShape();
inbetween(%shape);
}

function inbetween(%shape)
{
for(%i=0;%i<50; %i++)
{
schedule(1000,0,TurnShape, %shape, 0.1);
}
}

DoTurnTest();

//end code


I would really appreciate if someone would help, I've been trying to do something a little more complicated than this, and I've spent a couple full days trying to get it to work right. Thats why I came back to try something more basic. Thanks in advance.

#1
12/28/2005 (6:40 pm)
Maybe you meant for you TurnShape() to look something like this:

function TurnShape(%shape, %delta)
{
%xfrm = %shape.getTransform();
%lx = getword(%xfrm,0); // first, get the current transform values
%ly = getword(%xfrm,1);
%lz = getword(%xfrm,2);
%rx = getword(%xfrm,3);
%ry = getword(%xfrm,4);
%rz = getword(%xfrm,5);
%angle = getword(%xfrm,6);
%angle += %delta;
%rd = %angle; //set the rotation angle
%shape.setTransform(%lx SPC %ly SPC %lz SPC %rx SPC %ry SPC %rz SPC %rd);
}
#2
12/28/2005 (7:02 pm)
Thru torque script i was never able to get it to rotate smoothly. no matter how fine the rotation or how quick the rotation call was made. I think it's cause torquescript doesn't get called every single cycle or something.
#3
12/28/2005 (7:18 pm)
That didn't really help the turning be more smooth, but the real problem is that I can't get schedule and setTransform to work together.
#4
12/28/2005 (7:23 pm)
@Ramen,
Do you think I just start writing my programs in C++ for the most efficient calls and such? Is that what advanced Torque coders do?
#5
12/28/2005 (7:29 pm)
I think the problem is your actually scheduling 50 events to occur 1 second later rather than 50 consecutive events. So the results is going to be a hodgepdge of events, or only one , or something. I'll play with this a little, as I need to do something similar.
#6
12/28/2005 (7:34 pm)
Thanks for the help everyone
#7
12/28/2005 (7:55 pm)
I think your TurnShape function needs to be:

function TurnShape(%shape, %delta, %increments)
{
%xfrm = %shape.getTransform();
%lx = getword(%xfrm,0); // first, get the current transform values
%ly = getword(%xfrm,1);
%lz = getword(%xfrm,2);
%rx = getword(%xfrm,3);
%ry = getword(%xfrm,4);
%rz = getword(%xfrm,5);
%angle = getword(%xfrm,6);
%angle += %delta;
%rd = %angle; //set the rotation angle
%shape.setTransform(%lx SPC %ly SPC %lz SPC %rx SPC %ry SPC %rz SPC %rd);
%increments = %increments-1;
if( %increments )
schedule(10,0,TurnShape, %shape, %delta, %increments);
}


Then to rotate yaw radians in 100 steps do this to start it:

TurnShape(%shape, %yaw/100, 100);

Now the question remains as to how to know when it is finished. You could just schedule a completion routine for the amount of time you expect it to take, in this case 10msec*100 or 1 sec.

Does this help?
#8
12/28/2005 (8:29 pm)
This seems to be a bit over my knowlege of Torque. I think I'll come back to this at a later time when I understand it all a bit more, thanks for your help everyone
#9
12/29/2005 (8:59 am)
Real quick and easy fix to make the original poster's code work better:

function inbetween(%shape)
{
   for(%i=0;%i<50; %i++)
  {
    schedule(1000 * %i ,0,TurnShape, %shape, 0.1);
  }
}

Your issue was as was mentioned in passing by someone else: Your original code was scheduling 50 turn events to all happen at the same time--1 second later...not 50 turnShape events strung out over 50 seconds.

As Tim said, don't give up--you actually were extremely close to the answer on your own, just missed a minor issue!
#10
12/29/2005 (9:34 am)
Wow, you all have been really helpful, but it's just a little too advanced for me at the moment. I thought there would be a quick fix to the problem. I have been reading the Torque documentation with these past few days off. Hopefully I'll be able to understand your help shortly and get things working better. Thanks again.
#11
01/02/2006 (12:51 pm)
Finally, a really good implementation of the above. I had to redo this several times before I got it right; :o)

// rotateShape synopsis:
// Rotate any shape in the xy-plane and schedule a completion script routine.
// This means that you can overlap the rotation with other movements.
// The function is optimal in the sense that it recursively reschedules itself
// so that only one execution thread (step) exists at a time. The rotation rate
// and step size are programmable, with defaults of 100 deg/sec and one deg stepping size.


Stuff just related to how I do things...
$PI = 3.14159265359;
$RADIANS = $PI/180.0;

This is a keyboard routine to allow entry of desired angle in degrees and optionally, the stepping rate
in degrees/sec.
function rot(%shape,%yaw,%rate,%stepsize)
{
   rotateShape(%shape,%yaw*$RADIANS,"",%rate,%stepsize);
}

This is the rotate() routine that recursively schedules the iteration steps.
function rotateShape(%shape, %desired, %completion, %rate, %stepsize, %angle, %delta, %steps)
   // %shape is a shape name or id
   // %desired is the target angle
   // %completion is an optional routine to be called when done
   // %rate is an optional stepping rate, 100hz (degrees/sec) is the default
   // %stepsize is an optional stepping size, 1.0 degrees is the default

   //        the following are assigned recursively - not by the user
   // %angle is the current angle state
   // %delta is the current angular step and direction
   // %step is the number of steps remaining
{
   // Update present state...
   %xfrm = %shape.getTransform();
   %lx = getword(%xfrm,0); // first, get the current transform values
   %ly = getword(%xfrm,1);
   %lz = getword(%xfrm,2);
   %rx = getword(%xfrm,3);
   %ry = getword(%xfrm,4);
   %rz = getword(%xfrm,5);
   %rd = getword(%xfrm,6);

   // One time defaults and initialization
   if( %angle $= "" )
      %angle = %rz * %rd;

   if( %stepsize $= "" )
      %stepsize = 1.0;                 // Step size in degrees
   
   if( %steps $= "" ) {
      %yawBot = %rz * %rd;
      %yaw = %desired - %yawBot;
      if(%yaw > 180*$RADIANS)
         %yaw -= 360*$RADIANS;
      else if(%yaw < -180*$RADIANS)
         %yaw += 360*$RADIANS;
      %steps = mCeil(mAbs(%yaw/$RADIANS/%stepsize));
      if( %steps == 0 )
         %steps = 1;
      %delta = %yaw/%steps;
   }
   if( %rate $= "" )
      %rate = 100;                     // degrees/sec
   %period = 1000.0/%rate*%stepsize;   // msec/step
   if(%period < 1) %period = 1;
   
// Resolve some special cases related to 3D engine notation
   %rx = 0;
   %ry = 0;
   if( %angle >= 0 ) {
      %rz = 1.0;
      if( %delta > 0 ) {
         if( (%angle < 240*$RADIANS) && (%angle+%delta >= 240*$RADIANS) ) {
            %rz = -1.0;
            %angle -= 360*$RADIANS;
         }
      }
      else if( %angle+%delta < 0 ) 
         %rz = -1.0;
   }
   else {
      %rz = -1.0;
      if( %delta < 0 ) {
         if( (%angle > 240*$RADIANS) && (%angle+%delta <= 240*$RADIANS) ) {
            %rz = 1.0;
            %angle += 360*$RADIANS;
         }
      }
      else if( %angle+%delta > 0 ) 
         %rz = 1.0;
   }  

   // Create new state...
   %angle += %delta; 
   %steps = %steps-1;
   %shape.setTransform(%lx SPC %ly SPC %lz SPC %rx SPC %ry SPC %rz SPC mAbs(%angle));
   
   // Pass all the state informations to next iteration
   schedule(%period, 0, (%steps > 0)?rotateShape:rotateComplete, %shape, %desired, %completion, %rate, %stepsize, %angle, %delta, %steps);
}

// rotateComplete sets the shape to the desired position and calls the user's completion routine
// Set the final position and schedule the completion routine.
function rotateComplete( %shape, %desired, %completion )
{
   %xfrm = %shape.getTransform();
   %lx = getword(%xfrm,0);
   %ly = getword(%xfrm,1);
   %lz = getword(%xfrm,2);
   %rz = (%desired>=0) ? 1 : -1;
   %shape.setTransform(%lx SPC %ly SPC %lz SPC 0 SPC 0 SPC %rz SPC mAbs(%desired));
   if( %completion !$= "" ) 
      schedule(10,0,%completion,%shape);
}

Hope others will find this as useful as I have.
#12
01/04/2006 (8:48 am)
I just updated the rotateShape routine I posted earlier, so bumping this thread.
#13
04/18/2006 (5:58 pm)
Hey tim -
i've written something similar but i imagine equivelant,
but i'm encountering jerkiness in the animation -
it's just not as smooth as it could be.
i've tried a wide range of < 100ms timer periods, to small avail.

i thought torque interpolated stuff like that on the client side;
am i missing something ?
#14
04/19/2006 (4:54 am)
HI, Orion -

I thought I tested my method with varying speeds and found it to be very smooth. Have you plugged mine into your test and verified that it is also not smooth? but then smooth is a relative term - it seemed smooth compared to what I had before which was awful. :-)
#15
04/19/2006 (10:04 am)
Hey Tim,
thanks for getting back.
Yr right, I may be being too picky.
It's not Totally bad, it's just a lot jerkier than simply rotating with the mouse, say.
I'm sort of sinning and running this topic in two threads, shame on me!
But in the other thread, Ramen Sama recommended doing it in the engine and i'm inclined to agree.
#16
04/19/2006 (10:11 am)
Yeh, I thought about doing it in C++ but then realized that the script method has the advantage of being able to coordinate with other script activities more easily, in particular the rescheduling of completion routines so that you can overlap a bunch of rotating object threads. Just turns out to be very convenient in script especially if you trying to synchronize an animation that plays while the object rotates.