它不起作用的原因是因为你不知道你的球击中了你的砖块(底部、左侧、右侧等)
这一行:
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) 开始使用向量和数学计算碰撞
这是最好的解决方案,但也是最难的,因为您需要更改游戏的设置方式,并且在编码方面更高级。
基本上,您需要将游戏的逻辑与视觉效果分开。以你的球为例。你会在内存中有一个球,它保存位置、速度、半径等,然后你会有你的球图形,在渲染之前更新。在伪代码中它会像这样运行:
- 创建您的球对象和砖对象。将所有砖块添加到数组中
- 创建所有图形(球和砖),并根据各自对象中的信息定位它们
- Main(或您的物理代码)中的每一帧都会根据其速度更新
ballObj 的位置
- 遍历
brickObjs 数组并检查我们是否有冲突
- 如果发生碰撞,移动
ballObj,使其刚好接触到碰撞的砖块,并反映它的速度(如果你想正确地做到这一点,你将确定ballObj何时与brickObj碰撞(例如帧时间的百分比),因此您可以在帧的其余部分沿其新速度重新移动ballObj,并可能与另一个对象发生碰撞)
- 在帧的末尾,将您的
ballGraphics 更新为ballObj 中的位置
就像我说的,它有点复杂,但结果更好。知道这类东西总是好的,但如果你不是很在意,你也可以使用像 Box2D 这样的物理引擎:http://www.box2dflash.org/(不像你想的那么简单)