【问题标题】:As3 Ball to bounce off an object correctlyAs3 球正确地从物体上反弹
【发布时间】:2015-01-01 21:12:32
【问题描述】:

我在 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/

谢谢你,新年快乐!

【问题讨论】:

标签: actionscript-3 flash object bounce


【解决方案1】:

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

这一行:

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;
    }
}

这是一种非常基本的方法,并且可能会在砖的角落处破裂,或者如果球跑得太快。

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

我还建议您查找向量 (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 版本),并且有一个简单的球碰撞用一块简单的砖。碰撞并不完美,因为这种碰撞检测是非常基本的,但它确实有效。当您说“根本无法发生任何碰撞”时,您是否尝试过在碰撞块中放置 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(或您的物理代码)中的每一帧都会根据其速度更新ballObj 的位置
  4. 遍历brickObjs 数组并检查我们是否有冲突
  5. 如果发生碰撞,移动ballObj,使其刚好接触到碰撞的砖块,并反映它的速度(如果你想正确地做到这一点,你将确定ballObj何时与brickObj碰撞(例如帧时间的百分比),因此您可以在帧的其余部分沿其新速度重新移动ballObj,并可能与另一个对象发生碰撞)
  6. 在帧的末尾,将您的ballGraphics 更新为ballObj 中的位置

就像我说的,它有点复杂,但结果更好。知道这类东西总是好的,但如果你不是很在意,你也可以使用像 Box2D 这样的物理引擎:http://www.box2dflash.org/(不像你想的那么简单)

【讨论】:

  • 谢谢!我在过去的 2 个小时里,我试图让它与你在我的砖块中作为文件提供的代码一起工作,并且根本不会发生任何冲突我也查找了所有其他方法并阅读了有关向量的信息....你能告诉我在哪里可以使用反射方法吗?我可以在那块砖里面使用它作为文件吗?你能看一下文件吗? app.box.com/s/0acyz9wkgniaug8zd96x右边的砖是第一段的代码。
  • 我已经更新了帖子 - 物理学并不是可以在帖子中总结的东西,所以这取决于你是想保持它像你拥有的那样简单,还是多做一些更深入
  • 非常感谢。不能打开cs5文件真的很不幸。你需要 10 分钟才能解决这个问题,我会付钱给你的。我的游戏已经完成,它可以与我的代码一起使用,除了当球从 x 轴撞击砖块时,这并不经常发生,但它确实发生了.....这是正常速度,所以任何碰撞都会已经工作了。我已经设置了视觉效果和碰撞......这在理论上回答了我的问题。感谢您的努力!
  • 对不起,第一段代码确实有效。我不得不将 _main.mcBall.ballYSpeed 更改为简单的 _main.ballYSpeed。现在的问题是它永远无法在所有四个方面都受到打击。如果我把它调到3,第四个就不行了,但是比以前好多了。谢谢!
  • “如果我将其调整为 3,第四个将不起作用” - 我不确定我是否理解您的意思 - 如果您将什么调整为 3?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-07
  • 1970-01-01
  • 2021-02-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多