如何摆脱已经实例化的对象的非null hitTestObject错误?

时间:2012-09-24 07:09:32

标签: actionscript-3 flash hittest tween

我是一名初学者/中级AS3“程序员”试图为大学评估完成类似基于闪光的基于闪光的游戏,我正在做自己严重的精神伤害,试图让基本的物体(球)碰撞工作在我的舞台上得分目标。我正在使用一个电源条类型变量来确定球滚动的力,它被转换为一个补间,以创建一个平滑的运动,沿着我的“车道”进入得分区域(这是俯视角度)。目标是较大的影片剪辑中的影片剪辑的实例,该影片剪辑由游戏桌的所有组件组成。即使我在发布球时已经实例化了我的游戏桌和得分组件,但我得到了典型的非空错误:

  

ballSpeed是552

     

targetArray值为[object upperScoringAreaCTarget_mc]

     

TypeError:错误#2007:参数hitTestObject必须为非null。

     
    

在flash.display :: DisplayObject / _hitTest()

         

在flash.display :: DisplayObject / hitTestObject()

         

在SkeeBlast_7_fla :: MainTimeline / ballTargetScore()

         

在SkeeBlast_7_fla :: MainTimeline / rollBall()

         

在SkeeBlast_7_fla :: MainTimeline / releaseBall()

  

这是我的球发布功能:

function releaseBall(event:MouseEvent):void
{
    rollBall();
    gameElements.removeEventListener(MouseEvent.MOUSE_MOVE, moveBall);
}

function rollBall():void
{
    ballSpeed = rollPower * 12;
    trace("ballSpeed is " + ballSpeed);
    ballFriction();
    ballGravity();
    //ball.y -= ballSpeed;
    //var myBallTween:Tween = new Tween(ball,"y",Strong.easeOut,ball.y,ball.y -     ballSpeed,3,true);
    myBallTween = new Tween(ball,"y",Strong.easeOut,ball.y,ball.y - ballSpeed,3,true);
    myBallTween.start();
    ballTargetScore();

}

和我的碰撞检测和评分功能:

 //match targets to scoring values which should be tied to determineScore()
function ballTargetScore():void
{
var targetValue:String;
var targetArray:Array = new Array(gameTable.upperScoringArea.upperScoringAreaCTarget,
  gameTable.upperScoringArea.upperScoringAreaLtTarget,
  gameTable.upperScoringArea.upperScoringAreaRtTarget,
  gameTable.middleScoringArea.middleScoringAreaTargetTop,
  gameTable.middleScoringArea.middleScoringAreaTargetMiddle,
  gameTable.middleScoringArea.middleScoringAreaTargetLower,
  gameTable.lowerScoringArea.lowerScoringAreaTarget);

if (ball.hitTestObject(gameTable.tableDisplay))
{
    myBallTween.stop();
}
else
{
    for (var i:uint; i < targetArray.length; i++)
    {
        if (targetArray[i] != null)
        {
            trace("targetArray value is " + targetArray[i]);

            if (ball.hitTestObject(gameTable.upperScoringArea.upperScoringAreaCTarget))
            {
                targetValue = gameTable.upperScoringArea.upperScoringAreaC_text.text;
            }
            if (ball.hitTestObject(gameTable.upperScoringArea.upperScoringAreaLtTarget))
            {
                targetValue = gameTable.upperScoringArea.upperScoringAreaLt_text.text;
            }
            if (ball.hitTestObject(gameTable.upperScoringArea.upperScoringAreaRtTarget))
            {
                targetValue = gameTable.upperScoringArea.upperScoringAreaRt_text.text;
            }
            if (ball.hitTestObject(gameTable.upperScoringArea.middleScoringAreaTargetTop))
            {
                targetValue = gameTable.middleScoringArea.middleScoringAreaU_text.text;
            }
            if (ball.hitTestObject(gameTable.upperScoringArea.middleScoringAreaTargetMiddle))
            {
                targetValue = gameTable.middleScoringArea.middleScoringAreaM_text.text;
            }
            if (ball.hitTestObject(gameTable.upperScoringArea.middleScoringAreaTargetLower))
            {
                targetValue = gameTable.middleScoringArea.middleScoringAreaL_text.text;
            }
            if (ball.hitTestObject(gameTable.upperScoringArea.lowerScoringAreaTarget))
            {
                targetValue = gameTable.lowerScoringArea.lowerSA_text.text;
            }
            else
            {
                trace("no hit");
            }
        }
    }
}

//gameElements.removeEventListener(Event.ENTER_FRAME, ballTargetScore);
determineScore(targetValue);
//return targetValue;
}

当我试图找到正确的组合时,这一切仍然有点混乱。

我需要首先得到一个基本的球&lt; - &gt;目标或边界碰撞工作,但最终,我想尝试弄清楚如何有条件地控制碰撞,因为许多目标像竖琴一样垂直对齐表。我是否能够在补间/滚动时测量球的速度?我是否能够正确地施加重力以使球落下,如果它抓住了得分目标下面的一个弧线,它将沿着弧线滚动直到它“落入洞中”?我想我的对象的边界框会出现问题。

感谢您的帮助,

艾伦


以下是对Vesper的回复,其中包含清理功能(谢谢)和新错误。

function ballTargetScore():void
{
    var targetValue:String;
    var targetArray:Array = new Array(gameTable.upperScoringArea.upperScoringAreaCTarget,
      gameTable.upperScoringArea.upperScoringAreaLtTarget,
      gameTable.upperScoringArea.upperScoringAreaRtTarget,
      gameTable.middleScoringArea.middleScoringAreaTargetTop,
      gameTable.middleScoringArea.middleScoringAreaTargetMiddle,
      gameTable.middleScoringArea.middleScoringAreaTargetLower,
      gameTable.lowerScoringArea.lowerScoringAreaTarget);
    var targetTextArray:Array =  new Array(gameTable.upperScoringArea.upperScoringAreaC_text.text,
        gameTable.upperScoringArea.upperScoringAreaLt_text.text,
        gameTable.upperScoringArea.upperScoringAreaRt_text.text,
        gameTable.middleScoringArea.middleScoringAreaU_text.text,
        gameTable.middleScoringArea.middleScoringAreaM_text.text,
        gameTable.middleScoringArea.middleScoringAreaL_text.text,
        gameTable.lowerScoringArea.lowerSA_text.text);

    for (var i:uint; i < targetArray.length; i++)
    {
        if (targetArray[i] != null)
        {
            trace("targetArray value is " + targetArray[i]);
            if (ball.hitTestObject(targetArray[i]))
            {
                targetValue = targetTextArray[i];
                trace('targetValue becomes',targetValue);
            }
        }
    }

    determineScore(targetValue);
}

和错误:

  

ballSpeed是432

     

targetArray值为[object upperScoringAreaCTarget_mc]

     

targetArray值是[object upperScoringAreaLtTarget_mc]

     

targetArray值是[object upperScoringAreaRtTarget_mc]

     

targetArray值是[object middleScoringAreaTargetTop_mc]

     

targetArray值是[object middleScoringAreaTargetMiddle_mc]

     

targetArray值是[object middleScoringAreaTargetLower_mc]

     

targetArray值是[object lowerScoringAreaTarget_mc]

     

ArgumentError:错误#2025:提供的DisplayObject必须是调用者的子级。

     
    

在flash.display :: DisplayObjectContainer / removeChild()

         

在SkeeBlast_7_fla :: MainTimeline / determineScore()

         

在SkeeBlast_7_fla :: MainTimeline / ballTargetScore()

         

在SkeeBlast_7_fla :: MainTimeline / rollBall()

         

在SkeeBlast_7_fla :: MainTimeline / releaseBall()

  

感谢您的帮助。


我确信这些规则是必要的,这让我把这变成了一个很长的问题。 :)

无论如何,我有点弄清楚DisplayObject的错误,但程序仍然无法正常工作。

我通过在确定分数函数中将我的gameElements MC添加到我的removeChild调用来修复错误,如下所示;然而,即使错误消失,球仍然没有被移除,并且targetValue和得分永远不会更新(或从上面显示在跟踪中)。

function determineScore(scoreEvent:String):void
{
    if ( scoreEvent == "D-O" || scoreEvent == "2XB" || scoreEvent == "?")
    {
        if (scoreEvent == "D-O")
        {
            ballCount +=  1;
            gameTable.tableDisplay.BR_text.text = ballCount - 1;
            gameTable.tableDisplay.BR_text.embedFonts = false;
            gameElements.removeChild(ball);
            if (ballCount > 0 )
            {
                initBall();
            }
            else
            {
                drawEnd();
            }
        }
        else if (scoreEvent == "2XB")
        {
            ballCount +=  2;
            gameTable.tableDisplay.BR_text.text = ballCount - 1;
            gameTable.tableDisplay.BR_text.embedFonts = false;
            gameElements.removeChild(ball);
            if (ballCount > 0 )
            {
                initBall();
            }
            else
            {
                drawEnd();
            }
        }
        else
        {
            determineScore(allRandomScore(allScoresArray));
        }
    }
    else
    {
        scoreTotal +=  Number(scoreEvent);
        ballScore = Number(scoreEvent);
        gameTable.tableDisplay.Score_text.text = scoreTotal;
        gameTable.tableDisplay.Score_text.embedFonts = false;
        gameElements.removeChild(ball);
        if (ballCount > 0 )
        {
            initBall();
        }
        else
        {
            drawEnd();
        }
    }
}

感谢您查看此内容。我觉得我终于取得了一些进展。


好的,继续进行另一次更新。

gameElements是我添加所有其他MC的主要空MC,比如游戏桌和球,这样当我回到主菜单时,我可以立即删除所有内容。

var gameElements:MovieClip = new MovieClip();
var gameTable:MovieClip = new table_mc();
var ball:MovieClip = new blastBall();

并从我的drawGame函数:

...
stage.addChildAt(gameElements, 1);
gameElements.addChild(gameTable);
initBall();
...

和initBall:

function initBall():void
{
    //resize ball
    ball.height = 18;
    ball.width = 18;
    //place ball on table in correct location
    ball.x = gameTable.x;
    ball.y = gameTable.height - 20;
    gameElements.addChild(ball);
    //reduce number of remaining balls;
    ballCount -=  1;
    //hide the mouse and connect its movement to ball
    Mouse.hide();
    gameElements.addEventListener(MouseEvent.MOUSE_MOVE, moveBall);
}

希望此条目没有限制。 :)

以下是我在确定点数中添加的一小部分内容,以便从ballTargetScore中获取“结果”(或者真的没有):

if (scoreEvent == null)
    {
        trace("scoreEvent is null");
        gameTable.tableDisplay.BR_text.text = ballCount - 1;
        gameTable.tableDisplay.BR_text.embedFonts = false;
        gameElements.removeChild(ball);
        if (ballCount > 0)
        {
            initBall();
        }
        else
        {
            drawEnd();
        }
    }

(尚未清理其他任何东西)仍然试图让第一次碰撞工作。当我开始捕获空值时,initBall和drawEnd开始工作(好吧,它仍然没有真正做我想要的,但至少有一个响应)。

1 个答案:

答案 0 :(得分:0)

嗯,你有一个目标数组,你收到的错误意味着它的一些元素是空的。但是,当您遍历数组时,由于某种原因,您需要检查整个目标集,而不是检查它们中的任何一个是否为空。我不明白为什么。如果检测到命中,您需要分配一个文本变量,我建议您创建另一个包含相应索引的数组,该数组将包含您要分配的所有文本。

var targetTextArray:Array=(gameTable.upperScoringArea.upperScoringAreaC_text.text,
    gameTable.upperScoringArea.upperScoringAreaLt_text.text,
    gameTable.upperScoringArea.upperScoringAreaRt_text.text,
    gameTable.middleScoringArea.middleScoringAreaU_text.text,
    gameTable.middleScoringArea.middleScoringAreaM_text.text,
    gameTable.middleScoringArea.middleScoringAreaL_text.text,
    gameTable.lowerScoringArea.lowerSA_text.text);

然后,当您遍历targetArray时,您不再需要检查该目标是什么,以便检索正确的文本。你这样做:

for (var i:uint; i < targetArray.length; i++)
{
    if (targetArray[i] != null)
    {
        trace("targetArray value is " + targetArray[i]);
        if (ball.hitTestObject(targetArray[i])) {
            targetValue=targetTextArray[i];
            trace('targetValue becomes',targetValue);
        }
    }
}

更新:好的,让我们清理你的确定分数()函数。看起来你正确地添加和移除你的球,但你可能会做两次这样的事情。移除球两次而不将其添加回来将为您带来此错误。目前,如果gameElements.removeChild(ball);在该函数中被调用两次,我无法得到。

function determineScore(scoreEvent:String):void
{
    var reBall:Boolean=false; // should we make another ball roll, given the score
    var reDisplay:Boolean=false; // should we set new text
    if ((scoreEvent==null)||(scoreEvent=="")) return; // we haven't scored
    if ( scoreEvent == "D-O" || scoreEvent == "2XB" || scoreEvent == "?")
    {
        if (scoreEvent == "D-O")
        {
            ballCount +=  1;
            reBall=true;
            reDisplay=true;
        } 
        else if (scoreEvent == "2XB")
        {
            ballCount +=  2;
            reBall=true;
            reDisplay=true;
        }
        else
        {
            determineScore(allRandomScore(allScoresArray));
            // hey, what are we doing here? We seemingly receive a "?" as an input,
            // and we roll a random value out of a set given elsewhere. Okay
            return; // as good measure, because we don't have to do anything more
        }
    }
    else
    { // if we're here, we assume we have a numeric score passed inside, right?
        scoreTotal +=  Number(scoreEvent);
        ballScore = Number(scoreEvent);
        reBall=true;
        reDisplay=true;
    }
    // Now look, we always have to launch a new ball or display end, and
    // we always have to redraw score textfield. But look, you are always calling 
    // determineScore with some value, while you should do it only if you hit something!
    // So I added starting clause of "if null or empty string".
    if (reDisplay) {
        // we have to update text
        gameTable.tableDisplay.BR_text.text = ballCount - 1;
        gameTable.tableDisplay.BR_text.embedFonts = false;
    }
    if (reBall) {
        // we have to remove ball and launch another, if we have any left
        gameElements.removeChild(ball);
        if (ballCount > 0 )
        {
            initBall();
        }
        else
        {
            drawEnd();
        }
    }
}