Game Development Community

Spawning outside of Terrain

by Randy Sewell · in Torque Game Builder · 08/31/2012 (5:17 am) · 12 replies

I have been working for hours trying to get this to work. Basically I am trying to search for objects prior to spawning my enemy, and if objects are found where he is going to spawn, it tries again.

When I move the object creation code outside of the IF statement, it spawns fine. My echo's inside the IF statements do not return. There are no errors in the console.

Can anyone see anything obviously wrong with the below code?

%tSceneGraph = %this.getSceneGraph(); 
      
      %objectList = %tSceneGraph.pickRadius(%position, 20, BIT(9), BIT(9), 0);  
      %objectCount = getWordCount(%objectList);  
      echo("Past the Object Count!"); 
      for(%i = 0; %i < %objectCount; %i++)  
        if (%i > 0 ) {  
            echo ("Too close!");  
            return %this.schedule(100, "spawnHandyMan");
         } 
         
         if (%i = 0 ) {  
         
         %handyman = new t2dAnimatedSprite()
         {
            scenegraph = %this.scenegraph;
            class = enemy_class;
            position = %position;
         };
     
         %handyman.playAnimation(handyman_Anim);
         %handyman.setSize(19, 28);
         %handyman.setLayer(11);
         %handyman.setCollisionActive( true, true );
         %handyman.setCollisionPhysics(true, false);
         %handyman.setCollisionCallback(true);   
         
         echo("HandyMan Created!");





#1
08/31/2012 (5:41 am)
I believe this will always evaluate to true...
if (%i = 0 )
try this...
if (%i == 0 )
#2
08/31/2012 (5:56 am)
You sir, are my hero. :)

#3
08/31/2012 (6:31 am)
Just one problem left.

if (%i > 0 ) {  
            echo ("Too close!");  
            return %this.spawnHandyMan();
         }

Somehow, the enemy is getting lost somewhere. It says he spawns, but he is nowhere to be found. Do you know what might cause this, and is there a simple solution to catch it in those instances?

One game, he disappeared after the second "Too Close" event, and another game I killed him dozens of times no problem.
#4
09/01/2012 (11:03 pm)
Another bit to add to this problem.

I changed my level from tile objects to a tilemap and now the pickradius doesn't seem to be working at all. I will see a "Spawned bottom!" echo but my enemy never actually hits the scene(no echos of him doing so).

So, when the enemy spawns on the bottom he would essentially be right in the middle of tons of tiles, but the "Too close!" echo is never called. Somehow it doesn't make it that far, but it also fails to spawn anything.

I tested it by putting a platform high into the sky and away from the tilemap. The enemies spawn just fine when they are nowhere near the tilemap(though, they do eventually stop spawning for no apparent reason, as if their schedule gets curtailed somehow).

Here is the full code for the spawn mechanism:

function t2dSceneObject::createHandyMan(%this)
{
   %spawnLocation = "Edges";
   %edges = "Top" TAB "Bottom" TAB "Left" TAB "Right";
   if (%spawnLocation $= "Edges")
      %spawnLocation = getField(%edges, getRandom(0, 3));
   
   switch$ (%spawnLocation)
   {
      //Area and Center saved for future use.
      //case "Area":
         //%xPos = getRandom(getWord(cameraBox.getAreaMin(), 0), getWord(cameraBox.getAreaMax(), 0));
         //%yPos = getRandom(getWord(cameraBox.getAreaMin(), 1), getWord(cameraBox.getAreaMax(), 1));
      //case "Center":
         //%xPos = cameraBox.position.x;
        // %yPos = cameraBox.position.y;
      case "Top":
         %xPos = getRandom(getWord(cameraBox.getAreaMin(), 0), getWord(cameraBox.getAreaMax(), 0));
         %yPos = getWord(cameraBox.getAreaMin(), 1);
         echo("Spawned Top!");
      case "Bottom":
         %xPos = getRandom(getWord(cameraBox.getAreaMin(), 0), getWord(cameraBox.getAreaMax(), 0));
         %yPos = getWord(cameraBox.getAreaMax(), 1);
         echo("Spawned Bottom!");
      case "Left":
         %xPos = getWord(cameraBox.getAreaMin(), 0);
         %yPos = getRandom(getWord(cameraBox.getAreaMin(), 1), getWord(cameraBox.getAreaMax(), 1));
         echo("Spawned Left!");
      case "Right":
         %xPos = getWord(cameraBox.getAreaMax(), 0);
         %yPos = getRandom(getWord(cameraBox.getAreaMin(), 1), getWord(cameraBox.getAreaMax(), 1));
         echo("Spawned Right!");
   }
   
      %position = %xPos SPC %yPos;      
      
      %objectList = %this.sceneGraph.pickRadius(%position, 30, 0xFFFFFFFF, BIT($LAYER_TERRAIN));  
      %objectCount = getWordCount(%objectList);  
      
      for(%i = 0; %i < %objectCount; %i++)  
        if (%i > 0 ) {  
            echo ("Too close!");  
            return %this.spawnHandyMan();
         } 
         
         if (%i == 0 ) {  
         
         %handyman = new t2dAnimatedSprite()
         {
            scenegraph = %this.scenegraph;
            class = enemy_class;
            position = %position;
         };
     
         %handyman.playAnimation(handyman_Anim);
         %handyman.setSize(19, 28);
         %handyman.setLayer($LAYER_TERRAIN);
         %handyman.setGraphGroup($COLLISION_G_ENEMY);
         %handyman.setCollisionMasks(BIT($COLLISION_G_ENEMY)|BIT($COLLISION_G_TERRAIN)|BIT($COLLISION_G_PLAYER)|BIT($COLLISION_G_PATTACK), BIT($LAYER_TERRAIN));  
         %handyman.setCollisionActive( true, true );
         %handyman.setCollisionPhysics(true, false);
         %handyman.setCollisionCallback(true);   
         
         echo("HandyMan Created!");
    }  
}

Any ideas?
#5
09/01/2012 (11:18 pm)
Also, I created walls at the top and bottom using tile objects, and whenever the enemy tries to spawn there, my function definitely works by finding a new locating for them.

Something with the tile map isn't working properly...

Here is what I have done to set up the tile layer and my test tile objects:

function terrainLayer_Class::onLevelLoaded(%this, %scenegraph)
{

   %this.setSize(&quot;100 100&quot;);
   %this.setLayer($LAYER_TERRAIN);
   %this.setGraphGroup($COLLISION_G_TERRAIN);
   %this.setCollisionMasks(BIT($COLLISION_G_PLAYER)|BIT($COLLISION_G_ENEMY)|BIT($COLLISION_G_EATTACK)|BIT($COLLISION_G_PATTACK), BIT($LAYER_TERRAIN));    
   %this.setCollisionActive( false, true );    
   %this.setCollisionPhysics(true, true);    
   %this.setCollisionCallback(true);   
   
   
}

The size of the tilemap and which tiles go in it was set up in the editor. Collision is set properly for each tile within, but maybe they aren't being called individually for the pickradius.

But the tile map as a whole at least should get called right?

If not, does anyone know of a way to set the attributes of each tile within the tile map through script?
#6
09/06/2012 (4:10 am)
Anyone know why pickRadius isn't detecting a tilemap or the tiles within?

Does this just not work, or am I missing something?
#7
09/07/2012 (7:04 am)
Hmm, I am probably going to have to use pickTile for the tileLayer, and pickRadius for other objects.

Looking through the docs I can't see a single method that can tie a radius, or at least my enemy's bounding box to the pickTile. PickTile uses a set position and my enemy is bigger than a single tile.

%objectlist = %this.$tileLayer.pickTile(%position)

I am thinking I may have to use pickTile 4 times, each offset to a corner of the enemy bounding box, and see if there is a tile present.

Anyone have a cleaner way to do this?
#8
09/07/2012 (10:58 am)
What I got from your posts is that you need to spawn a baddie somewhere in the level but not in any of the edge walls which surround the entire camera/playing area?
I am assuming the handy man is the bad guy? Well you could 'shrink' the spawning area by adding spacer variables.
Maybe you could pick the random positions for "case Right" like

getRandom(getWord(cameraBox.getAreaMin(), 1)+$wallWidth+($handyManWidth/2), getWord(cameraBox.getAreaMax(), 1)-$wallWidth-($handyManWidth/2));

It appears that right now you are allowing the baddies to spawn anywhere but you need to shrink their spawning area. Make sense?
#9
09/07/2012 (6:27 pm)
Where they actually spawn is working as I need it to. They spawn randomly at the edge of a box that exists just outside camera view.

What pickRadius and pickTile are trying to do, is ensure that when my enemy spawns, it will first check and see if there are any objects in the chosen spawn location. If objects are found, it aborts the spawn and starts over until an empty spawn location is found.

For instance, if my enemy spawns Bottom right now, he gets stuck in the tile layer because pickRadius isn't seeing the tiles.

So, if I can get pickTile working as needed, it should have my enemy spawning in an empty space every time.
#10
09/08/2012 (5:09 am)
So, this bit of code works up to the point where I add the "return %this.spawnHandyMan();" that crashes the game as soon as it gets called.

If I remove it, it works fine and tells me "Tile too close!" as I expected it to. And of course, when it tells me that I don't see an enemy pop out because he is stuck in the terrain somewhere...

%tileList = %this.terrainLayer_Class.pickTile(%position);  
      %tileCount = getWordCount(%tileList);  
      
      for(%h = 0; %h < %tileCount; %h++)  
        if (%h > 0 ) {  
            echo ("Tile too close!");
            return %this.spawnHandyMan();
         }

It is essentially the same as my pickRadius method, but with pickTile instead.

Any ideas?
#11
09/08/2012 (6:18 am)
Made solid progress with pickTile, but there is still some anomaly that seems to crop up quite often when I am spawning enemies.

My latest test seems to have worked giving me a console output of:

Spawned Right!
Tile too Close!
Spawned Left!
Tile too Close!
Spawned Left!
Enemy added to scene!
Handyman Created!
Enemy destroyed!
Spawned Left!
Tile too Close!

And that is where it ends. The function just ends somehow, somewhere, for no apparent reason.

As best as I can tell, it is just dropping the call of the next spawn, but I don't know how or why...

Does anyone have any experience with this or know what might cause it?

#12
09/08/2012 (6:54 am)
For reference, this is my current code. Somehow a respawn gets dropped, and it happens anywhere between 0(no spawn even at start) and 30 kills of the enemy.

function t2dSceneObject::createHandyMan(%this)
{
   %spawnLocation = "Edges";
   %edges = "Top" TAB "Bottom" TAB "Left" TAB "Right";
   if (%spawnLocation $= "Edges")
      %spawnLocation = getField(%edges, getRandom(0, 3));
   
   switch$ (%spawnLocation)
   {
      //Area and Center saved for future use.
      //case "Area":
         //%xPos = getRandom(getWord(cameraBox.getAreaMin(), 0), getWord(cameraBox.getAreaMax(), 0));
         //%yPos = getRandom(getWord(cameraBox.getAreaMin(), 1), getWord(cameraBox.getAreaMax(), 1));
      //case "Center":
         //%xPos = cameraBox.position.x;
        // %yPos = cameraBox.position.y;
      case "Top":
         %xPos = getRandom(getWord(cameraBox.getAreaMin(), 0), getWord(cameraBox.getAreaMax(), 0));
         %yPos = getWord(cameraBox.getAreaMin(), 1);
         echo("Spawned Top!");
      case "Bottom":
         %xPos = getRandom(getWord(cameraBox.getAreaMin(), 0), getWord(cameraBox.getAreaMax(), 0));
         %yPos = getWord(cameraBox.getAreaMax(), 1);
         echo("Spawned Bottom!");
      case "Left":
         %xPos = getWord(cameraBox.getAreaMin(), 0);
         %yPos = getRandom(getWord(cameraBox.getAreaMin(), 1), getWord(cameraBox.getAreaMax(), 1));
         echo("Spawned Left!");
      case "Right":
         %xPos = getWord(cameraBox.getAreaMax(), 0);
         %yPos = getRandom(getWord(cameraBox.getAreaMin(), 1), getWord(cameraBox.getAreaMax(), 1));
         echo("Spawned Right!");
   }
   
      %position = %xPos SPC %yPos;      
      
      %tileCount = $terrainLayer.pickTile(%position);  

      for(%h = 0; %h < %tileCount; %h++)  
        if (%h > 0 ) {  
            echo ("Tile too close!");
            return %this.spawnHandyMan();
         } 
      
      if (%h == 0 ) {  
      %objectList = %this.sceneGraph.pickRadius(%position, 30, 0xFFFFFFFF, BIT($LAYER_TERRAIN));  
      %objectCount = getWordCount(%objectList);  
      
      for(%i = 0; %i < %objectCount; %i++)  
        if (%i > 0 ) {  
            echo ("Too close!");
            return %this.spawnHandyMan();
         } 
         
         if (%i == 0 ) {  
         %handyman = new t2dAnimatedSprite()
         {
            scenegraph = %this.scenegraph;
            class = enemy_class;
            position = %position;
         };
     
         %handyman.playAnimation(handyman_Anim);
         %handyman.setSize(19, 28);
         %handyman.setLayer($LAYER_TERRAIN);
         %handyman.setGraphGroup($COLLISION_G_ENEMY);
         %handyman.setCollisionMasks(BIT($COLLISION_G_ENEMY)|BIT($COLLISION_G_TERRAIN)|BIT($COLLISION_G_PLAYER)|BIT($COLLISION_G_PATTACK), BIT($LAYER_TERRAIN));  
         %handyman.setCollisionActive( true, true );
         %handyman.setCollisionPhysics(true, false);
         %handyman.setCollisionCallback(true);   
         
         echo("HandyMan Created!");

    }
   }
}

function t2dSceneObject::spawnHandyMan(%this)
{
   %this.createHandyMan();
}

function enemy_class::explode(%this)
{
   %this.spawnhandyman();
   %this.schedule(50, "safeDelete");
   echo("Enemy destroyed!");
}