Hex 3-Match Game Prototype
Simple game.
Use mouse, move cell to neighbor cell. If that move makes match, you can erase matched cells.
/**
* Copyright greentec ( http://wonderfl.net/user/greentec )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/4UfX
*/
// forked from greentec's Hex 3-Match Check
package {
import com.bit101.components.PushButton;
import com.bit101.components.Label;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.KeyboardEvent;
import com.greensock.*;
import com.greensock.easing.*;
import flash.events.TimerEvent;
import flash.utils.Timer;
import net.wonderfl.score.basic.BasicScoreForm;
import net.wonderfl.score.basic.BasicScoreRecordViewer;
import flash.utils.getTimer;
public class FlashTest extends Sprite {
public var _width:int = 465;
public var _height:int = 465;
public var mapSerialArray:Vector.<Vector.<int>> = new Vector.<Vector.<int>>(); //for performance
public var neighbors:Array = [];
public var mapSize:int = 5; //6
public var map:Vector.<Vector.<Vector.<HexCell>>> = new Vector.<Vector.<Vector.<HexCell>>>(2 * mapSize + 1);
public var edgeLength:int = 20;
public var edgeW:int;
public var edgeH:int;
public var cellSprite:Sprite;
//public var blockColorArray:Array = [0xcc0000, 0x00cc00, 0x0000cc, 0xcccc00, 0x00cccc, 0xcc00cc];
public var blockColorArray:Array = [0xcc0000, 0x00cc00, 0x0000cc, 0xcccc00, 0x00cccc, 0xcc00cc];
public var matchingShape:Shape;
public var refreshButton:PushButton;
public var bottomArray:Vector.<Vector.<int>> = new Vector.<Vector.<int>>();
public var dropTimer:Timer;
public var cellMoveTimer:Timer;
public var isDrag:Boolean = false;
public var draggingHexCell:HexCell;
public var moveToHexCell:HexCell;
public var isMove:Boolean = false;
public var isFirstMove:Boolean = false;
public var isDrop:Boolean = false;
private var startTime:uint;
private var timeLabel:Label;
private var score:int;
private var scoreLabel:Label;
private var combo:int = 0;
private var restartButton:PushButton;
private var maxTime:int = 59;
private var form:BasicScoreForm;
private var ranking:BasicScoreRecordViewer;
public function FlashTest() {
// write as3 code here..
addChild(new Bitmap(new BitmapData(465, 465, false, 0x292929)));
var i:int;
for (i = 0; i < 6; i += 1)
{
neighbors[i] = [];
}
neighbors[0] = [+1, -1, 0];
neighbors[1] = [+1, 0, -1];
neighbors[2] = [0, +1, -1];
neighbors[3] = [-1, +1, 0];
neighbors[4] = [-1, 0, +1];
neighbors[5] = [0, -1, +1];
edgeW = edgeLength * 3 / 2;
edgeH = edgeLength * Math.sqrt(3) / 2;
cellSprite = new Sprite();
addChild(cellSprite);
initMap(map);
drawMap(map);
matchingShape = new Shape();
addChild(matchingShape);
scoreLabel = new Label(this, 10, 10, "Score 0");
scoreLabel.scaleX = scoreLabel.scaleY = 2;
var count:int = findMatch();
if (count > 0)
{
combo = 1;
score += count * combo;
scoreLabel.text = "Score " + String(score) + "\nCombo " + String(combo);
checkDrop();
moveDrop();
}
else
{
combo = 0;
onRefresh();
}
refreshButton = new PushButton(this, 465 - 110, 10, "Refresh", onRefresh);
refreshButton.enabled = false;
//dropTimer = new Timer(1100, 1);
startTime = getTimer();
timeLabel = new Label(this, 465 / 2, 10, "Time 1:00");
timeLabel.scaleX = timeLabel.scaleY = 2;
timeLabel.x -= timeLabel.width;
addEventListener(Event.ENTER_FRAME, onGameTimer);
restartButton = new PushButton(this, 465 / 2 - 100, 465 / 2 - 50, "Restart", onRestart);
restartButton.width = 200;
restartButton.height = 100;
restartButton.visible = false;
//stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
}
private function onRestart(e:Event):void
{
restartButton.visible = false;
score = 0;
combo = 0;
scoreLabel.text = "Score " + String(score) + "\nCombo " + String(combo);
startTime = getTimer();
addEventListener(Event.ENTER_FRAME, onGameTimer);
onRefresh();
}
private function onDropComplete(e:TimerEvent):void
{
dropTimer.stop();
isDrop = false;
var count:int = findMatch();
if (count > 0)
{
combo += 1;
score += count * combo;
scoreLabel.text = "Score " + String(score) + "\nCombo " + String(combo);
checkDrop();
moveDrop();
}
else
{
combo = 0;
}
}
private function onGameTimer(e:Event):void
{
var nowTime:uint = getTimer();
nowTime -= startTime;
if (nowTime > maxTime * 1000)
{
//game end
removeEventListener(Event.ENTER_FRAME, onGameTimer);
timeLabel.text = "Time 0:00";
restartButton.visible = true;
form = new BasicScoreForm(this, 465 / 2 - 140, 465 / 2 - 80, score, 'SAVE SCORE', onCloseForm);
return;
}
//timeLabel.text = String(nowTime);
nowTime = maxTime * 1000 - nowTime;
var seconds:int = int(nowTime / 1000) % 60;
if (seconds < 10)
{
timeLabel.text = "Time 0:0" + String(int(nowTime/ 1000) % 60);
}
else
{
timeLabel.text = "Time 0:" + String(int(nowTime/ 1000) % 60);
}
}
private function onCloseForm($didSaveScore:Boolean):void
{
if ($didSaveScore)
{
form.visible = false;
ranking = new BasicScoreRecordViewer(this, 465 / 2 - 110, 465 / 2 -120, 'RECORD RANKING', 20);
restartButton.visible = true;
}
}
private function onKeyDown(e:KeyboardEvent):void
{
switch(e.keyCode)
{
//case 32: // Space bar
//checkDrop();
//moveDrop();
//break;
}
}
private function onRefresh(e:Event = null):void
{
var i:int;
var hexCell:HexCell;
matchingShape.graphics.clear();
for (i = 0; i < mapSerialArray.length; i += 1)
{
hexCell = map[mapSerialArray[i][0] + mapSize][mapSerialArray[i][1] + mapSize][mapSerialArray[i][2] + mapSize];
hexCell._color = Math.random() * blockColorArray.length;
hexCell.drawCell(hexCell._G.graphics, blockColorArray[hexCell._color], true);
hexCell._move = false;
hexCell._remove = false;
hexCell.downCount = 0;
}
combo = 0;
var count:int = findMatch();
if (count > 0)
{
combo += 1;
score += count * combo;
scoreLabel.text = "Score " + String(score) + "\nCombo " + String(combo);
checkDrop();
moveDrop();
}
}
private function moveDrop():void
{
var i:int;
var hexCell:HexCell;
var maxDownCount:int = -1;
for (i = 0; i < mapSerialArray.length; i += 1)
{
hexCell = map[mapSerialArray[i][0] + mapSize][mapSerialArray[i][1] + mapSize][mapSerialArray[i][2] + mapSize];
if (hexCell._move == true)
{
//empty tile
if (hexCell._remove == true)
{
hexCell._color = Math.random() * blockColorArray.length;
hexCell.drawCell(hexCell._G.graphics, blockColorArray[hexCell._color], true);
//hexCell.drawCell(hexCell._GLine.graphics, 0x000000, false);
hexCell.y -= hexCell.downCount * edgeH * 2;
//hexCell._remove = false;
}
//hexCell.y -= hexCell.downCount * edgeH * 2;
TweenLite.to(hexCell, hexCell.downCount * 0.2, { ease :Bounce.easeOut,
x :hexCell.x,
y :hexCell.originalY } );
maxDownCount = Math.max(maxDownCount, hexCell.downCount);
hexCell._move = false;
hexCell._remove = false;
hexCell.downCount = 0;
}
}
if (dropTimer != null)
{
dropTimer.removeEventListener(TimerEvent.TIMER_COMPLETE, onDropComplete);
dropTimer = null;
}
isDrop = true;
dropTimer = new Timer((maxDownCount + 1) * 200, 1);
dropTimer.addEventListener(TimerEvent.TIMER_COMPLETE, onDropComplete);
dropTimer.start();
}
private function checkDrop():void
{
var i:int;
var hexCell:HexCell;
var hexCellDrop:HexCell;
var nowX:int;
var nowY:int;
var nowZ:int;
var newX:int;
var newY:int;
var newZ:int;
var removeCount:int;
var downCount:int;
for (i = 0; i < bottomArray.length; i += 1)
{
nowX = bottomArray[i][0];
nowY = bottomArray[i][1];
nowZ = bottomArray[i][2];
hexCell = map[nowX + mapSize][nowY + mapSize][nowZ + mapSize];
removeCount = 0;
downCount = 0;
if (hexCell._remove == true)
{
//hexCell._move = true;
//hexCell._remove = false;
removeCount += 1;
downCount += 1;
}
while (true)
{
nowY += 1;
nowZ -= 1;
if (calcBoundary(nowX, nowY, nowZ) == false)
{
while (true)
{
nowY -= 1;
nowZ += 1;
if (calcBoundary(nowX, nowY, nowZ) == false)
{
break;
}
hexCell = map[nowX + mapSize][nowY + mapSize][nowZ + mapSize];
if (hexCell._remove == true)
{
hexCell._move = true;
hexCell.downCount = removeCount;
}
//else
//{
//if (downCount > 0)
//{
//hexCell._move = true;
//hexCell.downCount = downCount;
//
//downCount -= 1;
//}
//}
}
break;
}
else
{
hexCell = map[nowX + mapSize][nowY + mapSize][nowZ + mapSize];
if (hexCell._remove == true)
{
//hexCell._remove = false;
removeCount += 1;
downCount += 1;
}
else if (downCount > 0)
{
hexCell._move = true;
hexCell._remove = true;
hexCell.downCount = downCount;
newX = nowX;
newY = nowY - downCount;
newZ = nowZ + downCount;
hexCellDrop = map[newX + mapSize][newY + mapSize][newZ + mapSize];
hexCellDrop.y = hexCell.y;
hexCellDrop._color = hexCell._color;
hexCellDrop._move = true;
hexCellDrop._remove = false;
hexCellDrop.downCount = downCount;
hexCellDrop.drawCell(hexCellDrop._G.graphics, blockColorArray[hexCellDrop._color], true);
}
}
}
}
}
private function findMatch():int
{
var i:int;
var hexCell:HexCell;
var hexCell2:HexCell;
var hexCell3:HexCell;
var nowX:int;
var nowY:int;
var nowZ:int;
var k:int;
var count:int = 0;
matchingShape.graphics.clear();
for (i = 0; i < mapSerialArray.length; i += 1)
{
hexCell = map[mapSerialArray[i][0] + mapSize][mapSerialArray[i][1] + mapSize][mapSerialArray[i][2] + mapSize];
for (k = 0; k < 6; k += 1)
{
nowX = mapSerialArray[i][0] + neighbors[k][0];
nowY = mapSerialArray[i][1] + neighbors[k][1];
nowZ = mapSerialArray[i][2] + neighbors[k][2];
if (calcBoundary(nowX, nowY, nowZ) == true)
{
hexCell2 = map[nowX + mapSize][nowY + mapSize][nowZ + mapSize]; //second cell
if (hexCell2._color == hexCell._color)
{
matchingShape.graphics.lineStyle(3, 0x000000, 0.7);
matchingShape.graphics.moveTo(hexCell.x, hexCell.y);
//matchingShape.graphics.lineTo(hexCell2.x, hexCell2.y);
while (true)
{
nowX += neighbors[k][0];
nowY += neighbors[k][1];
nowZ += neighbors[k][2];
if (calcBoundary(nowX, nowY, nowZ) == true)
{
hexCell3 = map[nowX + mapSize][nowY + mapSize][nowZ + mapSize]; //third and more cells
if (hexCell3._color == hexCell._color)
{
matchingShape.graphics.lineTo(hexCell3.x, hexCell3.y);
hexCell._remove = true;
hexCell2._remove = true;
hexCell3._remove = true;
count += 1;
}
else
{
break;
}
}
else
{
break;
}
}
}
}
}
}
return count;
}
private function onHexCellMouseOver(e:MouseEvent):void
{
var hexCell:HexCell = e.target.parent as HexCell;
hexCell.alpha = 0.5;
//trace(hexCell._x, hexCell._y, hexCell._z);
var k:int;
var tempX:int;
var tempY:int;
var tempZ:int;
var tempColor:int;
if (isDrag == true)
{
for (k = 0; k < 6; k += 1)
{
tempX = hexCell._x + neighbors[k][0];
tempY = hexCell._y + neighbors[k][1];
tempZ = hexCell._z + neighbors[k][2];
if (tempX == draggingHexCell._x &&
tempY == draggingHexCell._y &&
tempZ == draggingHexCell._z)
{
moveToHexCell = hexCell;
//switch color
tempColor = hexCell._color;
hexCell._color = draggingHexCell._color;
draggingHexCell._color = tempColor;
hexCell.drawCell(hexCell._G.graphics, blockColorArray[hexCell._color], true);
draggingHexCell.drawCell(draggingHexCell._G.graphics, blockColorArray[draggingHexCell._color], true);
//switch point
hexCell.x = draggingHexCell.originalX;
hexCell.y = draggingHexCell.originalY;
draggingHexCell.x = hexCell.originalX;
draggingHexCell.y = hexCell.originalY;
draggingHexCell.stopDrag();
draggingHexCell.mouseEnabled = true;
draggingHexCell.mouseChildren = true;
//move animation
TweenLite.to(hexCell, 0.5, { ease :Quart.easeOut,
x :hexCell.originalX,
y :hexCell.originalY } );
TweenLite.to(draggingHexCell, 0.5, { ease :Quart.easeOut,
x :draggingHexCell.originalX,
y :draggingHexCell.originalY } );
isMove = true;
isFirstMove = true;
if (cellMoveTimer != null)
{
cellMoveTimer.removeEventListener(TimerEvent.TIMER_COMPLETE, onCellMoveComplete);
cellMoveTimer = null;
}
cellMoveTimer = new Timer(600, 1);
cellMoveTimer.addEventListener(TimerEvent.TIMER_COMPLETE, onCellMoveComplete);
cellMoveTimer.start();
isDrag = false;
break;
}
}
}
}
private function onCellMoveComplete(e:TimerEvent):void
{
cellMoveTimer.stop();
isMove = false;
var hexCell:HexCell;
var count:int = findMatch();
if (count > 0)
{
combo += 1;
score += count * combo;
scoreLabel.text = "Score " + String(score) + "\nCombo " + String(combo);
checkDrop();
moveDrop();
}
else
{
combo = 0;
}
//canceling move
if (count == 0 && isFirstMove == true)
{
var tempColor:int;
hexCell = moveToHexCell;
//switch color
tempColor = hexCell._color;
hexCell._color = draggingHexCell._color;
draggingHexCell._color = tempColor;
hexCell.drawCell(hexCell._G.graphics, blockColorArray[hexCell._color], true);
draggingHexCell.drawCell(draggingHexCell._G.graphics, blockColorArray[draggingHexCell._color], true);
//switch point
hexCell.x = draggingHexCell.originalX;
hexCell.y = draggingHexCell.originalY;
draggingHexCell.x = hexCell.originalX;
draggingHexCell.y = hexCell.originalY;
draggingHexCell.stopDrag();
draggingHexCell.mouseEnabled = true;
draggingHexCell.mouseChildren = true;
//move animation
TweenLite.to(hexCell, 0.5, { ease :Quart.easeOut,
x :hexCell.originalX,
y :hexCell.originalY } );
TweenLite.to(draggingHexCell, 0.5, { ease :Quart.easeOut,
x :draggingHexCell.originalX,
y :draggingHexCell.originalY } );
isMove = true;
isFirstMove = false;
if (cellMoveTimer != null)
{
cellMoveTimer.removeEventListener(TimerEvent.TIMER_COMPLETE, onCellMoveComplete);
cellMoveTimer = null;
}
cellMoveTimer = new Timer(600, 1);
cellMoveTimer.addEventListener(TimerEvent.TIMER_COMPLETE, onCellMoveComplete);
cellMoveTimer.start();
}
}
private function onHexCellMouseOut(e:MouseEvent):void
{
var hexCell:HexCell = e.target.parent as HexCell;
hexCell.alpha = 1;
}
private function onHexCellStartDrag(e:MouseEvent):void
{
var hexCell:HexCell = e.target.parent as HexCell;
if (isDrag == false && isMove == false && isDrop == false)
{
draggingHexCell = hexCell;
hexCell.startDrag();
hexCell.mouseEnabled = false;
hexCell.mouseChildren = false;
isDrag = true;
}
}
//private function onHexCellStopDrag(e:MouseEvent):void
//{
//var hexCell:HexCell = e.target.parent as HexCell;
//hexCell.stopDrag();
//hexCell.x = hexCell.originalX;
//hexCell.y = hexCell.originalY;
//hexCell.mouseEnabled = true;
//hexCell.mouseChildren = true;
//
//isDrag = false;
//}
private function drawMap(map:Vector.<Vector.<Vector.<HexCell>>>):void
{
var i:int;
var hexCell:HexCell;
for (i = 0; i < mapSerialArray.length; i += 1)
{
hexCell = map[mapSerialArray[i][0] + mapSize][mapSerialArray[i][1] + mapSize][mapSerialArray[i][2] + mapSize];
hexCell._color = Math.random() * blockColorArray.length;
hexCell.drawCell(hexCell._G.graphics, blockColorArray[hexCell._color], true);
hexCell.drawCell(hexCell._GLine.graphics, 0xffffff, false);
hexCell.x = _width / 2 + hexCell._x * edgeW;
hexCell.y = _height / 2 + (0 - hexCell._y + hexCell._z) * edgeH;
hexCell.originalX = hexCell.x;
hexCell.originalY = hexCell.y;
cellSprite.addChild(hexCell);
}
//cellSprite.addEventListener(MouseEvent.CLICK, onHexCellClick, true);
cellSprite.addEventListener(MouseEvent.MOUSE_OVER, onHexCellMouseOver, true);
cellSprite.addEventListener(MouseEvent.MOUSE_OUT, onHexCellMouseOut, true);
cellSprite.addEventListener(MouseEvent.MOUSE_DOWN, onHexCellStartDrag, true);
//cellSprite.addEventListener(MouseEvent.MOUSE_UP, onHexCellStopDrag, true);
}
private function initMap(map:Vector.<Vector.<Vector.<HexCell>>>):void
{
var i:int, j:int, k:int;
var hexCell:HexCell;
var serialIndex:int = 0;
for (i = -1 * mapSize; i < mapSize + 1; i += 1)
{
map[i+mapSize] = new Vector.<Vector.<HexCell>>(2 * mapSize + 1);
for (j = -1 * mapSize; j < mapSize + 1; j += 1)
{
map[i+mapSize][j+mapSize] = new Vector.<HexCell>(2 * mapSize + 1);
for (k = -1 * mapSize; k < mapSize + 1; k += 1)
{
if (i + j + k == 0)
{
hexCell = new HexCell(i, j, k, edgeLength);
cellSprite.addChild(hexCell);
map[i + mapSize][j + mapSize][k + mapSize] = hexCell;
mapSerialArray[serialIndex] = new Vector.<int>(3);
mapSerialArray[serialIndex][0] = i;
mapSerialArray[serialIndex][1] = j;
mapSerialArray[serialIndex][2] = k;
serialIndex += 1;
}
}
}
}
//bottom array - for test drop tile
serialIndex = 0;
for (i = 0; i >= -mapSize; i -= 1)
{
bottomArray[serialIndex] = new Vector.<int>(3);
bottomArray[serialIndex][0] = -1 * (mapSize + i);
bottomArray[serialIndex][1] = i;
bottomArray[serialIndex][2] = mapSize;
//trace(bottomArray[serialIndex][0], bottomArray[serialIndex][1], bottomArray[serialIndex][2]);
serialIndex += 1;
}
for (i = 1; i <= mapSize; i += 1)
{
bottomArray[serialIndex] = new Vector.<int>(3);
bottomArray[serialIndex][0] = i;
bottomArray[serialIndex][1] = -mapSize;
bottomArray[serialIndex][2] = mapSize - i;
//trace(bottomArray[serialIndex][0], bottomArray[serialIndex][1], bottomArray[serialIndex][2]);
serialIndex += 1;
}
}
private function calcBoundary(_x:int, _y:int, _z:int):Boolean
{
if (_x + _y + _z == 0 &&
_x >= -mapSize && _x <= mapSize &&
_y >= -mapSize && _y <= mapSize &&
_z >= -mapSize && _z <= mapSize)
{
return true;
}
return false;
}
}
}
Class
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Graphics;
import flash.display.Sprite;
import flash.geom.ColorTransform;
/**
* ...
* @author ypc
*/
class HexCell extends Sprite
{
public var _x:int;
public var _y:int;
public var _z:int;
public var _G:Sprite;
public var _GLine:Sprite;
public var edgeLength:int = 20;
public var _color:int = -1;
public var _remove:Boolean = false;
public var _move:Boolean = false;
public var originalX:Number;
public var originalY:Number;
public var downCount:int;
public function HexCell(_x:int, _y:int, _z:int, edge:int=20)
{
this._x = _x;
this._y = _y;
this._z = _z;
this.edgeLength = edge;
_G = new Sprite();
_GLine = new Sprite();
addChild(_G);
addChild(_GLine);
}
public function drawCell(_G:Graphics, color:uint, fill:Boolean):void
{
var angle:Number;
_G.clear();
if (fill == true)
{
_G.beginFill(color, 0.8);
//_G.beginFill(color);
}
else
{
_G.lineStyle(1, color);
}
_G.moveTo(edgeLength, 0);
for (var i:int = 1; i <= 6; i += 1)
{
angle = 2 * Math.PI / 6 * i;
_G.lineTo(edgeLength * Math.cos(angle), edgeLength * Math.sin(angle));
}
if (fill == true)
{
_G.endFill();
}
}
}
}