Game Development Community

Dynamic mounting

by M. Stolley · in Torque Game Engine · 11/01/2005 (9:22 am) · 18 replies

Hi,

i have a problem with a rubicks cube like game.

How can i rotate a complete side of some cubes that are mounted to a rubicks cube like object and then after i turned the side i.e. around 90 degre i will turn another side.

So if you do not understand what i mean perhaps this little video can help you/me.

http://www.nearlygood.com/video/rubickthirty.html

or see some picture of the rubick cube here
https://www.toys-for-all.de/index.php/cPath/68/category/rubiks-cubes.html


So i am new to Torque and can not program in c++ and just begin to learn the scripting language.

I think that must be dynamicly mounted and unmounted.
Can Torque can do this and how does it work ?

Thank you

Mathias

#1
11/01/2005 (9:41 am)
While you COULD do this without mounting, if you want to do it in the manner you're thinking of, you need something like my unreleased resource to allow SceneObjects to freely mount to others.

I am not sure how net-aware my code is (I'm not a TGE uber-coder), but I feel if I released this others would find it sufficiently valuable to complete any missing logic.

I'll try to post it later today -- it is based on 1.4rc2 codebase.

tone
#2
11/01/2005 (10:01 am)
Hi Anthony Lovell,

i am verry interested in this resource.

I also want to move the single cube rows after rotating up and down or left and right.
Do you think this is possible too with your resource?
Also do you think your resource can be used in TSE?

Mathias
#3
11/01/2005 (11:26 am)
How exactly does your code work? I'm always interested in new code. :) Will it do Mounting in Place? so to speak.
#4
11/01/2005 (12:06 pm)
I just submitted it. It has a few places where correction are welcome, and I would not be surprised it I had to issue one or two fixes.
It should easily work in TSE.

It works thuslike.

First: to differentiate from the old ShapeBase mounting stuff, I do not use the word mounting (I've not seen any system outside of TGE that used that word for this, but maybe I have just not been around!)

I refer to this in terms along the lines of "attaching and detaching child SceneObjects", but it does much more (and simply!)

The fix ONLY affects SceneObject.cc and SceneObject.h, and those files are in the resource in their entirety, adapted from HEAD as of Oct 16 2005

The essentials are that each SceneObject can now have 0 or 1 parent SceneObjects it is attached to. It has a "Local Transform" expressing its translation and orientation RELATIVE to the coordinate system of its parent. A family of C++ and TS functions have been added to augment existing calls (which implicitly operated in the root coordinate system), but which explicitly indicate they operate on the LOCAL transform. Calling these on any object which has no parent has the same effect as altering the root transform properties -- in this manner, I would expect that calling these will eventually become the predominate way of manipulating objects in a TGE scene).

In effect, if one creates a complex scene graph of nested SceneObjects, each object maintains (as before) a member variable which stores its root transform, but also a matrix to store its local transform. This keeps performance lively, and the root transform matrix for any sceneobject should be identical to the product of the local transforms of itself and its ancestors in the scenegraph. It is a thing of beauty that one cannot live without when one's game has ships moving on seas carrying 50+ sailors and equipment mounting boxes with sliders and knobs all attached and all translating and revolving NOT (as a rule) relative to the scene, but relative to the thing they are attached to.

A subset of the README I submitted follows.
#5
11/01/2005 (12:07 pm)
NEW SCENEOBJECT C++ FUNCTIONS
/// also useful for setting NULL parent (making SceneObject a root object)
   virtual bool attachToParent(SceneObject *parent, MatrixF *atThisOffset = NULL);

   /// returns NULL if this is a root SceneObject
   SceneObject *getParent();
   
   /// attach a subobject, but do not alter the subObject's present absolute position or orientation
   /// returns FALSE if the operation would cause a cycle in the scene graph
   bool attachChild(SceneObject* subObject);   

   /// attach a subobject, at the specified offset expressed in our local coordinate space
   /// returns FALSE if the operation would cause a cycle in the scene graph
   bool attachChildAt(SceneObject* subObject, MatrixF atThisTransform);   

   /// attach a subobject, at the specified position expressed in our local coordinate space
   /// returns FALSE if the operation would cause a cycle in the scene graph
   bool attachChildAt(SceneObject* subObject, Point3F atThisPosition);   
   
   /// how many child SceneObjects are (directly) attached to this one?
   U32 getNumChildren() const;

   /// how many child objects does this SceneObject have when we count them recursively?
   U32 getNumProgeny() const;

   /// returns the (direct) child SceneObject at the given index (0 <= index <= getNumChildren() - 1)
   SceneObject *getChild(U32 index) const; 
   
   /// is this SceneObject a child (directly or indirectly) of the given object?
   /// this is used internally to disallow creation of cycles in the scene graph
   bool isChildOf(SceneObject *);

   /// set position in parent SceneObject's coordinate space (or in world space if no parent)
   void setLocalPosition(const Point3F &pos);

   /// move the object in parent SceneObject's coordinate space (or in world space if no parent)
   void localMove(const Point3F &delta);
   /// as localMove(const Point3F &delta), with different signature
   void localMove(F32 x, F32 y, F32 z);

   /// move the object in world space, without altering place in scene hierarchy
   void move(const Point3F &delta);
   /// as move(const Point3F &delta), with different signature   
   void move(F32 x, F32 y, F32 z);

   /// returns the transform relative to parent SceneObject transform (or world transform if no parent)
   const MatrixF& getLocalTransform() const;
   /// returns the position within parent SceneObject space (or world space if no parent)
   Point3F getLocalPosition() const;
   
   
   virtual void onParentScaleChanged();   
   virtual void onParentTransformChanged();
      
   /// Sets the Object -> Parent transform.  If no parent SceneObject, this is equivalent to 
   ///  setTransform()
   virtual void setLocalTransform(const MatrixF & mat);


   /// Called to let instance specific code happen 
   virtual void onLostParent(SceneObject *oldParent);   

   /// Called to let instance specific code happen 
   virtual void onNewParent(SceneObject *newParent);   

   /// notification that a direct child object has been attached
   virtual void onNewChild(SceneObject *subObject);   

   /// notification that a direct child object has been detached
   virtual void onLostChild(SceneObject *subObject);
#6
11/01/2005 (12:09 pm)
NEW SCENEOBJECT SCRIPT FIELDS

In section "SceneGraph"
parent -- a reference to a parent SimObject (better be NULL or a SceneObject!)
pos -- a position relative to the parent (same as "position" -- which is to say root position -- when there is no parent)
rot -- a rotation relative to the parent (same as "rotation" -- which is to say root rotation -- when there is no parent)


NEW SCENEOBJECT SCRIPT FUNCTIONS

ConsoleMethod( SceneObject, getLocalTransform, const char*, 2, 2, "Get transform of object relative to its parent.")
ConsoleMethod( SceneObject, getLocalPosition, const char*, 2, 2, "Get position of object relative to its parent.")
ConsoleMethod( SceneObject, setLocalTransform, void, 3, 3, "(Transform T)")
ConsoleMethod( SceneObject, getLocalForward, const char*, 2, 2, "Returns a vector indicating the direction this object is facing within parent's space.")
ConsoleMethod( SceneObject, setLocalPosition, void, 3, 3, "(Point3F p)")

ConsoleMethod( SceneObject, move, void, 3, 3, "(Point3F deltaInWorldSpace)") // why this did not already exist astounds me!
ConsoleMethod( SceneObject, localMove, void, 3, 3, "(Point3F deltaInParentsSpace)")
ConsoleMethod( SceneObject, setPosition, void, 3, 3, "(Point3F worldPos)") // why this did not already exist astounds me!

ConsoleMethod(SceneObject, getNumChildren, S32, 2, 2, "returns number of direct child objects")
ConsoleMethod(SceneObject, getNumProgeny, S32, 2, 2, "returns number of recursively-nested child objects")
ConsoleMethod(SceneObject, getChild, S32, 3, 3, "getChild(int index) -- returns child SceneObject at given index")
ConsoleMethod(SceneObject, attachChildAt, bool, 4, 4, "(SceneObject subObject, MatrixF offset)"
              "Mount object to this one with the specified offset expressed in our coordinate space.")
ConsoleMethod(SceneObject, attachToParent, bool, 3, 3, "attachToParent(SceneObject)"
              "specify a null or non-null parent")
ConsoleMethod(SceneObject, getParent, S32, 2, 2, "returns ID of parent SceneObject")
ConsoleMethod(SceneObject, attachChild, bool, 3, 3, "(SceneObject subObject)"
              "attach an object to this one, preserving its present transform.")
ConsoleMethod(SceneObject, detachChild, bool, 3, 3, "SceneObject subObject")
#7
11/01/2005 (12:19 pm)
And, just a stupid example from my test script.

//-----------------------------------------------------------------------------
// this StageManager stuff is called from the end of the server's Game::startGame() code 
function StageManager::setStage(%this)
{
 
  $dad = new Item()
   {
      dataBlock = TestItemData;
static = true;
   };
$dad.setShapeName("dad");
   
   $son = new Item() 
   {
      dataBlock = TestItemData;
static = true;
   };
$son.setShapeName("son");
   
   MissionCleanup.add($dad);
   MissionCleanup.add($son);

   $dad.setTransform("-103 -103 210 0 1 0 0 0");
   $son.setTransform("-104 -104 209 0 1 0 0 0");
   $dad.attachChild($son);

   new ScriptObject(Anim) {
   };
   MissionCleanup.add(Anim);   
}



function Anim::start(%this, %mag) 
{
  %this.animTime = 0;
  %this.doAnim = 1;
  %this.animPeriod = 2;
  %this.animOrigin = getWord($son.getLocalPosition(), 2);

  echo("animOrigin is " @ %this.animOrigin);

  %this.animMagnitude = %mag;
  %this.animSon();
}

function Anim::stopAnim(%this) {
  %this.doAnim = 0;
}

function Anim::animSon(%this) 
{
  if (%this.doAnim == 0) return;
  %newY = %this.animOrigin + (%this.animMagnitude * mSin(%this.animTime * 6.2832 / %this.animPeriod)) ;

  %posNow = $son.getLocalPosition();
  %posNow = setWord(%posNow, 2, %newY);
  $son.setLocalPosition(%posNow);

  %this.animTime = %this.animTime + 0.2;  
  %this.schedule(200, "animSon");
}

The behavior, once started, allows a simple sinusoidal motion of the child relative to the parent.
If you use any script commands to alter the transform of the parent, the son follows but otherwise continues its behavior relative to its parent.

I coded this because my simulation relies heavily on this modeling of physical mechanical devices. In my Java prototype, I ran "getNumProgeny()" on the equivalent to a TGE SceneObject that represented a battleship and all the men and equipment on board, and it was a tree of 1750 nodes.

tone
#8
11/07/2005 (11:46 am)
Wow, what a great resource. Thank you so much for sharing. Is this based off of Ben's temporary parenting hack solution?

I've been waiting 7 days now to see it, hopefully it will be accepted soon!
#9
11/07/2005 (11:54 am)
I think I really mimicked most of what was behind the shapebase mounting logic. I had to learn just enough 3D transform operation to make it work.

I hope it comes out soon and that with your help we can make it fully bulletproof. I'd need others to help stress it in important ways, and I hope to later add what I feel TGE truly misses -- a SIMPLE for expressing translation and rotation. This could become so much more accessible.

tone
#10
11/07/2005 (11:57 am)
Wow, if this works how i think it will, it'll be amazing. I'll have to give it a go and see how it works.


Ugh, i'm not positive where all this code is supposed to go. Can we have a link to the resource until it's appproved?
#11
11/08/2005 (3:05 pm)
Ok .. please let me know what you find (or miss) from this at

http://dreadnoughtproject.org/HierarchicalCoordinateSpaces_20051101a.zip

The zip is around 32K should contain everything you need to know.
Help me improve it, please.

tone
#12
11/08/2005 (9:52 pm)
Awesome. thanks a bunch. i'll post some feedback.
#13
11/09/2005 (12:55 am)
ERROR!!!!
when compiling.


j:\Torque\engine\sim\sceneObject.cc(2178): error C2039: 'getFlippedPlane' : is not a member of 'Interior'

PlaneF plane = interior->getFlippedPlane(surface.planeIndex);

did a search for getFlippedPlane, resulted nothing. I assume this is a custom function of yours.... or something from the HEAD
#14
11/09/2005 (1:36 am)
Its from HEAD
#15
11/09/2005 (6:28 am)
Yes. Check the readme... it indicates this is from a recent HEAD and I thiink the date is that marked on the ZIP file (or nearly).

It also outlines where my own TGE inexperience creates the greatest doubt as to how complete/correct the code is. Those areas are probably the ones that could use the greatest attention: networked behavior as well as should I be basing the localTransforms against the transforms or RENDERTransforms of their parents?

Modifying the code I gave you to work with 1.3 is probably quite easy -- do a diff against the current HEAD and hand-apply the changes.

tone
#16
11/13/2005 (2:31 am)
This sounds cool. Has it been submitted as a GG resource or TDN article, yet?
#17
11/13/2005 (2:59 am)
Damn cool!!!!

I surely hope this gets into the engine and/or as a resource. Has been missing for ages
#18
11/13/2005 (10:38 am)
Not sure about this, but I think the best 2 options are:
1) if is possible, mount the lateral cubes as parented with the base cubes
2) dinamically generate a skin, based on the position of each lateral cube.

The first option requires that you develop the Rubik's cube in 3D exactly as it is in reality, that's a roman cross with an additional axis, on top of it there are "peripheral" cubes that are removable if forced.
The peripheral cubes may be modeled apart as parent of the roman cross, while the main cubes rotates, you rotate the parented cubes also.

The second option, easyer, is developable simplysh by having a quick look at some *old* gwbasic, qbasic, commodore, apple (and so) source code. In the 80's there was plenty of games of all genres and for sure I saw more than one rubik's cube game.
These games were not in 3D, so the cube were displayed unwrapped with the squares changing color after each move.
You could dinamycly generate the same result and save it as a bitmap, then use it to skin your cube.
This solution, however, lacks in animation: I don't know how to represent the rotation animation of the various faces of the cube without messes.

Bye, Berserk.
.