How to create a table of elements with different content - actionscript-3

How do i create a 3x3 table (in tabular form) and every cell has a different image.
But i want to create the cell and then in it add the picture of the icon, not make the icon an movieClip and directly adding it after that.
I`m trying to have 3 rows :
1st row will be Time1 ,Time2 ,Time3.
2nd row Turbo1 ,Turbo2 ,Turbo3
3rd row will be something like Speed1, Speed2, Speed3 .
Something like the picture below.
(in blue are the names of the bitmaps/movieClips/names of the pictures I am using for every icon)
i was thinking of doing it like this
private var testArr:Array = new Array();
public function MainClass()
{
for(var i:int=0; i<3; i++)
{
testArr[i]= new Array();
for(var j:int = 0 ; j<3 ; j++)
{
testArr[i][j] = new IconClass();
this.addChild(testArr[i][j]);
testArr[i][j].x=testArr[i][j].width*j + j*10;
testArr[i][j].y=testArr[i][j].height*i + i*10;
testArr[i][j].addEventListener(MouseEvent.CLICK, somethingFancy );
}
}
}
and on new IconClass(); i would pass the image that it needs to have. But! how would it be done ??

So as discussed there are a couple of useful designs. For handling the different images for different states I would create an Icon class that is a display object that handles what images to load for the different states.
That would look something like:
package
{
import flash.display.Sprite;
public class icon extends Sprite
{
private var _images:Vector.<Object>;
public var isEnabled:Boolean;
public function icon() {
_images = new Vector.<Object>();
}
//in this functions all the images you need for different states
private function addImage( state:String, bitmap:Bitmap ):void {
_images.push( { state:state, image:bitmap } );
}
//change the image of the sprite, based on the state ( i.e. - mouseOver, mouseOut )
public function changeState( state:String ):void {
var i:int;
state = isActive ? "enabled" + state : "disabled" + state;
for ( ; i < _images.length; i++ ) {
if ( _images[i].state == state ) {
updateImage( _images[i].image );
}
}
}
private function updateImage( bitmap:Bitmap ):void {
//do image changing here to new bitmap
}
}
}
And what is happening here is the icon class will have a vector of objects that associate the correct bitmap to the correct state. Now how that would be setup in your table might look something like this:
private var _iconList:Vector.<icon>;
public function MainClass():void {
createSprites();
_iconList = new Vector.<icon>();
var rows :int = 3,
columns :int = 3,
startX :int = 0, //set to some x coordinate
startY :int = 0, //set to some y coordinate
padding :int = 5,
i :int,
j :int,
currentIndex:int;
for ( i = 0; i < rows; i++ ) {
for ( j = 0; j < columns; j++ ) {
_iconList[currentIndex].x = startX + i * ( _iconList[currentIndex].width + padding );
_iconList[currentIndex].y = startY + j * ( _iconList[currentIndex].height + padding );
_iconList[currentIndex].addEventListener( MouseEvent.MOUSE_OVER, onMouseOver );
_iconList[currentIndex].addEventListener( MouseEvent.MOUSE_OUT, onMouseOut );
addChild( _iconList[currentIndex] );
currentIndex++;
}
}
}
private function createIcons():void {
var i:int;
for ( ; i < 9; i++ ) {
var ic:icon = new icon();
ic.addImage( "disabledMouseOver", "yourImageGetter()" ); //you're using a getAtlas() to a bitmap
ic.addImage( "disabledMouseOut", "yourImageGetter()" );
ic.addImage( "enabledMouseOver", "yourImageGetter()" );
ic.addImage( "enabledMouseOut", "yourImageGetter()" );
_iconList.push( ic );
}
}
private function onMouseOver( e:MouseEvent ):void {
var ic:icon = e.target as icon;
ic.changeState( "MouseOver" );
}
private function onMouseOut( e:MouseEvent ):void {
var ic:icon = e.target as icon;
ic.changeState( "MouseOut" );
}
So what's happening here:
We create an icon class that has storage for the different bitmap images and different states to associate them with
In our main class, we do createIcons() which makes new icons and adds the different images for the different states
Then we create our table with the list of icons in _iconList and add the mouse event listeners to each of them.
The listeners onMouseOver and onMouseOut call the targeted icon changeState() which will then handle the correct image to switch between.
Edit:
The isEnabled boolean is going to be used at your discretion ( as discussed in chat ) from another view to control icons that are enabled for the user and which MOUSE_OVER and MOUSE_OUT states to use.

private var iconArr:Array = new Array();
private var testArr:Array = new Array();
public function MainClass()
{
iconArr.push(
[
"time1",
"time2",
"time3"
],
[
"turbo1",
"turbo2",
"turbo3"
],
[
"speed1",
"speed2",
"speed3"
]
);
for(var i:int=0; i<3; i++)
{
testArr[i]= new Array();
for(var j:int = 0 ; j<3 ; j++)
{
//pass in a string, the icon will change depending on that string
testArr[i][j] = new IconClass(iconArr[i][j]);
this.addChild(testArr[i][j]);
testArr[i][j].x=testArr[i][j].width*j + j*10;
testArr[i][j].y=testArr[i][j].height*i + i*10;
testArr[i][j].addEventListener(MouseEvent.CLICK, somethingFancy );
}
}
}
May not fit your needs, in which case you should edit it.

Related

Action Script 3: Adding an gotoAndStop Animation

So the other day I found a tutorial on how to create a pattern lock screen in action script. To do so I had to create a class, I have a good grasp on how the class is working. But I want to add an animation so when the user goes over the dots in the pattern and animation plays. But I have no idea how to do something like this through the class. Here is the code I used in my class.
package
{
import flash.display.Sprite;
import flash.events.MouseEvent;
import fl.transitions.Tween;
import fl.transitions.easing.Strong;
public class Main extends Sprite
{
private var dots:Array = []; // Stores the in stage movieclips
private var pattern:Array = []; //The pattern entered by the user
private var pass:Array = [1,4,7,8,5,2,5]; //The correct pattern to proceed
public function Main():void
{
dots = [one,two,three,four,five,six,seven,eight,nine]; //add the clips in stage
addListeners();
}
private function addListeners():void //adds the listeners to each dot
{
var dotsLength:int = dots.length;
for (var i:int = 0; i < dotsLength; i++)
{
dots[i].addEventListener(MouseEvent.MOUSE_DOWN, initiatePattern);
dots[i].addEventListener(MouseEvent.MOUSE_UP, stopPattern);
}
}
/* Adds a mouse over listener and uses it to add the number of the dot to the pattern */
private function initiatePattern(e:MouseEvent):void
{
var dotsLength:int = dots.length;
for (var i:int = 0; i < dotsLength; i++)
{
dots[i].addEventListener(MouseEvent.MOUSE_OVER, addPattern);
}
pattern.push(dots.indexOf(e.target) + 1); //adds the array index number of the clip plus one, because arrays are 0 based
}
private function addPattern(e:MouseEvent):void
{
pattern.push(dots.indexOf(e.target) + 1); //adds the pattern on mouse over
}
private function stopPattern(e:MouseEvent):void //stops storing the pattern on mouse up
{
var dotsLength:int = dots.length;
for (var i:int = 0; i < dotsLength; i++)
{
dots[i].removeEventListener(MouseEvent.MOUSE_OVER, addPattern);
}
checkPattern();
}
private function checkPattern():void //compares the patterns
{
var pLength:int = pass.length;
var correct:int = 0;
for (var i:int = 0; i < pLength; i++) //compares each number entered in the user array to the pass array
{
if (pass[i] == pattern[i])
{
correct++;
}
}
if (correct == pLength) //if the arrays match
{
//Hides Sign In
MovieClip(root).LockScreen.visible = false;
MovieClip(root).RTID.visible = false;
MovieClip(root).SignIn.visible = false;
//Turns On Main Menu
MovieClip(root).gamemenu_mc.visible = true;
MovieClip(root).biggamesmenu_mc.visible = true;
MovieClip(root).totaltextmenu_mc.visible = true;
MovieClip(root).tmenu_mc.visible = true;
MovieClip(root).smenu_mc.visible = true;
MovieClip(root).optionsmenu_mc.visible = true;
}
pattern = []; //clears the user array
}
}
}
Easiest way I can think to do this is:
inside your dot movie clip, put a stop() action on the first frame
create your animation on the dot timeline and on the last frame of the animation put another stop().
In your mouse over function, tell the dot to play.
private function addPattern(e:MouseEvent):void
{
var dot:MovieClip = MovieClip(e.currentTarget);
if(dot.currentFrame < 2) dot.play(); //play only if on the first frame
pattern.push(dots.indexOf(dot) + 1); //adds the pattern on mouse over
}
Reset the dots animation
private function stopPattern(e:MouseEvent):void //stops storing the pattern on mouse up
{
for (var i:int = 0; i < dots.length; i++)
{
dots[i].removeEventListener(MouseEvent.MOUSE_OVER, addPattern);
dots[i].gotoAndStop(1); //go back to the first frame
}
checkPattern();
}
Alternatively, if you're just want something simple like a layer of the dot fading in/out or the size of the dot increasing, you could just use a tweening library and tween the appropriate property on mouse over.
If you wanted to draw lines to connect the dots, you could do this:
package
{
import flash.display.Sprite;
import flash.events.MouseEvent;
import fl.transitions.Tween;
import fl.transitions.easing.Strong;
import flash.display.Shape;
public class Main extends Sprite
{
private var lineContainer:Shape = new Shape();
private var dots:Array = []; // Stores the in stage movieclips
private var pattern:Array = []; //The pattern entered by the user //don't make life hard, just store the object itself instead of the index
private var pass:Array;
public function Main():void
{
dots = [one,two,three,four,five,six,seven,eight,nine]; //add the clips in stage
pass = [one,four,seven,eight,five,two,five]; //The correct pattern to proceed
addChildAt(lineContainer, this.getChildIndex(one)); //the line container right behind the first dot.
addListeners();
}
private function addListeners():void //adds the listeners to each dot
{
var dotsLength:int = dots.length;
for (var i:int = 0; i < dotsLength; i++)
{
dots[i].addEventListener(MouseEvent.MOUSE_DOWN, initiatePattern);
dots[i].addEventListener(MouseEvent.MOUSE_UP, stopPattern); //you could attach this to `this` instead of each dot, same result
}
}
/* Adds a mouse over listener and uses it to add the number of the dot to the pattern */
private function initiatePattern(e:MouseEvent):void
{
pattern = []; //reset array
lineContainer.graphics.clear(); //clear lines
for (var i:int = 0; i < dots.length; i++)
{
dots[i].addEventListener(MouseEvent.MOUSE_OVER, addPattern);
}
addPattern(e); //trigger the mouse over for this element
}
private function addPattern(e:MouseEvent):void
{
//if (pattern.indexOf(e.currentTarget) == -1) { //wrap in this if statemnt if only wanted a dot to be selected once (like Android)
pattern.push(e.currentTarget); //adds the pattern on mouse over
drawLines();
var dot:MovieClip = MovieClip(e.currentTarget);
if(dot.currentFrame < 2) dot.play(); //play only if on the first frame
//}
}
private function drawLines():void {
lineContainer.graphics.clear(); //clear the current lines
lineContainer.graphics.lineStyle(5, 0xFF0000); //thickness (5px) and color (red) of the lines
if (pattern.length > 1) { //don't draw if there aren't at least two dots in the pattern
lineContainer.graphics.moveTo(pattern[0].x + pattern[0].width * .5, pattern[0].y + pattern[0].height * .5); //move to first
for (var i:int = 1; i < pattern.length; i++) {
lineContainer.graphics.lineTo(pattern[i].x + pattern[i].width * .5, pattern[i].y + pattern[i].height * .5); //draw a line to the current dot
}
}
lineContainer.graphics.endFill();
}
private function stopPattern(e:MouseEvent):void //stops storing the pattern on mouse up
{
for (var i:int = 0; i < dots.length; i++)
{
dots[i].removeEventListener(MouseEvent.MOUSE_OVER, addPattern);
dots[i].gotoAndStop(1); //go back to the first frame
}
checkPattern();
}
private function checkPattern():void //compares the patterns
{
var pLength:int = pass.length;
var correct:int = 0;
for (var i:int = 0; i < pLength; i++) //compares each number entered in the user array to the pass array
{
if (pass[i] == pattern[i])
{
correct++;
}
}
if (correct == pLength) //if the arrays match
{
//Hides Sign In
MovieClip(root).LockScreen.visible = false;
MovieClip(root).RTID.visible = false;
MovieClip(root).SignIn.visible = false;
//Turns On Main Menu
MovieClip(root).gamemenu_mc.visible = true;
MovieClip(root).biggamesmenu_mc.visible = true;
MovieClip(root).totaltextmenu_mc.visible = true;
MovieClip(root).tmenu_mc.visible = true;
MovieClip(root).smenu_mc.visible = true;
MovieClip(root).optionsmenu_mc.visible = true;
}
pattern = []; //clears the user array
lineContainer.graphics.clear(); //clear the lines
}
}
}

AS3 - how to get mouse events on embedded bitmaps?

I'm embedding an image, creating a grid, and trying to cast each embedded image as a DisplayObject so I can use MouseEvents on each image in the grid, however, I can't get a mouseEvent to work. Any help is greatly appreciated. I think I'm missing something simple perhaps.
public class ImageGrid extends Sprite
{
private var gridItems:Array;
private var grid:Sprite;
private var sprite:Sprite
private var reveals:uint = 0;
private var exceededNumReveals:SimpleText;
[Embed(source="../Assets/images/tile-grad5-108.png")]
public var imgCls:Class;
public function ImageGrid(tileSize:Number, numTiles:Number, rows:Number)
{
gridItems = new Array();
grid = new Sprite();
addChild(grid);
for (var i:int = 0; i < numTiles; i++) {
gridItems[i] = new imgCls() as DisplayObject;
trace(gridItems[i] is DisplayObject) //true
gridItems[i].rotation = 180
gridItems[i].x = (i % rows) * (tileSize)
gridItems[i].y = int(i / rows) * (tileSize)
gridItems[i].addEventListener(MouseEvent.CLICK, gridItemClick, false, 0, false);
grid.addChild(gridItems[i]);
}
}
private function gridItemClick (event:MouseEvent):void {
trace(event.currentTarget);
reveals ++
if (reveals < AssetManager.numReveals) {
TweenLite.to(event.currentTarget, 0.5, {y:900,rotation:Math.random() * 360, ease:Sine.easeOut});
} else {
exceededNumReveals = new SimpleText ('You have exceeded your number of reveals', false, false, null, true, true, false, null, null, 20, 'right');
exceededNumReveals.y = this.y + 300;
exceededNumReveals.x = this.x + 30;
addChild(exceededNumReveals)
}
}
}
}
Here is how I fixed it:
public function ImageGrid(tileSize:Number, numTiles:Number, rows:Number)
{
gridItems = new Array();
grid = new Sprite();
addChild(grid);
for (var i:int = 0; i < numTiles; i++) {
var imageHolder:Sprite = new Sprite()
gridItems[i] = new imgCls() as DisplayObject;
gridItems[i].rotation = 180
gridItems[i].x = (i % rows) * (tileSize)
gridItems[i].y = int(i / rows) * (tileSize)
imageHolder.addChild(gridItems[i]);
imageHolder.addEventListener(MouseEvent.CLICK, gridItemClick, false, 0, false);
grid.addChild(imageHolder);
}
}
Wrap them in an interactive object (MovieClip, Sprite, etc.) to add a Mouse Click Event to them. Bitmaps are not interactive objects.
bitmaps are not interactive objects, you will have to add the listener to the parent

How to Add objects without them hitting each other

Im doing a test/game and i have bumped in a problem I cant figure out.
I am trying to add Objects (in my case Bricks) to the stage ,but adding in such a way that they never hit one other, and when there is`t any space left on the stage ,to stop adding them and to display lets say "no more space".
The stage is 500x500px and the "block" is 75px to 30px ,but I need this to be able to do the same with other objects with different width and height.
I would be very thankful to an solution for this.:)
The creating of the blocks is done in an AS.
There is a movieClip exported for AS with the name Block
package {
import flash.display.MovieClip;
import flash.events.Event;
public class MainClass extends MovieClip {
private var _blockTime:Number = 0;
private var _blockLimit:Number = 20;
private var Number_:int =0;
private var _blockHolder:MovieClip = new MovieClip();
public function MainClass() {
addEventListener(Event.ENTER_FRAME ,onEveryFrame);
this.addChild(_blockHolder)
}
private function onEveryFrame(ev:Event):void{
makeBlocks();
}
private function makeBlocks():void{
_blockTime++;
if(_blockTime >= _blockLimit){
var _block:Block = new Block();
_block.y = Blocks_YX_Positioning()
_block.x = Blocks_YX_Positioning()
_blockHolder.addChild(_block);
_blockTime = 0;
Number_++
}
}
//code so the block is staing on the stage
private function Blocks_YX_Positioning():int{
var _block_YX:int = Math.random()*500
if (_block_YX < 0 ) {
_block_YX = 50;
}
if (_block_YX > 450 ) {
_block_YX = 450;
}
return _block_YX;
}
}
}
It's as simple as implementing a 2 dimensional Array representing a grid. You don't need any collision detection.
This i how it goes. first you create an Array that represents the grid.
var arrayGrid = [];
// define number of elements in grid
var columns = Math.floor(500 / 70);
var rows = Math.floor(500 / 30);
// create the references: 1,2,3,4 etc.
for( var i = 0; i < columns * rows; i++ ) {
array[i] = i;
}
As you can see, we are putting a number in every element of the array for every element on the imaginary grid. If the grid was 5 x 5, then it would have 25 elements.
Then you make a function like putBrick that puts your bricks in the stage randomly using a number from the array. I'm using 12 as the random number. At the end of the function remove the element of the array we used as a reference. At the start of the function check if the array is empty.
if( arrayGrid.length > 0 ){
var someRandomNumber = 12;
var currentCol = someRandomNumber % columns;
var currentRow = Math.floor(someRandomNumber / columns);
brick.x = currentCol * brick.width;
brick.y = currentRow * brick.height;
array.splice(someRandomNumber,1);
} else {
trace("we are done here!");
}
You will have to tweak a few things, and find the random number, but that's the core logic.

How to make new bubbles stack in my Bubble Shooter game?

I'm making a Bubble Shooter game, and I'm trying to make the bubble I'm fireing to stack and then be at the right place in the column. The bubbles I've placed on the board looks like this:
000000000000000
000000000000000
000000000000000
000000000000000
There's 4 rows with 15 bubbles. This is the code I have written so far:
Main
package {
import flash.display.Sprite;
import flash.events.KeyboardEvent;
import flash.events.Event;
import flash.display.SpreadMethod;
public class Main extends Sprite {
private const ROT_SPEED:uint=2;
private const R:uint=18;
private const DEG_TO_RAD:Number=0.0174532925;
private const BUBBLE_SPEED:uint=10;
private var bubbleArr:Array=new Array();
private var loadArr:Array=new Array();
private var cannon:cannon_mc;
private var bubble:bubble_mc;
private var row:uint=0;
private var col:uint=0;
private var left:Boolean=false;
private var right:Boolean=false;
public var bubCont:Sprite;
private var loadCont:Sprite;
private var fire:Boolean=false;
private var vx,vy:Number;
public function Main() {
placeContainer();
placeCannon();
loadBubble();
stage.addEventListener(KeyboardEvent.KEY_DOWN,onKDown);
stage.addEventListener(KeyboardEvent.KEY_UP,onKUp);
addEventListener(Event.ENTER_FRAME,onEFrame);
trace("row= "+row+" , col= "+col);
}
private function placeCannon():void {
cannon=new cannon_mc();
addChild(cannon);
cannon.y=385.5;
cannon.x=320;
}
private function onKDown(e:KeyboardEvent):void {
switch(e.keyCode) {
case 37 :
left=true;
break;
case 39 :
right=true;
break;
case 38 :
if (! fire) {
fire=true;
var radians=(cannon.rotation-90)*DEG_TO_RAD;
vx=BUBBLE_SPEED*Math.cos(radians);
vy=BUBBLE_SPEED*Math.sin(radians);
}
break;
}
}
private function onKUp(e:KeyboardEvent):void {
switch(e.keyCode) {
case 37 :
left=false;
break;
case 39 :
right=false;
break;
}
}
private function onEFrame(e:Event):void {
if (left) {
cannon.rotation-=ROT_SPEED;
}
if (right) {
cannon.rotation+=ROT_SPEED;
}
if (fire) {
bubble.x+=vx;
bubble.y+=vy;
if (bubble.x<59) {
bubble.x=59;
vx*=-1;
}
if (bubble.x>(59+R*R)) {
bubble.x=59+R*R;
vx*=-1;
}
if (bubble.y<(40)) {
bubble.y=40;
}
}
}
public function placeContainer():void {
var iRow:Boolean=false;
bubCont=new Sprite();
addChild(bubCont);
for (var i:uint=0; i<4; i++) {
if (! iRow) {
for (var j:uint=0; j<15; j++) {
bubbleArr[i]=new Array();
bubbleArr[i][j]=Math.floor(Math.random()*6);
bubble = new bubble_mc(bubbleArr[i][j],i,j);
bubCont.addChild(bubble);
iRow=true;
row++;
col++;
}
} else {
for (j=0; j<15; j++) {
bubbleArr[i]=new Array();
bubbleArr[i][j]=Math.floor(Math.random()*6);
bubble = new bubble_mc(bubbleArr[i][j],i,j);
bubble.x=77+j*2*R;
bubCont.addChild(bubble);
iRow=false;
row++;
col++;
}
}
}
}
private function loadBubble():void {
addChild(bubble);
bubble.gotoAndStop(Math.floor(Math.random()*6))+1;
bubble.x=320;
bubble.y=410;
}
}
bubble_mc class:
package {
import flash.display.MovieClip;
public class bubble_mc extends MovieClip {
public function bubble_mc(val:uint,row:uint,col:uint) {
gotoAndStop(val+1);
name=row+"_"+col;
x=59+col*36;
y=40+row*32;
}
}
I have absolutley no idea how to make the bubbles stack together.. I have tried using hitTestObject-function and I have tried to write my own function that checks for collision and then calls a function that is supposed to place the bubble in the right place, but it doesn't work and I dont know why. I'm getting a error called TypeError: Error #1010.
Here is the collision function and the parkBubble function- which is supposed to place the bubbles in the right place:
private function parkBubble(bubble:bubble_mc,row:int,col:int):void {
var iRow:Boolean=false;
for (var j:uint=0; j<col; j++) {
trace("first for loop ");
for (var i:uint=row; i>0; i--) {
trace("second for loop ");
if (bubbleArr[i][j]!=null) {
trace("first if loop ");
if (! iRow) {
trace("second if loop ");
bubbleArr[i+1]=new Array();
bubbleArr[i+1][j]=Math.floor(Math.random()*6);
bubble = new bubble_mc(bubbleArr[i+1][j],(i+1),j);
bubCont.addChild(bubble);
iRow=true;
row++;
col++;
} else {
trace("first for loop after else ");
bubbleArr[i+1]=new Array();
bubbleArr[i+1][j]=Math.floor(Math.random()*6);
bubble = new bubble_mc(bubbleArr[i+1][j],(i+1),j);
bubble.x=77+j*2*R;
bubCont.addChild(bubble);
iRow=false;
row++;
col++;
}
}
}
}
removeChild(bubble);
fire=false;
loadBubble();
trace("slutet av parkBubble ");
}
private function collide(bub:bubble_mc):Boolean {
var dist_x:Number=bub.x-bubble.x;
var dist_y:Number=bub.y-bubble.y;
return Math.sqrt(dist_x*dist_x+dist_y*dist_y)<=2*R-4;
}
Was the TypeError on this line?
var placed_bubble:bubble_mc=new bubble_mc([row][col],row,col);
The [row] is an array, and [col] is an array. But the constructor expects an unsigned integer:
public function bubble_mc(val:uint,row:uint,col:uint) {
In order to copy the bubble to the bubble container, pass the frame number:
var placed_bubble:bubble_mc=new bubble_mc(bubble.currentFrame-1, row, col);
This might not be the only problem. TypeError often results from a variable not being defined, which could be from some other code that modifies the variable "bubble". For example, placeContainer assigns the bubbles in the container to the variable "bubble".
The function parkBubble always sets "iRow" to false, but if the bubble collides with a row above it that is odd you want iRow to be true.
var row:uint=Math.floor(bubble.y/(40+R*Math.sqrt(3)));
var iRow:Boolean= row % 2 == 1 ? true : false;
After it is at least compiling, you'll have less problems if you go back and simplify and optimize the math with some constant names. Then you'll more easily see the above code for calculating the row is not quite right. It should subtract the top margin (40). That is obvious with named constants:
private const Y_PER_ROW:int = int(R * Math.sqrt(3));
private const TOP:int = 40;
...
var row:uint = int((bubble.y - TOP) / Y_PER_ROW);
I would double-check your other calculations, too. Puzzle Bobble games usually set the odd rows to horizontally offset at radius, not at 2 radius (2 * R). So they fit together like hexagons.
The placeContainer function could be simplified. Most of the code in even or odd rows is the same, so could be taken out of the if block. And in this code you posted, I don't see why you need "row++" and "col++" in placeContainer. This is equivalent and easier to read:
for (var i:uint=0; i<4; i++) {
var xOffset:int = (i % 2) * 2 * R;
for (var j:uint=0; j<15; j++) {
bubbleArr[i] = new Array();
bubbleArr[i][j] = int(Math.random()*6);
bubble = new bubble_mc(bubbleArr[i][j], i, j);
bubble.x += xOffset;
bubCont.addChild(bubble);
row++;
col++;
}
}
Then, the collision detection code could be simplified and optimized to avoid calculations when the bubble is far away and avoid the expensive square-root calculation:
Circle Collision Detection HTML5 Canvas
http://cgp.wikidot.com/circle-to-circle-collision-detection

AS3 hitTestPoint always returns false for one function

I have a movieclip I drawn, called Map. It has a child with the name Wall. I'm trying to make a function that returns a 2d tile array of if there is something in that tile or not, for pathfinding.
The problem is, levelGrid is entirely false. I'm not sure what I am doing wrong.
I have filled the whole movieclip (Wall) with bright red, and yes it still returns false.
The x and y of both Map and Wall is 0, so I don't think there should be issues with hitTestPoint accepting global x / y.
They are added to a display list.
My other movement hittest works fine.
My code:
public function levelMap() {
for (var i = 0; i < height / 25; i++) {
levelGrid[i] = [];
for (var j = 0; j < width / 25; j++) {
levelGrid[i][j] = this.getChildByName("Wall").hitTestPoint(j*25,i*25,true);
}
}
trace(levelGrid);
}
Thanks in advance (levelGrid is a class variable)
I made a visual test out of your code. I did not change any functionality though so I think your problem is your graphics. Check the width, height och positions of the graphics. If you dont get anything in the Array, then maybe those values are not set correctly.
Each dot represent a hitTestPoint in this test. If its green you have a hit (true return value). Red means no hit. Hope this helps.
TestHitPoint.as
package
{
import flash.display.Sprite;
public class TestHitPoint extends Sprite
{
private static const TILE_SIZE : int = 25;
private var levelGrid : Array;
public function TestHitPoint()
{
// add graphics to test
addChild( new WallGraphics() );
// fix array
levelGrid = new Array();
// loop
for (var i : int = 0; i < height / TILE_SIZE; i++)
{
levelGrid[i] = [];
for (var j : int = 0; j < width / TILE_SIZE; j++)
{
var success : Boolean = this.getChildByName("Wall").hitTestPoint(j*TILE_SIZE, i*TILE_SIZE, true);
levelGrid[i][j] = success;
addChild( new PositionMarker(j*TILE_SIZE, i*TILE_SIZE, success) );
}
}
}
public function levelMap() : void
{
}
}
}
import flash.display.Sprite;
internal class WallGraphics extends Sprite
{
public function WallGraphics()
{
name = "Wall";
with(graphics)
{
beginFill(0x0000FF, 1);
drawRect(100, 50, 60, 200);
drawRect(50, 100, 200, 50);
endFill();
}
}
}
internal class PositionMarker extends Sprite
{
public function PositionMarker(posX : Number, posY : Number, success : Boolean)
{
with(graphics)
{
beginFill((success) ? 0x00FF00 : 0xFF0000, 1);
drawCircle(posX, posY, 4);
endFill();
}
}
}
Output: