1

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;
}
JNeander
  • 13
  • 5

1 Answers1

1

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

Community
  • 1
  • 1
Ethan Kennerly
  • 125
  • 1
  • 9
  • Thank you for the answer! I've changed my placeContainer function to yours, it works fine exept that on the last row it doesn't add the last bubble to the stage, no matter how many rows you set it to. Do you know why that is? I also realized I posted the wrong parkBubble function, so I've changed it in my question, could you take a look at it and tell me what I'm doing wrong? – JNeander Jul 16 '12 at 11:33
  • I think I'm about to solve the parkBubble function! If @Ethan has any thoughts why the last bubble isn't shown in placeContainer function, please let me know! :) – JNeander Jul 17 '12 at 14:24
  • One confusion might be that the variable "bubble" is used both in placeContainer and in firing. So when you fire, it will fire the last bubble. To avoid removing the last bubble from placeContainer, inside of placeContainer, create a local variable with a different than "bubble", such as "placedBubble". There might be other problems in this code or some other code. – Ethan Kennerly Jul 22 '12 at 21:43