Game Development Community

t2dTileLayer loaded by script in Tetris game

by Pedro Vicente · in Torque Game Builder · 01/17/2010 (11:33 pm) · 9 replies

Hello everyone

I am building a Tetris game and in the process learning TGB.
I started by defining the tetrominoes (the tetris shapes) in the TGB editor as a 4X4 matrix of tiles, by filing only some matrix positions with frames from an image, for example, for the "I" tetrominoe

0 2 0 0
0 2 0 0
0 2 0 0
0 2 0 0

this generates the following code in the .t2d level file

new t2dTileLayer() {
      LayerFile = "~/RewardGames/TetrisGame/tilemaps/red_I.lyr";
      canSaveDynamicFields = "1";
      Position = "-22.000 -27.000";
      size = "16.000 16.000";
      CollisionCallback = "1";
      CollisionMaxIterations = "1";
         mountID = "3";
   };


On start I have this tilemap loaded on my scene

i973.photobucket.com/albums/ae212/psilvavicente/games/tetris1.png

Then I added a class for this definition

new t2dTileLayer() {
      ...
      class = "Shape";
      ...
   };

and an onAdd function to that class

function Shape::onAdd(%this )
{
	
	TetrisGame.shape = %this;
}

so that I can have control over this object in the main game class TetrisGame, like defining functions.

Then I tried instead of having the t2dTileLayer defined on the scene, having it defined by script on the main class

I got some tips from this forum

www.torquepowered.com/community/forums/viewthread/78502

and based on this, I moved the t2dTileLayer definition from the level file .t2d to the main class (and removed the OnAdd call)

function TetrisGame::CreateShape( %this )
{
    %shape = new t2dTileLayer()  {		
      LayerFile = "~/RewardGames/TetrisGame/tilemaps/red_I.lyr";
      canSaveDynamicFields = "1";
      class = "Shape";
      Position = "-4.930 -26.937";
      size = "16.000 16.000";
      CollisionCallback = "1";
      CollisionMaxIterations = "1";
	   mountID = "3";
   };
   
   sceneWindow2D.getSceneGraph().getGlobalTileMap().addTileLayer( %shape );  
   %shape.loadTileLayer( %shape.layerFile ); 
   
   %shape.position = TetrisGame.ShapeStartingPosition; 
   %shape.Define();
   
   %this.shape = %shape;  	
}


One thing to notice is that the tilemap appears now in another position.

i973.photobucket.com/albums/ae212/psilvavicente/games/tetris3.png
I then defined a Draw() function

The shapes are drawn by iterating over the 4X4 array and calling setStaticTile for the positions that are "filled" (the blue tile drawn at [0,0] is only for debugging purposes)

function Shape::Draw(%this)
{
	%xPos = getWord(%this.position,0);
	%yPos = getWord(%this.position,1);
		
	// draw a blue tile at matrix (0,0) 
	WellTileMap.setStaticTile( %xPos, %yPos, TetrisBlocksImageMap, 1 );	
	
	// call setStaticTile for every array position that is filled
	for ( %x = 0; %x < %this.sizex; %x++ )
	{
		for ( %y = 0; %y < %this.sizex; %y++ )
		{
			if( %this.block[ %x , %y] != 0 )
			{
				%frame = %this.block[ %x ,%y ];
				
				//setStaticTile parameters
				//  tileX: The X coordinate of the tile to set 
				//  tileY: The Y coordinate of the tile to set 
				//  imageMapName: The imagemap to set the tile to frame: 
				//  The frame of the imagemap to use 
				
				%tileX = %x + %xPos;
				%tileY = %y + %YPos;				
				
				WallTileMap.setStaticTile( %tileX, %tileY, TetrisBlocksImageMap, %frame );
			}
		}
	}
}



Calling this on the main class


function TetrisGame::onLevelLoaded( %this, %scenegraph )
{
		
	%this.CreateShape();	
	%this.shape.Draw();
	
	
}

The shape is drawn at the position I defined ,

%shape.position = TetrisGame.ShapeStartingPosition;


but the one created in TetrisGame::CreateShape is *also* drawn

i973.photobucket.com/albums/ae212/psilvavicente/games/tetris4.png
So, my question is: How can I get rid of the "first" shape?

It seems that this call


%this.shape.Draw();

should "point" only to the shape drawn relative to the WallTileMap map (that defines the walls)

I am constructing my game based in an old tutorial, but experimenting with other solutions in the way

tdn.garagegames.com/wiki/Torque_2D/Getting_Started/T2DTetrisTutorial


Thanks for reading


#1
01/17/2010 (11:38 pm)

function TetrisGame::onLevelLoaded( %this, %scenegraph )
{	
   // set the starting position to the middle of the wall 
	
	%this.ShapeStartingPosition = WellTileMap.getTileCountX()/2 SPC 0;
	
	// create the tetromimoes
	
	%this.CreateShapes();	
		
        // draw a first shape in the wall
	
	%this.shape.Draw();
	
	// start
	
	%this.Fall();		
}
#2
01/17/2010 (11:39 pm)


TetrisGame.ShapeStartingPosition is defined at the upper middle of the wall. The wall is 12X18, so the blue tile of the shape is drawn at (6,0)
#3
01/18/2010 (9:01 am)
Hey, pedro, I'm still processing your post, but first, you can edit your forum posts by clicking the icon that resembles a pencil in the upper right of the post to edit
#4
01/18/2010 (9:13 am)
1) what is the definition of TetrisGame.ShapeStartingPosition

2) In "CreateShape" you are loading in a t2dTileLayer which is displayed by TGB
then in "Draw" you are modifying your wall layer to have tiles that resemble the "Shape" you loaded in as a t2dTileLayer, so in screen shot 4, the top image is merely tiles on the "wall tile layer", while the layer you loaded in is at position 0,0 (which is the center of the screen)
i973.photobucket.com/albums/ae212/psilvavicente/games/tetris4.png
3) Are you intending for the motion to be smooth or are you intending for the shape to move by having the tiles change on the wall tile layer?
#5
01/18/2010 (12:28 pm)
thanks, David. A reply to 1) is posted in #1 and #2.

2) that' right. Having the "shape" tiles drawn in the "wall tile layer" is convenient because I have a coordinate system relative to the wall, so I can do all the game logic based on that.

3) For the shape to move by having the tiles change on the wall tile layer. I intend the shapes to fall at every time step. For example, by a schedule function that moves it in the Y axis 1 position every second.
For this to work, the previous shape has to be erased

function TetrisGame::Fall( %this )
{
	%this.shape.Move( 0, 1); 
	%this.shape.Draw(); 
	%this.schedule( 1000, Fall );
	
}

function Shape::Move(%this, %dx, %dy)
{
	%x = getWord( %this.position, 0 );
	%y = getWord( %this.position, 1 );
	%this.position = %x + %dx SPC %y + %dy;
}



#6
01/18/2010 (2:13 pm)
ah well, to remove the original shape layer, you can just set
%shape.visible = false;
whenever you create a shape

that way you'll only see the Wall layer that'll display what you set in "Draw"

additionally, there's a lot of extra code and processing associated with tileLayers (since they can be displayed and such)

you may want to consider creating your shapes in text files that you read in and store as arrays rather than whole tile layers per shape
#7
01/18/2010 (7:00 pm)
You could replace the Move code through a single line by the way:

%this.position = t2dVectorAdd( %this.position, "0 1" );
#8
01/19/2010 (12:21 am)
@Mark

thanks, I could, but I am learning Torque Script, and I like to keep things simple, C/C++ like syntax. I defined the shape position with 2 variables for the (X,Y) position instead.

function Shape2::Move(%this, %dx, %dy)
{	
	%this.PositionX = %this.PositionX + %dx;
	%this.PositionY = %this.PositionY + %dy;	
}
#9
01/19/2010 (12:49 am)
@David

you are right on spot, I don't need my shapes to be t2dTileLayer instances at all, with the overhead that comes with it. I was doing so because I defined the shapes in the TGB editor as 4X4 tilemaps and saved them to tilemap files. The block matrix was being initiated for a shape by reading each frame from the file

%type = %this.getTileType(%x, %y);
	// index of frame in image map
	// format is "static imageMapName imageMap-Frame"
	%frame = getword( %type, 2); 
	%this.block[%x, %y] = %frame;

but this matrix array information can be instead defined simply by script. This thread shows how to define a OOP style Torque Script class

www.torquepowered.com/community/forums/viewthread/27384

and based on this I defined a new class for the shapes, based in the ScriptObject class. Nice to know that there is a constructor/destructor mechanism in Torque

function Shape::onAdd(%this)
{
	// set the starting position to the middle of the wall 
	%this.PositionX = WellTileMap.getTileCountX() / 2;
	%this.PositionY = 0;
	
	// size of each block
	%this.SizeX = 4;
	%this.SizeY = 4;
   	
	for( %x = 0; %x < %this.SizeX; %x++)
	{
		for( %y = 0; %y < %this.SizeY; %y++)
		{
			%this.block[%x, %y] = 0; 
		}
	}
	
	// red_I is defined as, 2 is the frame index in the blocks image
   // 0 2 0 0
   // 0 2 0 0 
   // 0 2 0 0
   // 0 2 0 0
   
   %this.block[1,0] = 2; 
   %this.block[1,1] = 2;
   %this.block[1,2] = 2;
   %this.block[1,3] = 2;
}

function Shape::onRemove(%this)
{
   
}

function Shape::Move(%this, %dx, %dy)
{	
	%this.PositionX = %this.PositionX + %dx;
	%this.PositionY = %this.PositionY + %dy;
	
}

function Shape::Draw(%this)
{
	// draw a blue tile at current position  
	WellTileMap.setStaticTile( %this.PositionX, %this.Positiony, TetrisBlocksImageMap, 1 );

	// call setStaticTile for every array position that is filled
	for ( %x = 0; %x < %this.SizeX; %x++ )
	{
		for ( %y = 0; %y < %this.SizeX; %y++ )
		{
			if( %this.block[ %x, %y ] != 0 )
			{
				%frame = %this.block[ %x, %y ];
				
				//setStaticTile parameters
				//  tileX: The X coordinate of the tile to set 
				//  tileY: The Y coordinate of the tile to set 
				//  imageMapName: The imagemap to set the tile to frame: 
				//  The frame of the imagemap to use 
				
				%tileX = %this.PositionX + %x;
				%tileY = %this.PositionY + %y;
				
				WellTileMap.setStaticTile( %tileX, %tileY, TetrisBlocksImageMap, %frame );
			}
		}
	}
}


The shape instance is then initialized as

function TetrisGame::onLevelLoaded( %this, %scenegraph )
{
	// create a shape
	
	%shape = new ScriptObject(Shape)
	{
	
	};

	%shape.Draw();
	%this.shape = %shape;
	%this.Fall();
	
}