Game Development Community

Simset and SimGroup

by Doug Linley · in Torque Game Builder · 04/13/2006 (11:00 am) · 8 replies

Can anyone point me in the direction of some documentation on working with SimSet and SimGroup? I've been looking by doing searches for simset here on the gg site and the tdn site, but I've had no luck.

thanks,

#1
04/13/2006 (1:20 pm)
This thread helped me the most: www.garagegames.com/mg/forums/result.thread.php?qt=30610.

However, the key things to note are:
// if the enemySet simset exists
if( isObject(enemySet))
	// delete it
	enemySet.delete();

// create a simset for the enemies
new SimSet(enemySet);
Do this at the start when you initialise the simset to make sure you have a nice new shiny one.

%enemy = new t2dAnimatedSprite() { scenegraph = t2dscene; };
   %enemy.playAnimation(lemurFallAnimation);
   
   %enemy.setPosition("0 0");
   %enemy.setConstantForce(0 SPC 500, true);
   
   %enemy.setCollisionActive(true, true);
   %enemy.setCollisionPhysics(true, false);
   %enemy.setCollisionCallback(true);
   %enemy.setSize("48 48");
   %enemy.setCollisionResponse(CLAMP);
   %enemy.setCollisionMaxIterations(2);
   %enemy.setCollisionPolyCustom(4, 0.35, 0.85, 0.35, -0.79, -0.32, -0.79, -0.32, 0.85 );
   
   %enemy.setLayer($enemyLayer);
   %enemy.setGraphGroup($enemyGroup);
   %enemy.setCollisionMasks(BIT($platformGroup)|BIT($playerGroup), BIT($platformLayer)|BIT($playerLayer));
   
   %enemy.moveSpeed = 50;
   %enemy.points = 250;
   %enemy.heath = 100;

   enemySet.add(%enemy);
The above defines an animated sprite, plus a couple of handy fields (moveSpeed, points, health). The last line then adds this to the SimSet.

To get at the enemy for future operations, simply use
%obj = enemySet.getObject(0);

%obj will hold all of the details of the item in the SimSet, so you can call:
%obj.setPosition("100 100");
And the sprite will move.

To iterate through the items in the SimSet, use:
for (%i = 0; %i < enemySet.getCount(); %i++)
{
	doStuffToEnemy(enemySet.getObject(%i));
}

Finally, to remove items from the SimSet, use:
enemySet.remove(%i);
Where %i is the item to remove. Remember that removing items from a SimSet does not delete the underlying object. So the enemy sprite will still exist.

Do something like:
for (%i=0; %i<enemySet.getCount(); %i++)
{
	%enemyToDelete = enemySet.getObject(%i);
	%enemyToDelete.safedelete();
}

I think that covers the basics :)

Edit - Just changed the last code segment. There's no need to remove the object from the SimSet if you're actually deleting it.
#2
04/13/2006 (2:17 pm)
Thank you for that fantastic reply!
#3
04/13/2006 (3:04 pm)
No probs. I just happened to be eye-deep in SimSet stuff when I read your post so it was just a few copy and pastes really :)
#4
04/14/2006 (4:33 am)
One extra note to Philips explination above in case you're wondering about the difference between SimGroup and SimSet

A given object can be in as many seperate simsets as you want to add it to, however an object can only be in ONE simgroup at any time. If you add it to a second group it will automatically be removed from the first simgroup before been added into the second.

Also remember that this is a "set" which does not have ordering. You can add the numbers 1-10 in order to a set and you may when you loop through get them back out in order 1-10 but this is not guaranteed, espcecially if you delete a number from the set.

Other than that, Philip pretty much covered everything for you :)
#5
04/14/2006 (8:42 am)
Thanks Philip and Gary! I'm going to be toying around with this stuff starting early tomorrow. I can't wait to dig in.
#6
04/14/2006 (9:09 am)
Great explanations of SimSets and SimGroups. Only will add one more difference between a SimSet and a SimGroup. Not only will it remove object added to it from other SimGroups (as Gary mentioned), when you delete a SimGroup it will also delete all objects within that SimGroup.

Rule of thumb I use is use a SimSet unless I specifically need the features of a SimGroup.
#7
06/28/2006 (9:41 am)
This is a great post and it confirms a lot of what I've been doing, but I'm coming across some issues and I'm not sure what's causing them. (It may be one issue, or two, making it even more difficult to determine.)

I have an opening script "groupTreasure.cs" called from my game.cs. This script generates a SimGroup called "Treasure". It then generates a SimGroup called "Gems" and adds the group to SimGroup Treasure. (I'll be doing this for other types of treasure, if I can ever get this first one working.) [Code example below.]

// Define our Treasure Type Holder //
if (isObject(Treasure))
{
   Treasure.clear();
   Treasure.delete();   
}
new SimGroup(Treasure){};


// Define the Gems treasure type holder //
if (isObject(Gems))
{
   Gems.clear();
   Gems.delete();   
}
new SimGroup(Gems){};

// Add all treasure type SimGroups to the Treasure SimGroup //
Treasure.add(Gems);


Then it calls a script "gem.cs" where I define all of my gems and their base class. I create the base class as follows:

// Set up gem object class //
new t2dStaticSprite(GemObj){
   
   class = "GemObj";
   minSpeed = 5;
   maxSpeed = 15;
   layer = 10;
   testText = "GemObj class attributes set.";
      
};
error(GemObj.testText);

(As you can see, I use an error message to the console to determine if the class is being created properly.)
Then, in the same script I create a gem of type emerald, and I add it to the Gems SimGroup as follows:

// Create gems from the base class
new t2dStaticSprite(emerald: GemObj)
{
   class = "GemObj";
   imageMap = "GemsImageMap";
   frame = 2;
   size = "32 32";
   testText = "Emerald object created.";
};
error(emerald.testText);
Gems.add(emerald);
Gems.listObjects();
$testClass = Gems.getObject(0).getName();
error($testClass);
error(emerald.getSize());

(Again, I've added in some error tracking. Which I'll explain in a second.)

After all this set up, I get to a script "Treasure.cs" (which is called as the final script in game.cs). It uses a function called "createRandomGem()" to pull a gem from the SimGroup, copy it, add it into the scene, and then get it going. I copy the gem so that the original in the SimGroup is unchanged, and can be used again. I also delete the one taken from the SimGroup out of the scene, before the loop runs again. (The function loops until a number of gems equal to $gemCount have been released into the scene.) [More code again.]

// Treasure.cs

// Begin treasure generation //
function createRandomGem()
{
   %scenegraph = sceneWindow2D.getSceneGraph();
   error("Creating a random gem.");
   if ($gemCount < %scenegraph.maxGems)
   {
      %object = Gems.getObject(getRandom(0,Gems.getCount()-1));
      %showObject = new t2dStaticSprite("randomGem" @ $gemCount:GemObj){};
      %object.setVisible(0);
      echo(%showobject);
      echo(%object);
      //%object.setPosition(0,0);
      %object.addToScene(%scenegraph);
      %showObject.addToScene(%scenegraph);
      %object.copy(%showobject,true);
      %showObject.setImageMap(%object.getImageMap());
      %showObject.setFrame(%object.getFrame());
      // %showObject.setSize(%object.getSize());
      %showObject.setLayer(%object.getLayer());
      
      %showObject.setVisible(1);
      %showObject.setLinearVelocityY(getRandom(%object.minSpeed, %object.maxSpeed));
      %showObject.setPosition(getRandom(-50,50), -40);
      
      $gemCount++;
      %time = getRandom(1000, 5000);
      schedule(%time, 0, "createRandomGem");
      %scenegraph.removeFromScene(%object);
   }
   if ($gemCount = 1)
   {
      $testObject = %showObject;
   }
}

Here's the problem. When I run the game, it generates gems. It generates the proper amount, at a random x location, at the proper speed range. Therefore, it's probably safe to say that the base GemObj traits are being sustained. However, the image is ONLY frame 0 of whatever image map is being used, and all other attributes (such as size) from the child object are not being retained. (I have tiny gems of only one or two sprites.)

I've done a long series of attempting to debug this problem with help from several people and here's what we did/found:

1) The code is entering GemObj and creating the class successfully.
2) The code is entering emerald:GemObj and creating it successfully. If I pull an attribute of GemObj at creation, inheritance is working correctly. If I pull an attribute of emerald, it returns the correct values.
3) emerald is being added to SimGroup Gems correctly. It returns a unique ID and mentions it as part of the SimGroup. It also lists it as "t2dStaticSprite". (I thought it should say "GemObj" here, but it doesn't?)
4) Attributes pulled from the emerald in the SimGroup are NOT complete. GemObj attributes appear to be intact, but no GemObj methods are working. Emerald attributes are NOT intact, even though a getName(); shows it as being of class "emerald". (Again, I thought it would show "GemObj" here?)

So... as near as I can tell, the emerald works fine until it's added into the SimGroup. Then, it retains SOME of the attributes of GemObj (variables, static attributes and the like..) but NONE of the methods (GemObj::onWorldLimit() is not being called at all, and neither is GemObj::onCollision().) And it retains NONE of the emerald's individual aspects. (Polymorphism isn't working and neither are methods of the parent class.)

Can anyone tell me what's going on and how to fix this? I thought I had the right idea for randomly generating treasure by storing it in a SimGroup and then scanning the SimGroup to draw out a random piece, but it's not working properly. I read in a different post that methods do not work with SimGroups - for instance, I can't create a SimGroup called "Treasure" and then do "Treasure::onCollision()". This is not the same thing, however, so I don't know if it's part of the issue, something else entirely, or something I'm not doing correctly.

Sorry about the long post, any help would be appreciated.

Edit: Also, just as an aside, somewhere in all this debugging, my player picked up the min and max speed used for GemObj even though he's of type PlayerPharaoh and is defined in the level script "mainLevel.t2d". I can't figure out why he's going the same speed as the gems and I'm wondering if all this is a related issues somehow.
#8
06/28/2006 (3:17 pm)
Okay, just an update. Some problems are still not working. I still can't get GemObj methods to work and my player is still moving slowly (like he picked up the speed from the treasure for some reason).

However, thanks to muphicks teaching me how to use the Torsion dubugger, I was able to determine that my objects weren't copying in the right direction. I had to change this line of code:

%object.copy(%showObject,true);

to be this line of code:

%showObject.copy(%object,true);

I'm not sure, I may have copied it incorrectly from the reference, so I'll check. If I didn't though, that means the directions in the TGB reference are backwards. I was copying showObject into Object, instead of Object into showObject. Since showObject was an empty item with default values, none of my gems were correct. Once I switched the terms and started copying in the right direction, it worked fine.

EDIT: Okay, I checked the reference and here's what it says:

"copy(%objec, %copyFields)... %object - t2dSceneObject: The t2dSceneObject to copy this object to."

So, according to this, using %object.copy(%showObject, true) should have worked, since %object is what I was copying from and %showObject is what I was copying to. However, it didn't work until I switched them. (%showObject.copy(%object, true);) Therefore, the reference should read "%object - t2dSceneObject: The t2dSceneObject to copy this object FROM."