Friday, July 20, 2012

Creating a Pentomino game using AS3: Part 2

Today we'll add automatic sizing and positioning to our grid.

I plan for my game to have multiple levels (maps), and each map may differ in size and shape. Since some maps can be rather big and take a lot of space, when smaller maps take much less space, there is a problem with positioning the grid properly so that most of the available screen is used.

I am going to reserve some space for a toolbar panel, which will later contain the available shapes and other game info. My game dimensions right now are 720x460. The panel will reserve 200 pixels in width, including the space left to the right screen edge. That means the width of the panel will be 195 pixels, its height - 450 pixels, because I'm leaving 5 pixels for the top, left and bottom margins. Keeping that in mind, the X and Y coordinates of the panel would be 520, 5 pixels.

This leaves us 520x460 free space. Inside of this rectangle, we'll put our grid. However, once again, remember that I'm leaving 5 pixel margins for top, bottom, left and right, so the actual rectangle size is 510x450. That's the size that we want to fit our grid in, making it take up as much space as possible.

Go to constructor of pentomino_game() class and call a calculateGrid() function before adding gridShape to stage:

public function pentomino_game() 
{
// default map
mapGrid = [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 0, 0, 1, 1, 1, 1],
[1, 1, 1, 1, 0, 0, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
];

// grid settings
calculateGrid();
addChild(gridShape);
gridShape.x = gridStartX;
gridShape.y = gridStartY;

// draw tiles
drawGrid();
}

First thing we do in the function is calculate how many columns and rows there are:

var columns:int = mapGrid[0].length;
var rows:int = mapGrid.length;

Write down a memo to remember the numbers we're working with:

// free size: 520x460
// fit in: 510x450

Now, using the columns value we can calculate how wide a cell should be to be able to fit in the 510 width rectangle.

// calculate width of a cell:
gridCellWidth = Math.round(510 / columns);

Then we calculate the real width and height of the grid in pixels:

var width:int = columns * gridCellWidth;
var height:int = rows * gridCellWidth;

Now we can set gridStartX value, which is the left margin of the grid. I'd set it to 5, but it's important to remember that gridCellWidth is a rounded value, it might have been a fraction and if we just set gridStartX to 5, the right marin might be bigger or smaller than 5. That's why we simply substract width from 520 and divide it by 2, to have the same margin from left and right. This might not always be 5 (it will be around 5 pixels then), but it will look nice since the margins are the same.

// calculate side margin
gridStartX = (520 - width) / 2;

Now, we check if height fits in the 450 high rectangle. If so, then we set gridStartY using the same method we set gridStartX:

if (height < 450) {
gridStartY = (450 - height) / 2;
}

If height is greater than or equals 450, we need to recalculate the whole thing, but set the height first instead of the width. Then we calculate height and width values again, and set gridStartX and gridStartY just like before:

if (height >= 450) {
gridCellWidth = Math.round(450 / rows);
height = rows * gridCellWidth;
width = columns * gridCellWidth;
gridStartY = (460 - height) / 2;
gridStartX = (520 - width) / 2;
}

Full function:

private function calculateGrid():void {
var columns:int = mapGrid[0].length;
var rows:int = mapGrid.length;

// free size: 520x460
// fit in: 510x450

// calculate width of a cell:
gridCellWidth = Math.round(510 / columns);

var width:int = columns * gridCellWidth;
var height:int = rows * gridCellWidth;

// calculate side margin
gridStartX = (520 - width) / 2;

if (height < 450) {
gridStartY = (450 - height) / 2;
}
if (height >= 450) {
gridCellWidth = Math.round(450 / rows);
height = rows * gridCellWidth;
width = columns * gridCellWidth;
gridStartY = (460 - height) / 2;
gridStartX = (520 - width) / 2;
}
}

The results can be observed when you use differently sized maps:




Full code:

package  
{
import flash.display.MovieClip;
import flash.display.Sprite;

/**
 * Open-source pentomino game engine
 * @author Kirill Poletaev
 */

public class pentomino_game extends MovieClip
{
private var mapGrid:Array = [];

private var gridShape:Sprite = new Sprite();
private var gridStartX:int;
private var gridStartY:int;
private var gridCellWidth:int;

public function pentomino_game() 
{
// default map
mapGrid = [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 0, 0, 1, 1, 1, 1],
[1, 1, 1, 1, 0, 0, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
];

// grid settings
calculateGrid();
addChild(gridShape);
gridShape.x = gridStartX;
gridShape.y = gridStartY;

// draw tiles
drawGrid();
}

private function calculateGrid():void {
var columns:int = mapGrid[0].length;
var rows:int = mapGrid.length;

// free size: 520x460
// fit in: 510x450

// calculate width of a cell:
gridCellWidth = Math.round(510 / columns);

var width:int = columns * gridCellWidth;
var height:int = rows * gridCellWidth;

// calculate side margin
gridStartX = (520 - width) / 2;

if (height < 450) {
gridStartY = (450 - height) / 2;
}
if (height >= 450) {
gridCellWidth = Math.round(450 / rows);
height = rows * gridCellWidth;
width = columns * gridCellWidth;
gridStartY = (460 - height) / 2;
gridStartX = (520 - width) / 2;
}
}

private function drawGrid():void {
gridShape.graphics.clear();
var width:int = mapGrid[0].length;
var height:int = mapGrid.length;

var i:int;
var u:int;

// draw background
for (i = 0; i < height; i++) {
for (u = 0; u < width; u++) {
if (mapGrid[i][u] == 1) drawCell(u, i, 0xffffff, 1, 0x999999);
}
}
}

private function drawCell(width:int, height:int, fill:uint, thick:Number, line:uint):void {
gridShape.graphics.beginFill(fill);
gridShape.graphics.lineStyle(thick, line);
gridShape.graphics.drawRect(width * gridCellWidth, height * gridCellWidth, gridCellWidth, gridCellWidth);
}

}

}

Thanks for reading!

No comments:

Post a Comment