Sunday, August 19, 2012

Creating a Pentomino game using AS3: Part 32

In this tutorial we'll improve user interface for saving and overwriting levels.

More specifically, we'll add the ability to cancel the saving process when the user is entering the name for the saved level, pop up a confirmation window if a save file is being overwritten and improve our class organization.

Open the game in Flash and open the save_screen MovieClip. Go to the second frame (with the input text field) and add a new button there with id btn_cancel. Add a third frame with some text saying that a file is about to be overwritten, and add 2 buttons - btn_overwrite and btn_cancel. Label them "Overwrite" and "Cancel".

Go to save_screen.as and first of all edit the removeEverything() function - only leave one line in it, and that's the line that removes the class instance from stage:

private function removeEverything():void {
this.parent.removeChild(this);
}

Go to onSaveFinal() function and instead of calling saveLevelLocal() function of Pentomino, call a local private function with the same name:

private function onSaveFinal(evt:MouseEvent):void {
saveLevelLocal(currentGrid, currentShapes, tName.text);
}

I moved the function to this class because there is no reason to have it in a separate class this time.

In saveLevelLocal(), we're going to have all the code from what used to be saveLevelLocal() in Pentomino class, however with a few modifications. The first one is that instead of immediately overwriting save file when needed, we inform the user that a level with such name already exists and let them decide on whether or not they want to overwrite the level. Add a CLICK event listener for btn_overwrite and handle the event by overwriting the data.

Call closeHandler.call() and removeEverything() after any of the operations successfully completes (level is overwritten or a new entry is added).

private 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;
var overwrite:int = overwriteIndex(levelObject.name);
if (overwrite != -1) {
// overwrite
this.gotoAndStop(3);
btn_overwrite.addEventListener(MouseEvent.CLICK, onOverwrite);
function onOverwrite(evt:MouseEvent):void {
sharedObject.data.levels[overwrite] = levelObject;
sharedObject.flush();
closeHandler.call();
removeEverything();
}
}else {
// add new
sharedObject.data.levels.push(levelObject);
sharedObject.flush();
closeHandler.call();
removeEverything();
}
}

The overwriteIndex() function also migrated from main.as to save_screen.as:

private function overwriteIndex(name:String):int {
var sharedObject:SharedObject = SharedObject.getLocal("myLevels");
var need:int = -1;
for (var i:int = 0; i < sharedObject.data.levels.length; i++) {
if (sharedObject.data.levels[i].name == name) {
need = i;
break;
}
}
return need;
}

Overall our code in save_screen.as is as follows:

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

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

public class save_screen extends MovieClip
{

private static var Pentomino:MovieClip;
private var currentGrid:Array;
private var currentShapes:Array;
private var closeHandler:Function;

public function save_screen(pentominoReference:MovieClip, getGrid:Array, getShapes:Array, onClose:Function) 
{
stop();
Pentomino = pentominoReference;
currentGrid = getGrid;
currentShapes = getShapes;
closeHandler = onClose;
btn_play.addEventListener(MouseEvent.CLICK, onPlay);
btn_save.addEventListener(MouseEvent.CLICK, onSave);
btn_cancel.addEventListener(MouseEvent.CLICK, onCancel);
}

private function onPlay(evt:MouseEvent):void {
removeEverything();
Pentomino.playLevel(currentGrid, currentShapes);
}

private function onSave(evt:MouseEvent):void {
this.gotoAndStop(2);
tName.text = Pentomino.edit.levelName;
btn_save_final.addEventListener(MouseEvent.CLICK, onSaveFinal);
}

private function onSaveFinal(evt:MouseEvent):void {
saveLevelLocal(currentGrid, currentShapes, tName.text);
}

private 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;
var overwrite:int = overwriteIndex(levelObject.name);
if (overwrite != -1) {
// overwrite
this.gotoAndStop(3);
btn_overwrite.addEventListener(MouseEvent.CLICK, onOverwrite);
function onOverwrite(evt:MouseEvent):void {
sharedObject.data.levels[overwrite] = levelObject;
sharedObject.flush();
closeHandler.call();
removeEverything();
}
}else {
// add new
sharedObject.data.levels.push(levelObject);
sharedObject.flush();
closeHandler.call();
removeEverything();
}
}

private function overwriteIndex(name:String):int {
var sharedObject:SharedObject = SharedObject.getLocal("myLevels");
var need:int = -1;
for (var i:int = 0; i < sharedObject.data.levels.length; i++) {
if (sharedObject.data.levels[i].name == name) {
need = i;
break;
}
}
return need;
}

private function onCancel(evt:MouseEvent):void {
closeHandler.call();
removeEverything();
}

private function removeEverything():void {
this.parent.removeChild(this);
}

}

}

The main.as class however is now smaller, since we removed the two functions:

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

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

public class main extends MovieClip
{
public var alreadyExists:Boolean = false;

public function main() 
{
}

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

private function clone(source:Object):*{
var myBA:ByteArray = new ByteArray();
myBA.writeObject(source);
myBA.position = 0;
return(myBA.readObject());
}

public function editLevel(levelItem:Object):void {
alreadyExists = true;
gotoAndStop(3);
edit.levelName = levelItem.name;
edit.mapGrid = levelItem.grid;
edit.calculateAndDraw();
edit.setShapes(levelItem.shapes);
}

}

}

Thanks for reading!

No comments:

Post a Comment