【问题标题】:AS3: Removed Child Still Passes HitTestAS3:移除的孩子仍然通过 HitTest
【发布时间】:2015-08-04 23:11:33
【问题描述】:

我正在制作一个类似于 doodle jump 的游戏,并且我有一个道具MovieClip,每次角色弹起时都会出现。当角色与通电发生碰撞时,我希望它添加到实时乐谱中,然后消失。但我希望它在 is 被移除后重新出现,因此会有源源不断的通电(每次角色跳跃时都有一个)。

我遇到的问题是,一旦第一个道具被击中,它会在视觉上移除所有未来的道具,但角色仍然能够与它们发生碰撞 - 不断增加分数,而不仅仅是一次。

我做了一个recording,我认为这有助于解释。

这是我要修复的代码块:

//IF MyChicken TOUCHES CHICKEN LEG, SCORE GOES UP BY 2000
            for (var c:int=0; c< 1; c++){
                chickMc = powerUp[c];
                if (MyChicken.hitTestObject(chickMc))
                    {
                        liveScore += 2000;
                        theScore.text = liveScore.toString();
                        tapSnd.play();
                        removeChild(chickMc);
                    }

            }

如果它是这个块之外的东西,这是我的整个代码:

import flash.events.Event;
import flash.sensors.Accelerometer;
import flash.events.AccelerometerEvent;
import flash.display.MovieClip;
import flash.media.Sound;
import flash.events.MouseEvent;

var firstPass:int = 1;
var liveScore:int;
var accX:Number;
var myVect:Vector.<MovieClip> = new Vector.<MovieClip>(5,true);
var powerUp:Vector.<MovieClip> = new Vector.<MovieClip>(1, true);
var vAcceleration:Number = 0.5;
var vVelocity:Number = -20;
var middleScreen:Number = stage.height / 2;
//var newEnemy:enemy;
//var nmeMc:MovieClip;
var newChicken:chicken;
var chickMc:MovieClip;
var newBouncer:bouncer;
var tmpMc:MovieClip;
var poolSnd:poolSound = new poolSound();
var tapSnd:tapSound = new tapSound();
var btnAgain:gameOver;

stop();

// MONITOR THE ACCELEROMETER
var myAcc:Accelerometer = new Accelerometer();
myAcc.addEventListener(AccelerometerEvent.UPDATE, onAccUpdate);

function onAccUpdate(evt:AccelerometerEvent):void{
    accX = evt.accelerationX;   
}

//MONITOR THE ENTER_FRAME EVENT
stage.addEventListener(Event.ENTER_FRAME, onMyEnterFrame);

//INIT STAGE WITH PLATFORMS (bouncer)
if (firstPass == 1){
    liveScore = 0;
    accX = 0;

    for (var i:int=0; i< 5; i++){
        newBouncer = new bouncer;
        newBouncer.x = Math.random()*stage.stageWidth;
        newBouncer.y = 0 + i*stage.stageHeight/6;

        myVect[i] = newBouncer;
        addChild(newBouncer);
        newBouncer.cacheAsBitmap = true;}

        for (var c:int=0; c< 1; c++){
        newChicken = new chicken;
        newChicken.x = Math.random()*stage.stageWidth;
        newChicken.y = 0 + c*stage.stageHeight/6;

        powerUp[c] = newChicken;
        addChild(newChicken);
        newChicken.cacheAsBitmap = true;}

        firstPass = 2;
}

function onMyEnterFrame(evt:Event):void{

    //MOVE X DEPENDING ON THE ACCELEROMETER
    MyChicken.x += (MyChicken.x - (MyChicken.x + accX * 20))*0.6;

    //MOVE CHAR TO THE LEFT OR TO THE RIGHT
    if(accX < 0) {
        MyChicken.gotoAndStop(2);
    }else{
        MyChicken.gotoAndStop(1);
    }

    // VERTICAL SPEED OF MyChicken
    vVelocity += vAcceleration;

    if((MyChicken.y > middleScreen) && (vVelocity < 0)){
            // MyChicken IS GOING UP
            MyChicken.y += vVelocity;
        }else{
            if(vVelocity > 0){
                // MyChicken IS GOING DOWN
                MyChicken.y += vVelocity;

                // TEST IF MyChicken HITS PLATFORM
                for (var i:int=0; i< 5; i++){
                    tmpMc = myVect[i];
                    if (MyChicken.hitTestObject(tmpMc))
                        {
                            vVelocity = -20;
                            tapSnd.play();
                        }

                }

                //IF MyChicken TOUCHES CHICKEN LEG, SCORE GOES UP BY 2000
                for (var c:int=0; c< 1; c++){
                    chickMc = powerUp[c];
                    if (MyChicken.hitTestObject(chickMc))
                        {
                            liveScore += 2000;
                            theScore.text = liveScore.toString();
                            tapSnd.play();
                            removeChild(chickMc);
                        }

                }

            }else{
                // THE WORLD IS GOING DOWN
                // WHEN MyChicken IS IN THE MIDDLE OF THE SCREEN

                for (var m:int=0; m< 1; m++){
                    chickMc = powerUp[m];
                    chickMc.y -=  vVelocity;
                }

                for (var j:int=0; j< 5; j++){
                    tmpMc = myVect[j];
                    tmpMc.y -=  vVelocity;
                }

                liveScore += 5;
                theScore.text = liveScore.toString();
            }
        }

        //CHECK IF PLATFORMS ARE OUT OF THE SCREEN
        if(myVect[0] != null){
        for (var k:int=0; k< 5; k++){
                    tmpMc = myVect[k];
                    if(tmpMc.y > stage.stageHeight){
                        tmpMc.y = -5;
                        tmpMc.x =  Math.random()*stage.stageWidth;
                    }
                }
        }

        if(powerUp[0] != null){
        for (var p:int=0; p< 1; p++){
                    chickMc = powerUp[p];
                    if(chickMc.y > stage.stageHeight){
                        chickMc.y = -5;
                        chickMc.x =  Math.random()*stage.stageWidth;
                    }
                }
        }

        //FAIL - IF CHICKEN FALLS OUT OF THE SCREEN
        if  (MyChicken.y > stage.stageHeight) {
            btnAgain  = new gameOver();
            addChild(btnAgain);
            btnAgain.x = 160;
            btnAgain.y = 230;
            btnAgain.theScoreFinal.text =  liveScore.toString();
            theScore.visible = false;
            btnAgain.addEventListener(MouseEvent.MOUSE_DOWN, onPlayAgain);

            //PAUSE GAME
            MyChicken.y = -300;
            vVelocity = 0;
            vAcceleration = 0;

            // PLAY FAIL SOUND
            poolSnd.play();
        }

        // CLICKS ON THE PLAY AGAIN BUTTON
        function onPlayAgain(evt:MouseEvent):void{

            removeChild(btnAgain);

            //NEW GAME
            MyChicken.y = stage.stageHeight - 50;
            MyChicken.x = stage.stageWidth / 2;
            theScore.text = "0";
            liveScore = 0;
            vVelocity = -20;
            vAcceleration = 0.5;
            theScore.visible = true;
        }

        //STAGE BOUNDS MyChicken ON THE LEFT OR RIGHT OF THE SCREEN
        if(MyChicken.x < 0) MyChicken.x = stage.stageWidth;
        if(MyChicken.x > stage.stageWidth) MyChicken.x = 0;
    }

【问题讨论】:

    标签: actionscript-3 flash hittest removechild


    【解决方案1】:

    移除对象不会改变其x/y 坐标或宽度/高度(边界)。 hitTestObject 检查两个对象的边界——它不考虑一个对象是否真的在显示树上。因此,即使您已成功移除对象,命中测试也会继续检查它。 (因为对象仍然存在,只是看不到)

    您可以通过先检查chickMc 是否已被删除来解决此问题:

    if (chickMc.parent && MyChicken.hitTestObject(chickMc))
    

    显示对象的parent 属性在从舞台上移除后将为空。

    尽管如此,您可能希望null 对该对象的引用,以便以后可以将其作为垃圾回收:

    for (var c:int=0; c< 1; c++){
        chickMc = powerUp[c];
        if (chickMc != null && MyChicken.hitTestObject(chickMc)){
            liveScore += 2000;
            theScore.text = liveScore.toString();
            tapSnd.play();
            removeChild(chickMc);
            powerUp[c] == null; //now that powerup object isn't referenced anywhere and can be garbage collected (destroyed from memory)
        }
    }
    

    【讨论】:

    • 不要将元素设置为 null,而是考虑将其从列表中删除。然后你必须向后迭代。
    • @null - 没什么意义,除非他们改变定义向量的方式。目前它是一个固定长度的向量(毫无意义地设置为 1,但我假设他们计划在它工作后稍后添加更多元素) - 我自己更喜欢动态数组,但使用固定数组没有任何问题,它 可能我想有一点速度优势
    • @LDMS 如果对powerup 数组有很多插入/删除操作,则应用程序会泄漏内存并失去性能,计算所有那些以前是加电的nulls。 IMNSHO 不是一个好主意。
    猜你喜欢
    • 2013-10-11
    • 1970-01-01
    • 1970-01-01
    • 2012-07-02
    • 1970-01-01
    • 2013-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多