Thursday, January 29, 2015
Creating a Pentomino game using AS3 Part 31
Firstly go to saved_levels.as class and find the lines that set tSubtitle2 text fields value and change "times played" to "times won":
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 won: " + 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 won: " + 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 won: " + 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;
}
}
Were still going to use the "played" property though.
Go to the constructor of that class and modify btn_play button handlers to pass a third parameter when calling playLevel() method. Pass the index of the level in the array:
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.ceil(levels.length / 3);
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, 3 * (currentPage-1));} );
item2.btn_play.addEventListener(MouseEvent.CLICK, function () { (root as MovieClip).playLevel(levels[3 * (currentPage-1) + 1].grid, levels[3 * (currentPage-1) + 1].shapes, 3 * (currentPage-1)+1);} );
item3.btn_play.addEventListener(MouseEvent.CLICK, function () { (root as MovieClip).playLevel(levels[3 * (currentPage-1) + 2].grid, levels[3 * (currentPage-1) + 2].shapes, 3 * (currentPage-1)+2);} );
item1.btn_edit.addEventListener(MouseEvent.CLICK, function () { (root as MovieClip).editLevel(levels[3 * (currentPage-1)])} );
item2.btn_edit.addEventListener(MouseEvent.CLICK, function () { (root as MovieClip).editLevel(levels[3 * (currentPage-1) + 1])} );
item3.btn_edit.addEventListener(MouseEvent.CLICK, function () { (root as MovieClip).editLevel(levels[3 * (currentPage-1) + 2]) } );
item1.btn_delete.addEventListener(MouseEvent.CLICK, function () { deleteLevel(3 * (currentPage-1))} );
item2.btn_delete.addEventListener(MouseEvent.CLICK, function () { deleteLevel(3 * (currentPage-1) + 1)} );
item3.btn_delete.addEventListener(MouseEvent.CLICK, function () { deleteLevel(3 * (currentPage-1) + 2)} );
}
Now go to main.as and modify playLevel() function to receive and pass the index value to games playLevel() function. Also, instead of passing grid and shapes values, pass clone(grid) and clone(shapes):
public function playLevel(grid:Array, shapes:Array, index:int):void {
gotoAndStop(2);
game.playLevel(clone(grid), clone(shapes), index);
}
The clone function ensures that a brand new array data is passed to the function, not a reference to an existing object. This is important as it prevents multiple bugs.
private function clone(source:Object):*{
var myBA:ByteArray = new ByteArray();
myBA.writeObject(source);
myBA.position = 0;
return(myBA.readObject());
}
In pentomino_game.as declare a new variable currentIndex:
private var currentIndex:int;
Set its value to received index value in playLevel. Set index value to -1 by default and an optional parameter:
public function playLevel(grid:Array, shapes:Array, index:int = -1):void {
mapGrid = grid;
availableShapes = shapes;
currentIndex = index;
// grid settings
calculateGrid();
gridShape.x = gridStartX;
gridShape.y = gridStartY;
// draw tiles
drawGrid();
// can put shape
canPutShape.x = gridStartX;
canPutShape.y = gridStartY;
// update available shapes
for (var i:int = 0; i < shapeButtons.length; i++) {
shapeButtons[i].count.text = String(availableShapes[i]);
}
}
Find the checkWin() function and in case of victory check if currentIndex does not equal -1. If so, that means we are playing a saved level and we need to increase its win count:
private function checkWin():void {
didWin = true;
var i:int;
var u:int;
var width:int = mapGrid[0].length;
var height:int = mapGrid.length;
for (i = 0; i < height; i++) {
for (u = 0; u < width; u++) {
if (mapGrid[i][u] == 1) {didWin = false;}
}
}
if (didWin) {
var winScreen:MovieClip = new win_screen(this);
addChild(winScreen);
if (currentIndex != -1) {
var savedLevels:SharedObject = SharedObject.getLocal("myLevels");
savedLevels.data.levels[currentIndex].played++;
savedLevels.flush();
}
}
}
Another bug well fix today is related to level resetting - go to resetLevel() and add a line that sets didWin to false:
public function resetLevel():void {
var i:int;
var u:int;
var width:int = mapGrid[0].length;
var height:int = mapGrid.length;
// change values in array
for (i = 0; i < height; i++) {
for (u = 0; u < width; u++) {
if (mapGrid[i][u] == 2) mapGrid[i][u] = 1;
}
}
// delete each shape
for (i = placedShapes.length-1; i >= 0; i--) {
selectedShape = placedShapes[i].currentFrame;
availableShapes[selectedShape-1]++;
shapeButtons[selectedShape-1].count.text = availableShapes[selectedShape-1];
placedShapes[i].parent.removeChild(placedShapes[i]);
placedShapes.pop();
}
placedShapes = [];
selectedShape = 0;
didWin = false;
}
Thats all for today!
Full pentomino_game.as code so far:
package
{
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.net.SharedObject;
import flash.utils.ByteArray;
/**
* Open-source pentomino game engine
* @author Kirill Poletaev
*/
public class pentomino_game extends MovieClip
{
private var mapGrid:Array = [];
private var availableShapes:Array = [];
private var shapeButtons:Array = [];
private var shapeValues:Array = [];
private var placedShapes:Array = [];
private var gridShape:Sprite = new Sprite();
private var canPutShape:Sprite = new Sprite();
private var gridStartX:int;
private var gridStartY:int;
private var gridCellWidth:int;
private var cursor:MovieClip;
private var rolledShape:MovieClip;
private var selectedShape:int = 0;
private var canPutHere:Boolean = false;
private var currentValues:Array = [];
private var didWin:Boolean = false;
private var currentIndex:int;
public function pentomino_game()
{
// default map
var defaultGrid:Array = [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
];
var defaultShapes:Array = [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2];
playLevel(defaultGrid, defaultShapes);
shapeValues = [
[[0, 0], [0, 1], [0, 2], [0, -1], [0, -2]],
[[0, 0], [0, -1], [0, 1], [1, 0], [1, -1]],
[[0, 0], [0, 1], [0, 2], [0, -1], [ -1, -1]],
[[0, 0], [0, 1], [0, -1], [ -1, 0], [1, -1]],
[[0, 0], [ -1, 0], [ -2, 0], [0, -1], [1, -1]],
[[0, 0], [0, 1], [0, -1], [1, -1], [ -1, -1]],
[[0, 0], [1, 0], [ -1, 0], [1, -1], [ -1, -1]],
[[0, 0], [ -1, 0], [ -2, 0], [0, -1], [0, -2]],
[[0, 0], [0, 1], [ -1, 1], [1, 0], [1, -1]],
[[0, 0], [0, 1], [0, -1], [1, 0], [ -1, 0]],
[[0, 0], [ -1, 0], [ -2, 0], [1, 0], [0, -1]],
[[0, 0], [0, 1], [1, 1], [0, -1], [-1, -1]]
];
addChild(gridShape);
addChild(canPutShape);
// add shape buttons
for (var i:int = 0; i < 4; i++) {
for (var u:int = 0; u < 3; u++) {
var shapeButton:MovieClip = new select_shape();
shapeButton.x = 528 + u * 62;
shapeButton.y = 55 + i * 62;
addChild(shapeButton);
shapeButton.bg.alpha = 0.3;
shapeButton.count.text = String(availableShapes[3 * i + u]);
shapeButton.shape.gotoAndStop(3 * i + u + 1);
shapeButtons.push(shapeButton);
shapeButton.addEventListener(MouseEvent.ROLL_OVER, buttonOver);
shapeButton.addEventListener(MouseEvent.ROLL_OUT, buttonOut);
shapeButton.addEventListener(MouseEvent.MOUSE_DOWN, buttonDown);
}
}
// cursor
cursor = new game_shape();
addChild(cursor);
cursor.mouseEnabled = false;
cursor.mouseChildren = false;
cursor.visible = false;
addEventListener(MouseEvent.MOUSE_MOVE, mouseMove);
addEventListener(MouseEvent.MOUSE_WHEEL, mouseWheel);
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDown);
addEventListener(Event.ENTER_FRAME, everyFrame);
addEventListener(MouseEvent.MOUSE_UP, mouseUp);
// buttons
btn_reset.addEventListener(MouseEvent.CLICK, doReset);
btn_mainmenu.addEventListener(MouseEvent.CLICK, doMainmenu);
}
public function playLevel(grid:Array, shapes:Array, index:int = -1):void {
mapGrid = grid;
availableShapes = shapes;
currentIndex = index;
// grid settings
calculateGrid();
gridShape.x = gridStartX;
gridShape.y = gridStartY;
// draw tiles
drawGrid();
// can put shape
canPutShape.x = gridStartX;
canPutShape.y = gridStartY;
// update available shapes
for (var i:int = 0; i < shapeButtons.length; i++) {
shapeButtons[i].count.text = String(availableShapes[i]);
}
}
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);
}
private function mouseMove(evt:MouseEvent):void {
cursor.x = mouseX;
cursor.y = mouseY;
checkPut();
}
private function checkPut():void {
if (selectedShape > 0) {
var mousePos:Point = new Point(Math.floor((mouseX - gridStartX) / gridCellWidth), Math.floor((mouseY - gridStartY) / gridCellWidth));
canPutHere = true;
updateCurrentValues();
for (var i:int = 0; i < currentValues.length; i++) {
var cellX:int = currentValues[i][0] + mousePos.x;
var cellY:int = currentValues[i][1] + mousePos.y;
if (cellX < 0 || cellY < 0 || cellX >= mapGrid[0].length || cellY >= mapGrid.length || mapGrid[cellY][cellX]!=1) {
canPutHere = false;
}
}
if (canPutHere) {
cursor.alpha = 0.8;
}
if (!canPutHere) {
canPutShape.graphics.clear();
cursor.alpha = 0.4;
}
}
}
private function drawCanPut():void {
canPutShape.graphics.clear();
var mousePos:Point = new Point(Math.floor((mouseX - gridStartX) / gridCellWidth), Math.floor((mouseY - gridStartY) / gridCellWidth));
for (var i:int = 0; i < currentValues.length; i++) {
var cellX:int = (currentValues[i][0] + mousePos.x) * gridCellWidth;
var cellY:int = (currentValues[i][1] + mousePos.y) * gridCellWidth;
canPutShape.graphics.beginFill(0x00ff00, 0.2);
canPutShape.graphics.drawRect(cellX, cellY, gridCellWidth, gridCellWidth);
}
}
private function mouseWheel(evt:MouseEvent):void {
if (evt.delta > 0) cursor.rotation += 90;
if (evt.delta < 0) cursor.rotation -= 90;
if (selectedShape > 0) checkPut();
}
private function keyDown(evt:KeyboardEvent):void {
if (evt.keyCode == 68) cursor.rotation += 90;
if (evt.keyCode == 65) cursor.rotation -= 90;
if (evt.keyCode == 32) cursor.scaleX *= -1;
if (selectedShape > 0) checkPut();
}
private function updateCurrentValues():void {
currentValues = clone(shapeValues[selectedShape-1]);
for (var i:int = 0; i < 5; i++) {
if (cursor.rotation == 90) {
currentValues[i].reverse();
currentValues[i][0] *= -1;
}
if (cursor.rotation == 180 || cursor.rotation == -180) {
currentValues[i][0] *= -1;
currentValues[i][1] *= -1;
}
if (cursor.rotation == -90) {
currentValues[i].reverse();
currentValues[i][1] *= -1;
}
if (cursor.scaleX < 0 && (cursor.rotation != -90 || cursor.rotation != 90)) {
currentValues[i][0] *= -1;
}
if (cursor.scaleX < 0 && (cursor.rotation == -90 || cursor.rotation == 90)) {
currentValues[i][0] *= -1;
currentValues[i][1] *= -1;
}
}
drawCanPut();
}
private function clone(source:Object):*{
var myBA:ByteArray = new ByteArray();
myBA.writeObject(source);
myBA.position = 0;
return(myBA.readObject());
}
private function startDragShape(shapeType:int, rot:int = 0, scalex:Number = 0, scaley:Number = 0):void {
cursor.rotation = rot;
cursor.scaleX = scalex;
cursor.scaleY = scaley;
if (scalex == 0) {
cursor.scaleX = gridCellWidth / 100;
cursor.scaleY = gridCellWidth / 100;
}
cursor.alpha = 0.75;
cursor.visible = true;
cursor.gotoAndStop(shapeType);
}
private function stopDragShape():void {
canPutShape.graphics.clear();
cursor.alpha = 0;
cursor.visible = false;
}
private function everyFrame(evt:Event):void {
if (rolledShape != null) {
rolledShape.rotation += 4;
}
}
private function buttonOver(evt:MouseEvent):void {
if(selectedShape==0){
evt.currentTarget.bg.alpha = 1;
rolledShape = evt.target.shape;
}
}
private function buttonOut(evt:MouseEvent):void {
evt.currentTarget.bg.alpha = 0.3;
rolledShape = null;
}
private function buttonDown(evt:MouseEvent):void {
selectedShape = evt.currentTarget.shape.currentFrame;
if(availableShapes[selectedShape-1]>0){
startDragShape(selectedShape);
availableShapes[selectedShape-1]--;
evt.currentTarget.count.text = availableShapes[selectedShape-1];
evt.currentTarget.bg.alpha = 0.3;
rolledShape = null;
}else {
selectedShape = 0;
}
}
private function mouseUp(evt:MouseEvent):void {
stopDragShape();
if (selectedShape > 0) {
if (!canPutHere) {
availableShapes[selectedShape-1]++;
shapeButtons[selectedShape-1].count.text = availableShapes[selectedShape-1];
selectedShape = 0;
}
if (canPutHere) {
var mousePos:Point = new Point(Math.floor((mouseX - gridStartX) / gridCellWidth), Math.floor((mouseY - gridStartY) / gridCellWidth));
var newShape:MovieClip = new game_shape();
addChild(newShape);
newShape.x = gridStartX + (mousePos.x+1) * gridCellWidth - gridCellWidth / 2;
newShape.y = gridStartY + (mousePos.y + 1) * gridCellWidth - gridCellWidth / 2;
newShape.rotation = cursor.rotation;
newShape.scaleX = cursor.scaleX;
newShape.scaleY = cursor.scaleY;
newShape.gotoAndStop(selectedShape);
newShape.addEventListener(MouseEvent.MOUSE_DOWN, placedShapeDown);
placedShapes.push(newShape);
for (var i:int = 0; i < currentValues.length; i++) {
var cellX:int = currentValues[i][0] + mousePos.x;
var cellY:int = currentValues[i][1] + mousePos.y;
mapGrid[cellY][cellX] = 2;
}
cursor.parent.setChildIndex(cursor, cursor.parent.numChildren - 1);
selectedShape = 0;
checkWin();
}
}
}
private function placedShapeDown(evt:MouseEvent):void {
selectedShape = evt.currentTarget.currentFrame;
// start dragging
startDragShape(evt.currentTarget.currentFrame, evt.currentTarget.rotation, evt.currentTarget.scaleX, evt.currentTarget.scaleY);
// update grid values
updateCurrentValues();
var shapePos:Point = new Point(Math.floor((evt.currentTarget.x - gridStartX) / gridCellWidth), Math.floor((evt.currentTarget.y - gridStartY) / gridCellWidth));
for (var i:int = 0; i < 5; i++) {
mapGrid[shapePos.y + currentValues[i][1]][shapePos.x + currentValues[i][0]] = 1;
}
// remove shape
for (var u:int = 0; u < placedShapes.length; u++) {
if (placedShapes[u] == evt.currentTarget) {
placedShapes.splice(u, 1);
break;
}
}
evt.currentTarget.removeEventListener(MouseEvent.MOUSE_DOWN, placedShapeDown);
evt.currentTarget.parent.removeChild(evt.currentTarget);
checkPut();
}
private function doReset(evt:MouseEvent):void {
resetLevel();
}
public function resetLevel():void {
var i:int;
var u:int;
var width:int = mapGrid[0].length;
var height:int = mapGrid.length;
// change values in array
for (i = 0; i < height; i++) {
for (u = 0; u < width; u++) {
if (mapGrid[i][u] == 2) mapGrid[i][u] = 1;
}
}
// delete each shape
for (i = placedShapes.length-1; i >= 0; i--) {
selectedShape = placedShapes[i].currentFrame;
availableShapes[selectedShape-1]++;
shapeButtons[selectedShape-1].count.text = availableShapes[selectedShape-1];
placedShapes[i].parent.removeChild(placedShapes[i]);
placedShapes.pop();
}
placedShapes = [];
selectedShape = 0;
didWin = false;
}
private function doMainmenu(evt:MouseEvent):void {
(root as MovieClip).gotoAndStop(1);
}
private function checkWin():void {
didWin = true;
var i:int;
var u:int;
var width:int = mapGrid[0].length;
var height:int = mapGrid.length;
for (i = 0; i < height; i++) {
for (u = 0; u < width; u++) {
if (mapGrid[i][u] == 1) {didWin = false;}
}
}
if (didWin) {
var winScreen:MovieClip = new win_screen(this);
addChild(winScreen);
if (currentIndex != -1) {
var savedLevels:SharedObject = SharedObject.getLocal("myLevels");
savedLevels.data.levels[currentIndex].played++;
savedLevels.flush();
}
}
}
}
}
Thanks for reading!
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.