0
votes

I'm attempting to make a small game where the user mouses over the circles that fall from the ceiling for points. The circles are added to a container and pushed into an array to hold them, and are removed and spliced when they are mouse-over'd or go off stage.

Everything works fine, until two circles are removed at nearly the same time, whether it be from falling off stage at the same time or mousing over two of them extremely fast. When this happens, the child on stage is removed, but the object is still left in the array, meaning another circle cannot take its place, leaving one less circle spawning every time the issue happens.

Code on main timeline:

import flash.events.Event;
import flash.events.MouseEvent;
import flash.display.MovieClip;
import flash.display.Sprite;

var ballContainer:Sprite = new Sprite();
addChild(ballContainer);

var maxBalls:uint = 10;
var balls:Array = [];
var ballTypes:Array = [GreenBall];
var ballChances:Array = [800];
var ballVelocities:Array = [1.5];
var ballAccelerations:Array = [1.02];

stage.addEventListener(Event.ENTER_FRAME, onTick);
function onTick(e:Event):void {
    while (balls.length < maxBalls){
        addBall();
    }
}

function addBall():void {
    var ballType = ballTypes[0];
    var ball = new ballType;
    ball.x = Math.ceil(Math.random()*(stage.stageWidth - ball.width));
    ball.y = 0 - (ball.height*1.5);
    ballContainer.addChild(ball);
    balls.push(ball);
}

Code in GreenBall:

import flash.events.Event;

var mainStage = Sprite(root);
var index = mainStage.balls.indexOf(this);
var velocity:Number = mainStage.ballVelocities[0]*randomNumber(0.5, 1.5);
var acceleration:Number = mainStage.ballAccelerations[0];

this.addEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
function onMouseOver(e:MouseEvent):void {
    this.removeEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
    removeBall();
}

this.addEventListener(Event.ENTER_FRAME, onTick);
function onTick(e:Event):void {
    this.y += velocity;
    velocity = velocity*acceleration;
    if (this.y > stage.stageHeight + this.height){
        this.removeEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
        removeBall();
    }
}

function removeBall():void {
    mainStage.balls.splice(index, 1);//doesn't get spliced if balls are removed too quickly
    mainStage.ballContainer.removeChild(this);
    this.removeEventListener(Event.ENTER_FRAME, onTick);
}

function randomNumber(min:Number, max:Number):Number {
    return Math.random()*(max - min) + min;
}

So what's going on? Did I set something up incorrectly? How can I go about fixing this issue?

Any help would be appreciated greatly.

1

1 Answers

4
votes

Your logic is flawed - the index should be calculated when the removal occurs. When you remove objects from an array via splice, the index of all the elements after the one you removed is decreased by one.

This means that if you have 10 balls and remove the first, the index value you have for every other ball will be incorrect and you'll be removing the wrong ball from your array on subsequent removals.

Moving the indexOf statement to the removeBall method should solve the issue:

function removeBall():void
{
    var index:int = mainStage.balls.indexOf(this);

    if(index >= 0)
    {
        mainStage.balls.splice(index, 1);
        mainStage.ballContainer.removeChild(this);
        this.removeEventListener(Event.ENTER_FRAME, onTick);
    }
}

To make it easy on yourself, you could extend Array and make a remove function:

public dynamic class List extends Array
{
    public function remove(item:*):void
    {
        var i:int = indexOf(item);
        if(i >= 0) splice(i, 1);
    }
}