Game Development Community

Creating Objects in Script with a Datablock

by James Nhan · in Torque Game Builder · 02/22/2011 (10:58 am) · 14 replies

How do I create an object in my script and assign it a datablock?

I've tried this:

%speed = new Speed()
{
   datablock = \"Powerup_Speed\";
};

But I get "Unable to instantiate object of class speed." errors. I've looked and looked and read and reread the documentation, but I can't figure this out :-/

About the author

Recent Threads


#1
02/22/2011 (11:07 am)
where have you defined the Speed object? If it's in source then you would have to set it up to use a datablock....

Assuming you just want a script object and you don't actually need a datablock, try something like this:

function SpeedCreate(%speed)
{
	%obj = new ScriptObject(Speed)
	{
		actualSpeed = %speed;
	};
	
	return %obj;
}

function Speed::getSpeed(%this)
{
   return %this.actualSpeed;
}
#2
02/22/2011 (1:07 pm)
The Speed object I defined in the Torque Game Builder. I made an object with class "Speed". Is there another place I have to define it?

This is my code at the moment:

datablocks.cs
datablock t2dSceneObjectDatablock(Powerup_Speed)
{
   Layer = 8;
   Size = "4 4";
   class = "speed";
   CollisionCallback = true;
   CollisionActiveReceive = true;
   CollisionActiveSend = false;
   CollisionDetectionMode = "CIRCLE";
   CollisionPhysicsReceive = false;
   CollisionPhysicsSend = false;
   factor = 2;
   time = 15000;
};

powerups.cs

function Speed::onCollision(%srcObj, %dstObj, %srcRef, %dstRef, %time, %normal, %contactCount, %contacts)
{
   if (%dstObj.class $= "playerShip")
   {
      %dstObj.Speed *= %srcObj.factor;
      speedTxtGUI.text = "Speed: " SPC %dstObj.Speed;
      %dstObj.schedule(%srcObj.time, "speedExpire", %srcObj.factor);
      %srcObj.safeDelete();
   }
}

function playerShip::speedExpire(%this, %factor)
{
   %this.Speed /= %factor;
   speedTxtGUI.text = "Speed: " SPC %this.Speed;
}

function Powerups::Spawn(%interval, %spawn)
{
   %speed = 0;
   eval("%speed = new Speed() { datablock = \"Powerup_Speed\"; };");
   %speed.setPositionX(getRandom(-43.0, 43.0));
   %speed.setPositionY(getRandom(-30.0, 30.0));
   
   if (%spawn)
   {
      schedule(%interval, "PowerupsRandomSpawn", %interval, %spawn);
   }
}

function Powerups::Init()
{
   Powerups::Spawn(1.0, true);
}

Ignore the eval, I was trying multiple things that I found on Google.
#3
02/22/2011 (7:47 pm)
If you look in your level file where you created this object with the class "Speed", you'll see that it's really a t2dSceneObject or a t2dStaticSprite (or something along those lines).

In your SpeedCreate, you want to clone this object.

You'll need to give the object a Name in addition to its Class name. Then you can clone it using it's name:

%newPowerup = SpeedPowerup.clone();
%newPowerup.actualSpeed = %speed;

You'll probably want to set other attributes on it, too (like position, speed, whatnot).
#4
02/23/2011 (9:35 am)
Okay, this is what I have:

function speed::Spawn(%this, %interval, %spawn)
{
   %speed = newSpeed.clone();
   
   %speed.setPositionX(getRandom(-43.0, 43.0));
   %speed.setPositionY(getRandom(-30.0, 30.0));
   
   if (%spawn)
   {
      %this.schedule(%interval, "Spawn", %interval, %spawn);
   }
}

However, the cloned object won't collide.

If I echo the factor attribute it's null. It seems it's not copying the datablock attributes over. However, when I try this:

function speed::Spawn(%this, %interval, %spawn)
{
   %speed = newSpeed.clone();
   
   %speed.Layer = 8;
   %speed.Size = "4 4";
   %speed.class = "speed";
   %speed.CollisionCallback = true;
   %speed.CollisionActiveReceive = true;
   %speed.CollisionActiveSend = false;
   %speed.CollisionDetectionMode = "CIRCLE";
   %speed.CollisionPhysicsReceive = false;
   %speed.CollisionPhysicsSend = false;
   %speed.factor = 2;
   %speed.time = 15000;
   
   %speed.setPositionX(getRandom(-43.0, 43.0));
   %speed.setPositionY(getRandom(-30.0, 30.0));
   
   if (%spawn)
   {
      %this.schedule(%interval, "Spawn", %interval, %spawn);
   }
}

The attribute displays correctly, but it won't execute the collide function on collision with my ship.
#5
02/23/2011 (10:22 am)
You're second example is how I often end up doing things (I, too, have had problems with clone).

Unfortunately, I'm always playing with the CollisionActive* and CollectionPhysics* to get what I want done. I'm sad to admit that I often break down and just use triggers attached to the object.

I don't get home until very late on Wednesday's, but I'll set an alarm to remind me to post how I handle this situation.
#6
02/23/2011 (7:14 pm)
I don't know if this will help you, but this is how I handle collisions:

function ArcadeMinions::buildMinion( %this )
{
  %minion = new t2dParticleEffect() {
      class = ArcadeMinion;
      scenegraph = ArcadeScene;
      effectFile = "~/data/particles/minion.eff";
      useEffectCollisions = "0";
      effectMode = "INFINITE";
      effectTime = "0";
      canSaveDynamicFields = "1";
      position = "0 0";
      size = "15.000 15.000";
      Layer = "18";
      ForwardOnly = "1";
      qUpdate = true;
    };
    %minionCollision = new t2dSceneObject() {
      scenegraph = ArcadeScene;
      class = ArcadeMinionCollision;
      canSaveDynamicFields = "1";
      Position = %start;
      size = "15.000 15.000";
      GraphGroup = "17";
      CollisionActiveReceive = "1";
      CollisionActiveSend = "1";
      CollisionPhysicsSend = "0";
      CollisionPhysicsReceive = "0";
      CollisionDetectionMode = "CIRCLE";
      CollisionCircleSuperscribed = "0";
   };
   %minion.moveEffectTo( 10, 2 );
   %minionCollision.mount( %minion );
   return %minion;
}

My player class has the following code in it's onCollision callback:

if( %dstObject.class $= "ArcadeMinionCollision" )
  {
    ArcadeState.modifyPlayerHealth( -0.30 );
  }
#7
02/25/2011 (7:14 am)
Ah, I see. So instead of cloning, you just create a new object?

Is there any way I can set its datablock?

I.E. is this valid?

function Powerups::Spawn(%interval, %spawn)  
{  
   %speed = new t2dSceneObject() {
      datablock = "Powerup_Speed";
   }  
   %speed.setPositionX(getRandom(-43.0, 43.0));  
   %speed.setPositionY(getRandom(-30.0, 30.0));  
     
   if (%spawn)  
   {  
      schedule(%interval, "PowerupsRandomSpawn", %interval, %spawn);  
   }  
}
#8
02/25/2011 (10:49 am)
I don't have the source code in front of me right now, but I can't see why that wouldn't work!
#9
02/25/2011 (11:14 am)
Thanks ^_^
#10
02/26/2011 (1:14 pm)
Hmm. I've tried this:

function speed::Spawn(%this, %interval, %spawn)
{
   %speed = new t2dSceneObject()
   {
      datablock = "Powerup_Speed";
   };  
   
   %speed.setPositionX(getRandom(-43, 43));
   %speed.setPositionY(getRandom(-30, 30));
   
   if (%spawn)
   {
      %this.schedule(%interval, "Spawn", %interval, %spawn);
   }
}

And the object gets created (I echo %speed), but it's nowhere to be seen on the screen. I think that it has no image map, but I can't figure out how to set its image map. Do I have to make it a particle and mount it to an object like you do? If so, how do I do that? The file isn't a .eff. It's the plasma ball in the starterArt.
#11
03/01/2011 (11:04 am)
Okay, I am able to make the new object now. However, I have a problem. The collision is not working. My ship collides with it, and gets Clamped, but the onCollision function is not being called on collision. Here is my script:

function speed::onCollision(%srcObj, %dstObj, %srcRef, %dstRef, %time, %normal, %contactCount, %contacts)
{
   echo("Test");
   if (%dstObj.class $= "playerShip")
   {
      %dstObj.Speed *= %srcObj.factor;
      speedTxtGUI.text = "Speed: " SPC %dstObj.Speed;
      %dstObj.schedule(%srcObj.time, "speedExpire", %srcObj.factor);
      %srcObj.safeDelete();
   }
}

function playerShip::speedExpire(%this, %factor)
{
   %this.Speed /= %factor;
   speedTxtGUI.text = "Speed: " SPC %this.Speed;
}

function speed::Spawn(%this, %interval, %spawn)
{
   %speed = new t2dSceneObject()
   {
      scenegraph = %this.scenegraph;
      Layer = 8;
      Size = "4.000 4.000";
      class = "speed";
      CollisionCallback = true;
      CollisionActiveReceive = true;
      CollisionActiveSend = false;
      CollisionDetectionMode = "CIRCLE";
      CollisionPhysicsReceive = false;
      CollisionPhysicsSend = false;
      factor = 2;
      time = 15000;
   };
   %speedSprite = new t2dStaticSprite()
   {
      scenegraph = %this.scenegraph;
      imageMap = particle_plasmaImageMap;
      Layer = 8;
      Size = "4.000 4.000";
   };
   %speedSprite.mount(%speed);
   
   %speed.setPositionX(getRandom(-43.0, 43.0)); 
   %speed.setPositionY(getRandom(-30.0, 30.0));
   
   if (%spawn)
   {
      %this.schedule(%interval, "Spawn", %interval, %spawn);
   }
}

function speed::onLevelLoaded(%this, %scenegraph)
{
   %this.scenegraph = %scenegraph;
   %this.Spawn(100, true);
}
#12
03/01/2011 (12:47 pm)
In my example, I had the CollisionActiveSend and Receive to true. I don't know if this should matter, but it's something to try.
#13
03/30/2011 (6:06 am)
James,

Correct me if I'm wrong on this one, but I believe a datablock should be set using the name "config" when you are creating objects. Like:

%newObject = new t2dStaticSprite()
   {
      sceneGraph = %this.owner.getSceneGraph();
      canSaveDynamicFields = "1";
      config = "playerBullet" @ %color @ %type @ "Datablock";
   };

At least, this is the name that is listed in the docs (and your scene file if you care to examine it).
#14
03/30/2011 (1:06 pm)
Ah, I actually forgot about this thread :P

I was able to do what I wanted without datablocks.