Game Development Community

About clone() method. bug?(sloved)

by KevinYuen · in Torque 2D Beginner · 03/15/2013 (10:22 pm) · 14 replies

%template = new SimObject()
   {
      NewName = "TestName";
      Record = new SimSet();
   };
   
   echo( "template record id:" @ %template.Record.getId() );
   
   for( %index = 0; %index < 10; %index++ )
   {
      %object = %template.clone( true );
      
      echo( "clone object " @ %index + 1 @ " record id:" @ %object.Record );
   }

output:

template record id:1245
clone object 1 record id:1245
clone object 2 record id:1245
clone object 3 record id:1245
clone object 4 record id:1245
clone object 5 record id:1245
clone object 6 record id:1245
clone object 7 record id:1245
clone object 8 record id:1245
clone object 9 record id:1245
clone object 10 record id:1245

they are using a same record? i want "record" member is independent, how?

#1
03/15/2013 (10:27 pm)
// ObjectBehaviorSensor is a behavior which hold a objectlist.
function ObjectBehaviorSensor::initialize( %this )
{   
   %this.visList = new SimSet();
   return true;
}

visList is shared by all objects which are having a ObjectBehaviorSensor.
#2
03/16/2013 (4:14 am)
Clone is a shallow copy, not a deep copy. See here for more info about the difference.

Also, the field "Record" is a dynamic-field which is completely custom and Torque doesn't know the meaning of its contents so it can only copy the fields value which in this case would contain the Id of the object (SimSet) and not the object itself. In other words, a dynamic-field has no type, it's just a string so a string is what is copied.

What would help you here would be a callback on an object being cloned so you could effectively have a constructor i.e.
function Foo::onClone( %this )
{
   // Do some initialization here like create a new sim-set for "Record".
}
The above isn't in the code right now but it could be added I guess.

In the meantime though, it's your responsibility to perform custom initialization. That'd be easy to do, just create a function that clones your object and initializes it.

#3
03/16/2013 (4:38 am)
like this ?

function TestTemplate::onClone( %this )
{
   %this.Record = new SimSet();
}

...
   %template = new SimObject()  
   {  
      class = "TestTemplate";
      NewName = "TestName";  
      Record = new SimSet();  
   };  
         
   echo( "template record id:" @ %template.Record.getId() );  
         
   for( %index = 0; %index < 10; %index++ )  
   {  
      %object = %template.clone( true );              
      echo( "clone object " @ %index + 1 @ " record id:" @ %object.Record );  
   }  
...

I can't find onClone in codes. :(
#4
03/16/2013 (4:41 am)
Quote:I can't find onClone in codes
As I said in bold, that isn't in the code now but it could be added.

Why not do this:
function TestTemplate::deepClone( %this )  
{  
	%object = %this.clone( true ); 
	%object.Record = new SimSet();  
	return %object;
}  
  
...  
   %template = new SimObject()    
   {    
      class = "TestTemplate";  
      NewName = "TestName";    
      Record = new SimSet();    
   };    
           
   echo( "template record id:" @ %template.Record.getId() );    
           
   for( %index = 0; %index < 10; %index++ )    
   {    
      %object = %template.deepClone();                
      echo( "clone object " @ %index + 1 @ " record id:" @ %object.Record );    
   }    
...
#5
03/16/2013 (4:44 am)
Thank you for your reply Melv :)

#6
03/16/2013 (4:49 am)
You're welcome. :)
#7
03/16/2013 (4:52 am)
function deepClone( %template )
{
   %object = %template.clone( true );
   %object.Record = new SimSet();
   return %object;
}
..
%object = deepClone(%template); 
..

if write as : function TestTemplate::deepClone( %this )

console output:
modules/LaunchStage/1/LaunchStage.cs (42): Unknown command deepClone.
Object (1232) SimSet -> SimObject
#8
03/16/2013 (5:32 am)
I'm not sure if that's a bug in the TorqueScript interpreter or not but try not to create types like this:
%template = new SimObject()      
{      
   class = "TestTemplate";    
   NewName = "TestName";      
   Record = new SimSet();      
};
... but do this instead ...
%template = new SimObject()      
{      
   class = "TestTemplate";    
   NewName = "TestName";      
}; 
%template.Record = new SimSet();

Try the following code:
function TestTemplate::deepClone( %this )    
{    
    %object = %this.clone( true );  
    %object.Record = new SimSet();    
    return %object;  
}    
  
function runTest()
{
    %template = new SimObject()      
    {      
      class = "TestTemplate";    
      NewName = "TestName";      
    };        

    for( %index = 0; %index < 10; %index++ )      
    {
      %object = %template.deepClone();                  
      echo( "clone object " @ %index + 1 @ " record id:" @ %object.Record );      
    }    
}

runTest();
#9
03/16/2013 (5:33 am)
When you do this:
%template = new SimObject()        
{        
   class = "TestTemplate";      
   NewName = "TestName";        
   Record = new SimSet();        
};
... TorqueScript screws-up and sets the namespace of "%template" to be "SimSet"!! Don't blame me, I didn't write the iterpreter. :)
#10
03/16/2013 (5:54 am)
A deeper question, can you give me some information?

function ObjectSystem::CreateDirectly( %this, %type, %name )
{
   %library = "";
   
   // query item library
   if( %type == $Game::ObjectType::Tower )
   {
      %library = ItemLibrary.TowersLib;
   }
   else if( %type == $Game::ObjectType::Enemy )
   {
      %library = ItemLibrary.EnemiesLib;
   }
   else if( %type == $Game::ObjectType::Building )
   {
      %library = ItemLibrary.BuildingLib;
   }
   else if( %type == $Game::ObjectType::OwnBullet )
   {
      %library = ItemLibrary.BulletsLib;
   }
   else
   {
      error( "Can not find item library!" );
      return "";
   }
   if( !isObject( %library ) )
   {
      error( "The library was not init ! type: " @ %type );
      return "";
   }
   
   // confirm 
   %info = %library.findObjectByInternalName( %name );
   if( !isObject( %info ) )
   {
      echo( "Can not find " @ %name @ " in tower library!" );
      return "";
   }
   
   %object = new Sprite()
   {
      internalName = %info.getInternalName();
   };
   
   // fill dynamic fields
   for( %index = 0; %index < %info.getDynamicFieldCount(); %index++ )
   {
      %FieldName = %info.getDynamicField( %index ) ;  
      %FieldValue = %info.getFieldValue( %FieldName );
      //echo( "Name:" @ %FieldName @ " Value:" @ %FieldValue );
      %object.setFieldValue( %FieldName, %FieldValue );
   }
   
   // create collision shape
   if( %object.PickingAllowed == 1 )
   {
      %object.createPolygonBoxCollisionShape( %object.CollisonSize );
   }
      
   // create behaviors
   for( %index = 0; %index < getWordCount( %object.Behaviors ); %index++ )
   {
      %behavior = getWord( %object.Behaviors, %index );
      if( %behavior $= $ObjectSystem::BehaviorMove )
      {          
         %MoveBehavior = ObjectBehaviorMove.createInstance();
         if( %MoveBehavior.initialize( %object.MoveSpeed ) )
            %object.addBehavior( %MoveBehavior );
         else
            %MoveBehavior.delete();
      }
      else if( %behavior $= $ObjectSystem::BehaviorUpgrade )
      {
         %UpgradeBehavior = ObjectBehaviorUpgrade.createInstance();
         if( %UpgradeBehavior.initialize() )
            %object.addBehavior( %UpgradeBehavior ); 
         else
            %UpgradeBehavior.delete();
      }
      else if( %behavior $= $ObjectSystem::BehaviorFire )
      {         
         %FireBehavior = ObjectBehaviorFire.createInstance();
         if( %FireBehavior.initialize() )
            %object.addBehavior( %FireBehavior ); 
         else
            %FireBehavior.delete();
      }
      else if( %behavior $= $ObjectSystem::BehaviorSensor )
      {
         %SensorBehavior = ObjectBehaviorSensor.createInstance();
         if( %SensorBehavior.initialize() )
            %object.addBehavior( %SensorBehavior ); 
         else
            %SensorBehavior.delete();
      }
      else
      {
         error( "Can not unknown behavior: " @ %behavior );
      }
   }
   
   %upgradeBehavior = %object.getBehavior( $ObjectSystem::BehaviorUpgrade );
   if( %object.Level !$= "" && isObject( %upgradeBehavior ) )
   {
      %upgradeBehavior.SetLevel( %object.Level );
   }
   
   %object.setEnabled( 1 );
   
   return %object;
}

function ObjectSystem::CreateFromTemplate( %this, %type, %name )
{   
   if( %name $= "" ) return;
   
   if( !isObject( ObjectSystem.TemplateSet ) )
   {
      ObjectSystem.TemplateSet = new SimSet();
   }
   
   if( isObject( ObjectSystem.TemplateSet ) )
   {
      for( %index = 0; %index < ObjectSystem.TemplateSet.getCount(); %index++ )
      {
         %template = ObjectSystem.TemplateSet.getObject( %index );
         %classname = %template.getInternalName();
         if( %name $= %classname )
         {
            %object = %this.ObjectDeepClone( %template );
            //ObjectSystem.BindScene.add( %object );
            %object.setEnabled( 1 );
            return %object;
         }
      }
   }
   
   %object = %this.CreateDirectly( %type, %name );
   if( !isObject( %object ) ) return "";   
   
   // ObjectSystem.BindScene.add( %object );
            
   ObjectSystem.TemplateSet.add( %object );
      
   %object.setEnabled( 0 );
   
   %cloneobject = %this.ObjectDeepClone( %object );
   
   //ObjectSystem.BindScene.add( %cloneobject );
   %cloneobject.setEnabled( 1 );
   
   return %cloneobject;
}
#11
03/16/2013 (5:55 am)
there are some SimSet fileds In my behaviors, like this:

function ObjectBehaviorSensor::initialize( %this )  
{     
   %this.visList = new SimSet();  
   return true;  
}

my current method is:
function ObjectSystem::ObjectDeepClone( %this, %template )
{
   %object = %template.clone( true );
   
   for( %index = 0; %index < %object.getBehaviorCount(); %index++ )
   {
      %behavior = %object.getBehaviorByIndex( %index );
      %behavior.DeepClone();
   }
   
   return %object;
}

//in behavior:
function ObjectBehaviorSensor::DeepClone( %this )
{
   %this.CoveredObjectList = new SimSet();
}

it's result is right, but need a lot of steps. :(
#12
03/16/2013 (7:57 am)
You don't need to clone behaviors. When you clone an object the behaviors are automatically cloned for you.
#13
03/16/2013 (7:59 am)
function ObjectBehaviorSensor::initialize( %this )    
    {       
       // it need deep clone :(
       %this.visList = new SimSet();    
       return true;    
    }

#14
03/16/2013 (11:04 pm)
uh.. sorry.. other question. :(

about gui clone:

%progbar = new GuiProgressCtrl()
    {
      class = "ProgressBar";
      internalName = "HealthBar";
      Profile="GuiHealthProgressBar";
      HorizSizing="relative";
      VertSizing="relative";
      Position="60 60";
      isContainer = "0";
      useMouseEvents = "0";
      Extent="100 20";
      Visible="1";
      Active="1";
    };      
        
    %progbar.setValue( 0.3 );
        
    Game.MainWindow.add( %progbar );  
    
    %clonebar = %progbar.clone( true );
    %clonebar.setPosition( 60, 100 );
    %clonebar.setValue( 0.7 );
    Game.MainWindow.add( %clonebar );  
      
    Game.ActiveStage.ScopeSet.add( %progbar );
    Game.ActiveStage.ScopeSet.add( %clonebar );

e.hiphotos.baidu.com/album/s%3D550%3Bq%3D90%3Bc%3Dxiangce%2C100%2C100/sign=054985f63ac79f3d8be1e4358a9abc2c/71cf3bc79f3df8dc1d744f98cc11728b4710286a.jpg?referer=c3c7fa1d43a7d933e6bfd1438828&x=.jpg
the profile was not copied...

profile code:

if (!isObject( GuiHealthProgressBar )) new GuiControlProfile( GuiHealthProgressBar )
{
opaque = true;
border = true;
fillColor = Red;
borderColor = LimeGreen;
};