Wednesday, August 15, 2012

Creating a Pentomino game using AS3: Part 28

Today we continue working on the Saved Levels browser screen - we add the ability to play saved levels, as well as display how many cells each level has and how many times a level has been played.

First of all we need to go to main.as and add a new line to the saveLevelLocal() function. We are going to store one more value for each level, and that is the number of level plays. Add a new property to the levelObject Object called played, and set its default value to 0:

package  
{
import flash.display.MovieClip;
import flash.net.SharedObject;

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

public class main extends MovieClip
{

public function main() 
{
}

public function playLevel(grid:Array, shapes:Array):void {
gotoAndStop(2);
game.playLevel(grid, shapes);
}

public function saveLevelLocal(grid:Array, shapes:Array, levelName:String):void {
var sharedObject:SharedObject = SharedObject.getLocal("myLevels");
if (sharedObject.data.levels == null) sharedObject.data.levels = [];
var levelObject:Object = new Object;
levelObject.grid = grid;
levelObject.shapes = shapes;
levelObject.name = levelName;
levelObject.played = 0;
sharedObject.data.levels.push(levelObject);
sharedObject.flush();
}

}

}

Now go to saved_levels.as. Here in the constructor add 3 lines that add CLICK mouse event listeners and handlers. The handlers are anonymous inline functions that call playLevel() function of main pentomino class (root), as well as add 1 to current level item's play count:

public function saved_levels() 
{
savedLevels = SharedObject.getLocal("myLevels");
btn_back.addEventListener(MouseEvent.CLICK, doBack);
if (savedLevels.data.levels != null) levels = savedLevels.data.levels;
tInfo.text = levels.length + " levels (" + savedLevels.size + "B)";
pages = Math.floor(levels.length / 3) + 1;
goPage(1);
btn_previous.addEventListener(MouseEvent.CLICK, function() { goPage(currentPage - 1) } );
btn_next.addEventListener(MouseEvent.CLICK, function() { goPage(currentPage + 1) } );
item1.btn_play.addEventListener(MouseEvent.CLICK, function () { (root as MovieClip).playLevel(levels[3 * (currentPage-1)].grid, levels[3 * (currentPage-1)].shapes); savedLevels.data.levels[3 * (currentPage-1)].played++ } );
item2.btn_play.addEventListener(MouseEvent.CLICK, function () { (root as MovieClip).playLevel(levels[3 * (currentPage-1) + 1].grid, levels[3 * (currentPage-1) + 1].shapes); savedLevels.data.levels[3 * (currentPage-1)+1].played++} );
item3.btn_play.addEventListener(MouseEvent.CLICK, function () { (root as MovieClip).playLevel(levels[3 * (currentPage-1) + 2].grid, levels[3 * (currentPage-1) + 2].shapes); savedLevels.data.levels[3 * (currentPage-1)+2].played++} );
}

Now go to goPage() function. We still have 2 unused text fields in level items - tSubtitle and tSubtitle2. Let's make use of them by displaying total cell count in the first text field and play count in the second text field.

In each if...statement in goPage() function that handles a level item pass a third value to drawPreview() functions, referring to current item's tSubtitle text field. Add a line that sets current item's tSubtitle2's text value to "times played: [num]":

private function goPage(pageNum:int):void {
currentPage = pageNum;
tPage.text = "Page " + currentPage + "/" + pages;

// level items
item1.alpha = item2.alpha = item3.alpha = 0;
item1.mouseEnabled = item2.mouseEnabled = item3.mouseEnabled = false;
item1.mouseChildren = item2.mouseChildren = item3.mouseChildren = false;


if (levels[3 * (currentPage-1)] != null) {
item1.alpha = 1;
item1.mouseEnabled = true;
item1.mouseChildren = true;
item1.tTitle.text = levels[3 * (currentPage-1)].name;
countShapes(item1, levels[3 * (currentPage-1)].shapes);
drawPreview(item1.levelPreview, levels[3 * (currentPage-1)].grid, item1.tSubtitle);
item1.tSubtitle2.text = "times played: " + levels[3 * (currentPage-1)].played;
}

if (levels[3 * (currentPage-1)+1] != null) {
item2.alpha = 1;
item2.mouseEnabled = true;
item2.mouseChildren = true;
item2.tTitle.text = levels[3 * (currentPage-1) + 1].name;
countShapes(item2, levels[3 * (currentPage-1) + 1].shapes);
drawPreview(item2.levelPreview, levels[3 * (currentPage-1) + 1].grid, item2.tSubtitle);
item2.tSubtitle2.text = "times played: " + levels[3 * (currentPage-1)+1].played;
}

if (levels[3 * (currentPage-1)+2] != null) {
item3.alpha = 1;
item3.mouseEnabled = true;
item3.mouseChildren = true;
item3.tTitle.text = levels[3 * (currentPage-1) + 2].name;
countShapes(item3, levels[3 * (currentPage-1) + 2].shapes);
drawPreview(item3.levelPreview, levels[3 * (currentPage-1) + 2].grid, item3.tSubtitle);
item3.tSubtitle2.text = "times played: " + levels[3 * (currentPage-1)+2].played;
}

// page navigation
btn_previous.alpha = btn_next.alpha = 0;
btn_previous.mouseEnabled = btn_next.mouseEnabled = false;

if (currentPage > 1) {
btn_previous.alpha = 1;
btn_previous.mouseEnabled = true;
}

if (currentPage < pages) {
btn_next.alpha = 1;
btn_next.mouseEnabled = true;
}
}

We pass the value to drawPreview() because we can count total cells in its existing loop and just apply that value to subtitle's text:

private function drawPreview(levelPreview:MovieClip, mapGrid:Array, subtitle:TextField):void {
var columns:int = mapGrid[0].length;
var rows:int = mapGrid.length;
var frameWidth:int = levelPreview.width;
var frameHeight:int = levelPreview.height;
var padding:int = 5;
var fitWidth:int = levelPreview.width - (padding * 2);
var fitHeight:int = levelPreview.height - (padding * 2);
var gridStartX:int;
var gridStartY:int;

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

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

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

if (height < fitHeight) {
gridStartY = (fitHeight - height) / 2;
}
if (height >= fitHeight) {
gridCellWidth = Math.round(fitHeight / rows);
height = rows * gridCellWidth;
width = columns * gridCellWidth;
gridStartY = (frameHeight - height) / 2;
gridStartX = (frameWidth - width) / 2;
}

// draw map
levelPreview.shape.x = gridStartX;
levelPreview.shape.y = gridStartY;
levelPreview.shape.graphics.clear();
var i:int;
var u:int;

var totalCells:int = 0;
for (i = 0; i < rows; i++) {
for (u = 0; u < columns; u++) {
if (mapGrid[i][u] == 1) {
drawCell(u, i, 0xffffff, 1, 0x999999, gridCellWidth, levelPreview.shape);
totalCells++;
}
}
}
subtitle.text = totalCells + " cells";
}

Full saved_levels.as code so far:

package  
{
import fl.controls.TextInput;
import flash.display.MovieClip;
import flash.display.Shape;
import flash.events.MouseEvent;
import flash.net.SharedObject;
import flash.text.TextField;

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

public class saved_levels extends MovieClip
{
private var savedLevels:SharedObject;
private var levels:Array = [];
private var pages:int;
private var currentPage:int;

public function saved_levels() 
{
savedLevels = SharedObject.getLocal("myLevels");
btn_back.addEventListener(MouseEvent.CLICK, doBack);
if (savedLevels.data.levels != null) levels = savedLevels.data.levels;
tInfo.text = levels.length + " levels (" + savedLevels.size + "B)";
pages = Math.floor(levels.length / 3) + 1;
goPage(1);
btn_previous.addEventListener(MouseEvent.CLICK, function() { goPage(currentPage - 1) } );
btn_next.addEventListener(MouseEvent.CLICK, function() { goPage(currentPage + 1) } );
item1.btn_play.addEventListener(MouseEvent.CLICK, function () { (root as MovieClip).playLevel(levels[3 * (currentPage-1)].grid, levels[3 * (currentPage-1)].shapes); savedLevels.data.levels[3 * (currentPage-1)].played++ } );
item2.btn_play.addEventListener(MouseEvent.CLICK, function () { (root as MovieClip).playLevel(levels[3 * (currentPage-1) + 1].grid, levels[3 * (currentPage-1) + 1].shapes); savedLevels.data.levels[3 * (currentPage-1)+1].played++} );
item3.btn_play.addEventListener(MouseEvent.CLICK, function () { (root as MovieClip).playLevel(levels[3 * (currentPage-1) + 2].grid, levels[3 * (currentPage-1) + 2].shapes); savedLevels.data.levels[3 * (currentPage-1)+2].played++} );
}

private function goPage(pageNum:int):void {
currentPage = pageNum;
tPage.text = "Page " + currentPage + "/" + pages;

// level items
item1.alpha = item2.alpha = item3.alpha = 0;
item1.mouseEnabled = item2.mouseEnabled = item3.mouseEnabled = false;
item1.mouseChildren = item2.mouseChildren = item3.mouseChildren = false;


if (levels[3 * (currentPage-1)] != null) {
item1.alpha = 1;
item1.mouseEnabled = true;
item1.mouseChildren = true;
item1.tTitle.text = levels[3 * (currentPage-1)].name;
countShapes(item1, levels[3 * (currentPage-1)].shapes);
drawPreview(item1.levelPreview, levels[3 * (currentPage-1)].grid, item1.tSubtitle);
item1.tSubtitle2.text = "times played: " + levels[3 * (currentPage-1)].played;
}

if (levels[3 * (currentPage-1)+1] != null) {
item2.alpha = 1;
item2.mouseEnabled = true;
item2.mouseChildren = true;
item2.tTitle.text = levels[3 * (currentPage-1) + 1].name;
countShapes(item2, levels[3 * (currentPage-1) + 1].shapes);
drawPreview(item2.levelPreview, levels[3 * (currentPage-1) + 1].grid, item2.tSubtitle);
item2.tSubtitle2.text = "times played: " + levels[3 * (currentPage-1)+1].played;
}

if (levels[3 * (currentPage-1)+2] != null) {
item3.alpha = 1;
item3.mouseEnabled = true;
item3.mouseChildren = true;
item3.tTitle.text = levels[3 * (currentPage-1) + 2].name;
countShapes(item3, levels[3 * (currentPage-1) + 2].shapes);
drawPreview(item3.levelPreview, levels[3 * (currentPage-1) + 2].grid, item3.tSubtitle);
item3.tSubtitle2.text = "times played: " + levels[3 * (currentPage-1)+2].played;
}

// page navigation
btn_previous.alpha = btn_next.alpha = 0;
btn_previous.mouseEnabled = btn_next.mouseEnabled = false;

if (currentPage > 1) {
btn_previous.alpha = 1;
btn_previous.mouseEnabled = true;
}

if (currentPage < pages) {
btn_next.alpha = 1;
btn_next.mouseEnabled = true;
}
}

private function countShapes(levelItem:MovieClip, shapes:Array):void {
for (var i:int = 1; i <= 12; i++) {
levelItem["tShape" + i].text = shapes[i - 1];
}
}

private function drawPreview(levelPreview:MovieClip, mapGrid:Array, subtitle:TextField):void {
var columns:int = mapGrid[0].length;
var rows:int = mapGrid.length;
var frameWidth:int = levelPreview.width;
var frameHeight:int = levelPreview.height;
var padding:int = 5;
var fitWidth:int = levelPreview.width - (padding * 2);
var fitHeight:int = levelPreview.height - (padding * 2);
var gridStartX:int;
var gridStartY:int;

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

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

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

if (height < fitHeight) {
gridStartY = (fitHeight - height) / 2;
}
if (height >= fitHeight) {
gridCellWidth = Math.round(fitHeight / rows);
height = rows * gridCellWidth;
width = columns * gridCellWidth;
gridStartY = (frameHeight - height) / 2;
gridStartX = (frameWidth - width) / 2;
}

// draw map
levelPreview.shape.x = gridStartX;
levelPreview.shape.y = gridStartY;
levelPreview.shape.graphics.clear();
var i:int;
var u:int;

var totalCells:int = 0;
for (i = 0; i < rows; i++) {
for (u = 0; u < columns; u++) {
if (mapGrid[i][u] == 1) {
drawCell(u, i, 0xffffff, 1, 0x999999, gridCellWidth, levelPreview.shape);
totalCells++;
}
}
}
subtitle.text = totalCells + " cells";
}

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

private function doBack(evt:MouseEvent):void {
(root as MovieClip).gotoAndStop(1);
}
}

}

Thanks for reading!

The results:


No comments:

Post a Comment