As3 球正确弹开物体

As3 Ball to bounce off an object correctly

我在 as3 场景中有一个物体和一个球。我的问题是如何让球沿 y 轴从物体上弹开。我已经让它在 x 轴上弹跳了,没问题。问题在于,简单地在代码中添加 y 轴会使球从物体上错误地反弹。这是主时间线上和砖类内部的代码

var ballXSpeed:Number = 8;//X Speed of the Ball
 var ballYSpeed:Number = 8;//Y Speed of the Ball
 mcBall.addEventListener(Event.ENTER_FRAME, moveBall);
 function moveBall(event:Event):void {
mcBall.x +=  ballXSpeed;//Move the ball horizontally
mcBall.y +=  ballYSpeed;//Move the ball vertically

不确定此代码是否相关:

if (mcBall.x >= stage.stageWidth - mcBall.width){
//if the ball hits the right side
of the screen, then bounce off//
ballXSpeed *=  -1;
}

在砖里面:

  if (this.hitTestObject(_main.mcBall))
        {
    _main.ballYSpeed *=  -1;
    /_main.ballXSpeed *=  -1; does not work/

谢谢,新年快乐!

它不起作用的原因是因为你不知道你的球在哪里击中了你的砖块(底部、左侧、右侧等)

这一行:

this.hitTestObject(_main.mcBall)

只是告诉您发生了碰撞,但除此之外您没有其他信息。一种非常基本的方法是在碰撞后检查球的位置。类似于:

if( this.hitTestObject(_main.mcBall) )
{
    // hold our ball position
    var bx:Number = _main.mcBall.x;
    var by:Number = _main.mcBall.y;
    var br:Number = _main.mcBall.width * 0.5;

    // get our bounds (assuming that the brick has it's registration point
    // in the center) - extend by the radius of the ball to cover the points
    var left:Number     = this.x - this.width * 0.5 - br; 
    var right:Number    = this.x + this.width * 0.5 + br;
    var top:Number      = this.y - this.height * 0.5 - br;
    var bottom:Number   = this.y + this.height * 0.5 + br;

    // check the position of the ball in relation to our brick
    if( ( bx >= left && bx <= right && by >= bottom ) ||    // bottom
        ( bx >= left && bx <= right && by <= top ) )        // top
    {
        _main.mcBall.ballYSpeed *= -1;
    }
    else // hit the left or the right
    {
        _main.mcBall.ballXSpeed *= -1;
    }
}

这是一个非常的基本方法,可能会在砖块的拐角处破裂,或者如果球走得太快。

您可以通过查找一些碰撞检测公式来获得更强大的碰撞检测:

  • 圆形 - 矩形:Circle-Rectangle collision detection (intersection)
  • 线 - 矩形(你的球在一帧到下一帧的中心创建一条线):Line intersection with AABB Rectangle?

我还建议您查找向量 (http://www.intmath.com/vectors/vectors-intro.php) 和法线(垂直向量),因为它们会让您更轻松。例如。你的球从一帧到另一帧的位置是一个矢量 - 你的一个块的一侧是另一个。

一旦检测到碰撞,您就可以使用这种简单的 reflect 方法来反射您的球,无论它撞击的一侧的梯度如何:

public function reflect( vector:Point, normal:Point ):void
{
    // using the formula [R = V - (2 * V.N) * N] or [V -= 2 * N * (N.V
    var dot:Number  = ( vector.x * normal.x ) + ( vector.y * normal.y );
    var vn2:Number  = 2.0 * MathUtil.dot( vector, normal );
    vector.x        = vector.x - ( normal.x * vn2 );
    vector.y        = vector.y - ( normal.y * vn2 );
}

在那个例子中,vector 是球的速度,normal 是被击中的砖块侧面的垂直矢量(例如,砖块底部的法线)砖会指向下方,因为砖的顶部会指向上方,因为左侧会指向左侧,等等)

编辑 03/01

嗯,我不确定你为什么没有遇到碰撞 - 我下载了你的文件,创建了一个简单的项目(我没有你正在使用的 Flash 版本),并且有一个简单的球与一块简单的砖碰撞。碰撞并不完美,因为这种碰撞检测非常基础,但它确实有效。当你说你 "cannot get any collision at all" 的时候,你试过在碰撞方块里放一个 trace() 看看它是否被调用了吗?

您可以尝试以下几种方法:

1) 在进行碰撞响应之前将球推到方块外 - 使用这种形式的碰撞检测,球在检测到之前在方块内。有时,这意味着下一帧也在内部,因此 ballXSpeed/ballYSpeed 会再次反映出来。您可以移动球,使其在反射前刚好接触到方块:

if( bx >= left && bx <= right && by >= bottom ) // bottom
{
    _main.mcBall.y = bottom; // move the ball so that it's touching
    _main.mcBall.ballYSpeed *= -1; // reflect
}
...

2) 如果你有多个方块,那么你的问题可能是它们都对球执行相同的碰撞检查 - 如果球在一个方块内,它很可能也在另一个方块内 -这尤其正确,因为您使用的是 hitTestObject(),它比较元素的 边界框 (您没有与球碰撞,而是与假想的碰撞球周围的边界框,即另一个正方形)。在这种情况下,一个方块将反射球,然后下一个方块将 重新反射 球。你需要将你的碰撞检测移动到一个集中的位置(例如你的 Main) - 保留所有块的列表,将你的碰撞更改为一个循环,当你检测到碰撞时,爆发。类似于:

var bricks:Array = new Array(); // add all your bricks to this array (NOTE: remember to remove them when they're destroyed)

private function _onEnterFrame( e:Event ) // in Main
{
    var len:int = bricks.length;
    for( var i:int = 0; i < len; i++ )
    {
        if( this._checkBallCollisionWithBrick( this.mcBall, bricks[i] ) ) // same logic as before, just in a function
            break; // stop the loop
    }
}

这意味着您一次只会与一块砖碰撞。

3) 开始使用向量和数学计算你的碰撞

这是最好的解决方案,但也是最难的,因为您需要更改游戏的设置方式,而且它在编码方面更高级一些。

基本上,您需要将游戏的逻辑视觉效果分开。以你的球为例。你会在内存中有一个球,它包含位置、速度、半径等,然后你会有你的球图形,这些图形会在渲染之前更新。在伪代码中它会 运行 像这样:

  1. 创建球对象和积木对象。将所有积木添加到数组中
  2. 创建所有图形(球和砖块),并根据各自对象中的信息定位它们
  3. Main(或您的物理代码)中的每一帧,根据其速度
  4. 更新ballObj的位置
  5. 运行 通过 brickObjs 数组并检查我们是否有碰撞
  6. 如果我们有碰撞,移动 ballObj 使其刚好接触碰撞的砖块,并反映它的速度(如果你想正确地做到这一点,你可以确定 ballObj 何时碰撞使用 brickObj(例如帧时间的百分比),因此您可以在帧的剩余部分沿着它的新速度重新移动 ballObj,并且可能与另一个对象发生碰撞)
  7. 在帧的末尾,将您的 ballGraphics 更新到 ballObj
  8. 中的位置

正如我所说,它有点复杂,但结果更好。了解这类东西总是好的,但如果你真的不在乎,你也可以使用像 Box2D 这样的物理引擎:http://www.box2dflash.org/(并不像你想要的那么简单)