Saturday, August 4, 2012

Creating a Pentomino game using AS3: Part 17

Today we'll add the ability to draw holes and cells on the grid.

First of all we'll declare 3 new variables, 2 of which are booleans set to false by default, and third is a Point variable with default coordinates -1;-1.

private var canDraw:Boolean = false;
private var mouseDown:Boolean = false;
private var currentCell:Point = new Point(-1, -1);

In the constructor, add 3 new event listeners for MOUSE_DOWN, MOUSE_UP and ENTER_FRAME events:

addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
addEventListener(Event.ENTER_FRAME, onEnterFrame);

The canDraw value will be off when the canvas size window is open, and on when the window is closed. That's why we can set canDraw to false in the beginning of newLevel() and to true in the end of its editContinue() function:

private function newLevel():void {
canDraw = false;

var newScreen:MovieClip = new new_edit_screen();
addChild(newScreen);
newScreen.tWidth.restrict = "0-9";
newScreen.tHeight.restrict = "0-9";
newScreen.tWidth.text = 10;
newScreen.tHeight.text = 6;
newScreen.incorrect.alpha = 0;
newScreen.btn_continue.addEventListener(MouseEvent.CLICK, editContinue);

function editContinue(evt:MouseEvent):void {
if (newScreen.tWidth.text == "" || newScreen.tHeight.text == "" || newScreen.tWidth.text == "0" || newScreen.tHeight.text == "0") {
newScreen.incorrect.alpha = 1;
return;
}
newScreen.parent.removeChild(newScreen);
mapGrid = [];
var width:int = newScreen.tWidth.text;
var height:int = newScreen.tHeight.text;
for (var i:int = 0; i < height; i++) {
mapGrid[i] = [];
for (var u:int = 0; u < width; u++) {
mapGrid[i][u] = 1;
}
}
// grid settings
calculateGrid();
gridShape.x = gridStartX;
gridShape.y = gridStartY;

// draw tiles
drawGrid();

// canPutShape settings
canPutShape.graphics.clear();
canPutShape.graphics.lineStyle(2, 0xff0000);
canPutShape.graphics.drawRect(0, 0, gridCellWidth, gridCellWidth);
canPutShape.alpha = 0;

canDraw = true;
}
}

The mouseDown value is set to true in onMouseDown() and to false in onMouseUp(). Moreover, we set currentCell to -1;-1 point in onMouseUp():

private function onMouseDown(evt:MouseEvent):void {
mouseDown = true;
}

private function onMouseUp(evt:MouseEvent):void {
mouseDown = false;
currentCell = new Point(-1, -1)
}

We're using the currentCell variable because our drawing tool will be similar to a brush, but it also has to toggle cells (from a hole to a cell, and from a cell to a hole). If the user once clicked on a cell, it toggles its value. But since we are going to have our drawing code written in an ENTER_FRAME event handler, we need to make sure the same cell doesn't get toggled more than once.

In the onEnterFrame() function, we check if we are allowed to draw and if the mouse is held down. Then we check if the user's mouse is rolled over a cell. If it is, we check if that cell does not have the coordinates of currentCell. And if so, we toggle the value, set currentCell's coordinates to currently selected cell's coordinates and call drawGrid():

private function onEnterFrame(evt:Event):void {
// if drawing is allowed and mouse is down
if (canDraw && mouseDown) {
var mousePos:Point = new Point(Math.floor((mouseX - gridStartX) / gridCellWidth), Math.floor((mouseY - gridStartY) / gridCellWidth));
// if valid coordinates
if (mousePos.x < mapGrid[0].length && mousePos.y < mapGrid.length && mousePos.x >= 0 && mousePos.y >= 0) {
// if the cell is not "current cell"
if (mousePos.x != currentCell.x || mousePos.y != currentCell.y) {
currentCell.x = mousePos.x;
currentCell.y = mousePos.y;
if (mapGrid[mousePos.y][mousePos.x] == 1) {
mapGrid[mousePos.y][mousePos.x] = 0;
}else {
mapGrid[mousePos.y][mousePos.x] = 1;
}
drawGrid();
}
}
}
}

Full 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.sampler.NewObjectSample;
import flash.utils.ByteArray;

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

public class pentomino_editor extends MovieClip
{
private var mapGrid:Array = [];
private var shapeButtons: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 canDraw:Boolean = false;
private var mouseDown:Boolean = false;
private var currentCell:Point = new Point(-1, -1);

public function pentomino_editor() 
{
addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
addEventListener(Event.ENTER_FRAME, onEnterFrame);

// add shape buttons
for (var i:int = 0; i < 4; i++) {
for (var u:int = 0; u < 3; u++) {
var shapeButton:MovieClip = new edit_shape();
shapeButton.x = 528 + u * 62;
shapeButton.y = 15 + i * 84;
addChild(shapeButton);
shapeButton.bg.alpha = 0.3;
shapeButton.shape.gotoAndStop(3 * i + u + 1);
shapeButtons.push(shapeButton);
shapeButton.addEventListener(MouseEvent.ROLL_OVER, buttonOver);
shapeButton.addEventListener(MouseEvent.ROLL_OUT, buttonOut);
}
}

// buttons
btn_mainmenu.addEventListener(MouseEvent.CLICK, doMainmenu);
btn_reset.addEventListener(MouseEvent.CLICK, function():void{newLevel()});

// new level
newLevel();

addChild(gridShape);
addChild(canPutShape);
}

private function onMouseMove(evt:MouseEvent):void {
if(mapGrid.length>0){
var mousePos:Point = new Point(Math.floor((mouseX - gridStartX) / gridCellWidth), Math.floor((mouseY - gridStartY) / gridCellWidth));
canPutShape.x = mousePos.x * gridCellWidth + gridStartX;
canPutShape.y = mousePos.y * gridCellWidth + gridStartY;
if (mousePos.x < mapGrid[0].length && mousePos.y < mapGrid.length && mousePos.x >= 0 && mousePos.y >= 0) {
canPutShape.alpha = 1;
}else {
canPutShape.alpha = 0;
}
}
}

private function newLevel():void {
canDraw = false;

var newScreen:MovieClip = new new_edit_screen();
addChild(newScreen);
newScreen.tWidth.restrict = "0-9";
newScreen.tHeight.restrict = "0-9";
newScreen.tWidth.text = 10;
newScreen.tHeight.text = 6;
newScreen.incorrect.alpha = 0;
newScreen.btn_continue.addEventListener(MouseEvent.CLICK, editContinue);

function editContinue(evt:MouseEvent):void {
if (newScreen.tWidth.text == "" || newScreen.tHeight.text == "" || newScreen.tWidth.text == "0" || newScreen.tHeight.text == "0") {
newScreen.incorrect.alpha = 1;
return;
}
newScreen.parent.removeChild(newScreen);
mapGrid = [];
var width:int = newScreen.tWidth.text;
var height:int = newScreen.tHeight.text;
for (var i:int = 0; i < height; i++) {
mapGrid[i] = [];
for (var u:int = 0; u < width; u++) {
mapGrid[i][u] = 1;
}
}
// grid settings
calculateGrid();
gridShape.x = gridStartX;
gridShape.y = gridStartY;

// draw tiles
drawGrid();

// canPutShape settings
canPutShape.graphics.clear();
canPutShape.graphics.lineStyle(2, 0xff0000);
canPutShape.graphics.drawRect(0, 0, gridCellWidth, gridCellWidth);
canPutShape.alpha = 0;

canDraw = true;
}
}

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 buttonOver(evt:MouseEvent):void {
evt.currentTarget.bg.alpha = 1;
}

private function buttonOut(evt:MouseEvent):void {
evt.currentTarget.bg.alpha = 0.3;
}

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

private function onMouseDown(evt:MouseEvent):void {
mouseDown = true;
}

private function onMouseUp(evt:MouseEvent):void {
mouseDown = false;
currentCell = new Point(-1, -1)
}

private function onEnterFrame(evt:Event):void {
// if drawing is allowed and mouse is down
if (canDraw && mouseDown) {
var mousePos:Point = new Point(Math.floor((mouseX - gridStartX) / gridCellWidth), Math.floor((mouseY - gridStartY) / gridCellWidth));
// if valid coordinates
if (mousePos.x < mapGrid[0].length && mousePos.y < mapGrid.length && mousePos.x >= 0 && mousePos.y >= 0) {
// if the cell is not "current cell"
if (mousePos.x != currentCell.x || mousePos.y != currentCell.y) {
currentCell.x = mousePos.x;
currentCell.y = mousePos.y;
if (mapGrid[mousePos.y][mousePos.x] == 1) {
mapGrid[mousePos.y][mousePos.x] = 0;
}else {
mapGrid[mousePos.y][mousePos.x] = 1;
}
drawGrid();
}
}
}
}

}

}

Thanks for reading!

The results:


No comments:

Post a Comment