topical media & game development
#graphic-player-10-cube-be-nascom-flash-util-UnitGrid.ax
#graphic-player-10-cube-be-nascom-flash-util-UnitGrid.ax
[swf]
[flash]
flex
package be.nascom.flash.util{
import flash.display.Shape;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.geom.Point;
import flash.geom.Rectangle;
public class @ax-graphic-player-10-cube-be-nascom-flash-util-UnitGrid extends EventDispatcher{
protected var _active_cells:Array;
protected var _grid_rectangle:Rectangle;
protected var _rows:uint=0;
public function get rows():uint{return _rows;}
protected var _cols:uint=0;
public function get cols():uint{return _cols;}
protected var _unit_size:uint=0;
public function get unit_size():uint{return _unit_size;}
public function get width():uint{return _unit_size*_cols;}
public function get height():uint{return _unit_size*_rows;}
protected var _test_shape:Shape;
public function get total_cells():uint{
return _cols*_rows;
}
public function @ax-graphic-player-10-cube-be-nascom-flash-util-UnitGrid(){}
public function init(rows:uint,cols:uint,unit_size:uint,test_shape:Shape=null):void{
_test_shape=test_shape;
_rows=rows;
_cols=cols;
_unit_size=unit_size;
trace("@ax-graphic-player-10-cube-be-nascom-flash-util-UnitGrid.init() rows:"+_rows+",cols:"+_cols+",unit_size:"+_unit_size);
var tot:uint=total_cells;
_active_cells=new Array();
for(var i:uint=0;i<tot;i++){
_active_cells[i]=true;
}
_grid_rectangle=new Rectangle(0,0,_cols*_unit_size,_rows*_unit_size);
dispatchEvent(new Event(Event.CHANGE));
}
protected function showInTestShape(p:Point):void{
if(_test_shape==null)return;
var color:uint=Math.floor(Math.random()*0xDF)+100000;
_test_shape.graphics.beginFill(color);
_test_shape.graphics.drawCircle(p.x,p.y,3);
_test_shape.graphics.endFill();
}
protected function checkCellIndexBounds(index:int):void{
if(!isWithinCellIndexBounds(index))throw new Error("CellGrid out of bounds cell index Error");
}
protected function isWithinCellIndexBounds(index:int):Boolean{
return index>=0 || index<total_cells;
}
public function getCenterCellIndex():uint{
return Math.round(Math.round(_rows/2)*_cols+_cols/2);
}
public function getCellXYPointByIndex(cell_index:uint):Point{
checkCellIndexBounds(cell_index);
return new Point(getCellXByIndex(cell_index),getCellYByIndex(cell_index));
}
public function getCellXByIndex(cell_index:uint):uint{
checkCellIndexBounds(cell_index);
return getColumnIndex(cell_index)*this._unit_size;
}
public function getCellYByIndex(cell_index:uint):uint{
checkCellIndexBounds(cell_index);
return getRowIndex(cell_index)*this._unit_size;
}
public function getRowIndex(cell_index:uint):uint{
return Math.floor(cell_index/_cols);
}
public function getColumnIndex(cell_index:uint):uint{
//trace("@ax-graphic-player-10-cube-be-nascom-flash-util-UnitGrid.getColumnIndex() rows:"+_rows+",cols:"+_cols+",cell_index:"+cell_index+",return:"+cell_index%_cols);
return cell_index%_cols;
}
public function indexIsActive(cell_index:uint):Boolean{
checkCellIndexBounds(cell_index);//too much?
return _active_cells[cell_index];
}
//LEFT SIDE
public function hasCellOnLeftSide(cell_index:uint):Boolean{
return getColumnIndex(cell_index) ? true : false;//if column index is 0, then it's the leftmost column
}
//use this like you use String.indexOf(), ex) if(getCellIndexToLeft(x)>-1)
public function getCellIndexToLeft(cell_index:uint):int{
checkCellIndexBounds(cell_index);
if(!hasCellOnLeftSide(cell_index))return -1;
return cell_index-1;
}
public function cellToLeftIsActive(cell_index:uint):Boolean{
if(!hasCellOnLeftSide(cell_index))return false;
return Boolean(_active_cells[getCellIndexToLeft(cell_index)]);
}
//RIGHT SIDE
public function hasCellOnRightSide(cell_index:uint):Boolean{
return getColumnIndex(cell_index)<_cols-1 ? true : false;
}
//use this like you use String.indexOf(), ex) if(getCellToRight(x)>-1)
public function getCellIndexToRight(cell_index:uint):int{
checkCellIndexBounds(cell_index);
if(!hasCellOnRightSide(cell_index))return -1;
return cell_index+1;
}
public function cellToRightIsActive(cell_index:uint):Boolean{
if(!hasCellOnRightSide(cell_index))return false;
return Boolean(_active_cells[getCellIndexToRight(cell_index)]);
}
//ABOVE
public function hasCellAbove(cell_index:uint):Boolean{
return getRowIndex(cell_index) ? true : false;
}
public function getCellIndexAbove(cell_index:uint):int{
checkCellIndexBounds(cell_index);
if(!hasCellAbove(cell_index))return -1;
return cell_index-_cols;
}
public function cellAboveIsActive(cell_index:uint):Boolean{
if(!hasCellAbove(cell_index))return false;
return Boolean(_active_cells[getCellIndexAbove(cell_index)]);
}
//BELOW
public function hasCellBelow(cell_index:uint):Boolean{
return getRowIndex(cell_index)<_rows-1 ? true : false;
}
public function getCellIndexBelow(cell_index:uint):int{
checkCellIndexBounds(cell_index);
if(!hasCellBelow(cell_index))return -1;
return cell_index+_cols;
}
/*
public function getRectRight(from_rect:Rectangle,minimum_rect:Rectangle,max_rect:Rectangle):Rectangle{
//search for a rect of minimum size, if none found:
return null;
//else return found Rectangle of maximum size
var rect:Rectangle=new Rectangle();
disableCells(rect);
return rect;
}
public function getRectUnder(from_rect:Rectangle,minimum_rect:Rectangle,max_rect:Rectangle):Rectangle{
return null;
}
public function getRectLeft(from_rect:Rectangle,minimum_rect:Rectangle,max_rect:Rectangle):Rectangle{
return null;
}
public function getSpaceOnTop(from_rect:Rectangle,minimum_rect:Rectangle,max_rect:Rectangle):Rectangle{
return null;
}
*/
public function getCellIndexContainingPoint(p:Point):int{
if(!_grid_rectangle.containsPoint(p))return -1;
var _x:uint=Math.floor(p.x/unit_size);
var _y:uint=Math.floor(p.y/unit_size);
var index:uint=_y*_cols+_x;
return index;
}
//RIGHT
protected function findSeedToTheRight(rect:Rectangle):int{
var seed:int=getCellIndexContainingPoint(new Point(rect.right,rect.top));
trace("@ax-graphic-player-10-cube-be-nascom-flash-util-UnitGrid.findSeedToTheRight() seed:"+seed);
if(seed==-1)return -1;//failsafe
var current_index:uint=this.getCellIndexToRight(seed);
if(seed==-1)return -1;
if(indexIsActive(current_index))return current_index;
//set only after conditions are met
var max_iterations:uint=Math.ceil(rect.height/_unit_size);
var cur_iteration:uint=0;
while(hasCellBelow(current_index) && cur_iteration<max_iterations){
current_index=getCellIndexBelow(current_index);
if(_active_cells[current_index])return current_index;
cur_iteration++;
}
return -1;
}
//finds first available "seed" starting from top right corner, going downwards
protected function findBiggestSquareRightDown(cell_index:uint,max_rect:Rectangle):Rectangle{
trace("CellGrid.findBiggestRectRightDown()");
var max_size:uint=Math.ceil(max_rect.width/this._unit_size);
var found:Rectangle=new Rectangle(0,0,_unit_size,_unit_size);
var down_check_cell:int=cell_index;
var right_check_cell:int=cell_index;
var check_cell:int;
var i:uint,j:uint,size:uint;
main:for(i=1;i<max_size;i++){
size=(i+1)*_unit_size;
if(size>max_rect.width)break;//this should be redundant (see main loop)
check_cell=down_check_cell=this.getCellIndexToRight(down_check_cell);
if(down_check_cell==-1)break;
//check new vertical line going down
for(j=0;j<i;j++){
if(check_cell==-1)break main;
if(!_active_cells[check_cell])break main;
check_cell=getCellIndexBelow(check_cell);
}
//check new horizontal line going right
check_cell=right_check_cell=this.getCellIndexBelow(right_check_cell);
for(j=0;j<i;j++){
if(check_cell==-1)break main;
if(!_active_cells[check_cell])break main;
check_cell=this.getCellIndexToRight(check_cell);
}
found=new Rectangle(0,0,size,size);
trace("\t"+found.toString());
}
return found;
}
public function findRectangleToTheRight(source_rect:Rectangle,min_rect:Rectangle,max_rect:Rectangle):Rectangle{
var seed:int=findSeedToTheRight(source_rect);
if(seed==-1)return null;
var biggest:Rectangle=findBiggestSquareRightDown(seed,max_rect);
biggest.x=this.getCellXByIndex(seed);
biggest.y=this.getCellYByIndex(seed);
return biggest;
}
//BELOW
protected function findSeedBelow(rect:Rectangle):int{
var seed:int=getCellIndexContainingPoint(rect.bottomRight);
trace("@ax-graphic-player-10-cube-be-nascom-flash-util-UnitGrid.findSeedBelow() seed:"+seed);
if(seed==-1)return -1;//failsafe
var current_index:uint=getCellIndexBelow(seed);
if(current_index==-1)return -1;
if(indexIsActive(current_index))return current_index;
//set only after conditions are met
var max_iterations:uint=Math.ceil(rect.height/_unit_size);
var cur_iteration:uint=0;
while(hasCellOnLeftSide(current_index) && cur_iteration<max_iterations){
current_index=getCellIndexToLeft(current_index);
if(_active_cells[current_index])return current_index;
cur_iteration++;
}
return -1;
}
//finds first available "seed" starting from bottom right corner, going left
protected function findBiggestSquareBottomRight(cell_index:uint,max_rect:Rectangle):Rectangle{
trace("CellGrid.findBiggestRectBottomRight()");
var max_size:uint=Math.ceil(max_rect.width/this._unit_size);
var found:Rectangle=new Rectangle(0,0,_unit_size,_unit_size);
var down_check_cell:int=cell_index;
var left_check_cell:int=cell_index;
var check_cell:int;
var i:uint,j:uint,size:uint;
main:for(i=1;i<max_size;i++){
size=(i+1)*_unit_size;
if(size>max_rect.width)break;//this should be redundant (see main loop)
check_cell=down_check_cell=this.getCellIndexToLeft(down_check_cell);
if(down_check_cell==-1)break;
//check new vertical line going down
for(j=0;j<i;j++){
if(check_cell==-1)break main;
if(!_active_cells[check_cell])break main;
check_cell=getCellIndexBelow(check_cell);
}
//check new horizontal line going right
check_cell=left_check_cell=this.getCellIndexBelow(left_check_cell);
if(left_check_cell==-1)break;
for(j=0;j<i;j++){
if(check_cell==-1)break main;
if(!_active_cells[check_cell])break main;
check_cell=this.getCellIndexToLeft(check_cell);
}
found=new Rectangle(0,0,size,size);
trace("\t"+found.toString());
}
return found;
}
public function findRectangleBelow(source_rect:Rectangle,min_rect:Rectangle,max_rect:Rectangle):Rectangle{
var seed:int=findSeedBelow(source_rect);
if(seed==-1)return null;
var biggest:Rectangle=findBiggestSquareBottomRight(seed,max_rect);
biggest.x=this.getCellXByIndex(seed)-biggest.width+_unit_size;//offset
//biggest.x=this.getCellXByIndex(seed);//offset
biggest.y=this.getCellYByIndex(seed);
return biggest;
}
//LEFT
//Refactor to "findNextActiveBelow(index,max_units), findNExtActiveAbove(index,max_units)
protected function findSeedToTheLeft(rect:Rectangle):int{
var seed:int=getCellIndexContainingPoint(rect.topLeft);
trace("@ax-graphic-player-10-cube-be-nascom-flash-util-UnitGrid.findSeedToTheLeft() seed:"+seed);
if(seed==-1)return -1;//failsafe
var current_index:uint=this.getCellIndexToLeft(seed);
if(seed==-1)return -1;
if(indexIsActive(current_index))return current_index;
//set only after conditions are met
var max_iterations:uint=Math.ceil(rect.height/_unit_size);
var cur_iteration:uint=0;
while(hasCellBelow(current_index) && cur_iteration<max_iterations){
current_index=getCellIndexBelow(current_index);
if(_active_cells[current_index])return current_index;
cur_iteration++;
}
return -1;
}
public function findRectangleToTheLeft(source_rect:Rectangle,min_rect:Rectangle,max_rect:Rectangle):Rectangle{
var seed:int=findSeedToTheLeft(source_rect);
if(seed==-1)return null;
var biggest:Rectangle=findBiggestSquareBottomRight(seed,max_rect);
biggest.x=this.getCellXByIndex(seed)-biggest.width+_unit_size;//offset
biggest.y=this.getCellYByIndex(seed);
return biggest;
}
//TOP
//Refactor to "findNextActiveAbove(index,max_units),
protected function findSeedAbove(rect:Rectangle):int{
var seed:int=getCellIndexContainingPoint(rect.topLeft);
//trace("@ax-graphic-player-10-cube-be-nascom-flash-util-UnitGrid.findSeedAbove() seed:"+seed);
//showInTestShape(getCellXYPointByIndex(seed));
if(seed==-1)return -1;//failsafe
var current_index:uint=this.getCellIndexAbove(seed);
if(seed==-1)return -1;
if(indexIsActive(current_index))return current_index;
//set only after conditions are met
var max_iterations:uint=Math.ceil(rect.width/_unit_size);
var cur_iteration:uint=0;
while(this.hasCellOnRightSide(current_index) && cur_iteration<max_iterations){
//trace("findSeedAbove() looping:"+cur_iteration);
current_index=this.getCellIndexToRight(current_index);
//showInTestShape(getCellXYPointByIndex(current_index));
if(_active_cells[current_index])return current_index;
cur_iteration++;
}
return -1;
}
//finds first available "seed" starting from bottom right corner, going left
protected function findBiggestSquareTopLeft(cell_index:uint,max_rect:Rectangle):Rectangle{
trace("CellGrid.findBiggestSquareTopLeft()");
var max_size:uint=Math.ceil(max_rect.width/this._unit_size);
var found:Rectangle=new Rectangle(0,0,_unit_size,_unit_size);
var up_check_cell:int,right_check_cell:int,check_cell:int;
up_check_cell=right_check_cell=check_cell=getCellIndexAbove(cell_index);
var i:uint,j:uint,size:uint;
main:for(i=0;i<max_size;i++){
size=(i+1)*_unit_size;
if(size>max_rect.width)break;//this should be redundant (see main loop)
if(up_check_cell==-1)break;
check_cell=up_check_cell;
//check new vertical line going up
for(j=0;j<i;j++){
if(check_cell==-1)break main;
if(!_active_cells[check_cell])break main;
//showInTestShape(getCellXYPointByIndex(check_cell));
check_cell=getCellIndexAbove(check_cell);
}
//check new horizontal line going right
check_cell=right_check_cell;
if(right_check_cell==-1)break;
for(j=0;j<i;j++){
if(check_cell==-1)break main;
if(!_active_cells[check_cell])break main;
//showInTestShape(getCellXYPointByIndex(check_cell));
check_cell=this.getCellIndexToRight(check_cell);
}
up_check_cell=getCellIndexToRight(up_check_cell);
right_check_cell=getCellIndexAbove(right_check_cell);
found=new Rectangle(0,0,size,size);
//trace("\t"+found.toString());
}
return found;
}
public function findRectangleAbove(source_rect:Rectangle,min_rect:Rectangle,max_rect:Rectangle):Rectangle{
var seed:int=findSeedAbove(source_rect);
trace("findRectangleAbove() source_rect:"+source_rect+" , seed:"+seed);
if(seed==-1)return null;
var biggest:Rectangle=findBiggestSquareTopLeft(seed,max_rect);
biggest.x=this.getCellXByIndex(seed);
biggest.y=this.getCellYByIndex(seed)-biggest.height;//y offset
return biggest;
}
public function disableCellsUnderRect(rect:Rectangle):void{
var top_left_index:uint=getCellIndexContainingPoint(rect.topLeft);
var bottom_right_index:uint=getCellIndexContainingPoint(rect.bottomRight);
var affected_cols:uint=getColumnIndex(bottom_right_index)-getColumnIndex(top_left_index);//plus one is a hack...
var affected_rows:uint=getRowIndex(bottom_right_index)-getRowIndex(top_left_index);//plus one is a hack...
trace("disableCellsUnderRect() affected_cols:"+affected_cols+",affected_rows"+affected_rows);
var i:uint,j:uint;
var current_index:uint=top_left_index;
var current_v_index:uint=top_left_index;
//var tot:uint=0;
for(i=0;i<=affected_rows;i++){
for(j=0;j<=affected_cols;j++){
_active_cells[current_index]=false;
current_index++;
//tot++;
//checkCellIndexBounds(current_index);
}
current_v_index=current_index=this.getCellIndexBelow(current_v_index);
}
//trace("@ax-graphic-player-10-cube-be-nascom-flash-util-UnitGrid.disableCellsUnderRect() total flagged:"+tot);
dispatchEvent(new Event(Event.CHANGE));
}
}
}
(C) Æliens
04/09/2009
You may not copy or print any of this material without explicit permission of the author or the publisher.
In case of other copyright issues, contact the author.