我建议您将level.bricks[]数组放在ArrayList列表中,这样您就可以从列表中廉价地删除()和/或销毁()它们,避免在 level.bricks 数组中的每次迭代检查空值(除非您的设置不介意数组中的空值)。此外,它将使您不必在每个渲染周期中检查数组的大小、每次迭代、所有砖块的大小......
List<Brick> brickList = new ArrayList<Brick>();
for (brick: level.bricks) {
brickList.add( new Brick(brick) );
}
//-------or-------
//if the brick object is a Sprite
for (brick: level.bricks) {
brickList.add(brick);
}
我相信错误的砖块被检测为“击中”的问题与试图补偿球纹理和边界为Rectangle有关。我建议使用com.badlogic.gdx.math.Circle类来定义球的边界。以下是com.badlogic.gdx.math.Intersector的脏自定义碰撞包装器,它应该适用于您在上面尝试的内容。它假设球的视觉像素延伸到纹理的边缘并且球的纹理是正方形的:
public class Collider {
private String bounceType = "";
private boolean vertical = false;
private boolean horizontal = false;
// Segment Vertices of the Rectangle
private Vector2 leftStart = new Vector2();
private Vector2 leftEnd = new Vector2();
private Vector2 topStart = new Vector2();
private Vector2 topEnd = new Vector2();
private Vector2 rightStart = new Vector2();
private Vector2 rightEnd = new Vector2();
private Vector2 bottomStart = new Vector2();
private Vector2 bottomEnd = new Vector2();
private Vector2 center = new Vector2();
private Circle ballBounds = new Circle();
// Pointers passed once during construction
private Ball ball;
private List<Brick> brickList;
private List<Score> scoreList;
/**
* Constructor requires that ball and brickList pointers are given.
* <p>
* Runs the updateBallBounds() method after assigning the parameters
*
*@param ball points to the ball to be used for the collision calculations
*@param brickList points to a list of brick objects to check against
*@param scoreList points to a list of score objects to track the score
*/
public Collider(Ball ball, List<Brick> brickList, List<Score> scoreList) {
this.ball = ball;
this.brickList = brickList;
updateBallBounds(this.ball, this.ballBounds);
}
/**
* Sets the position and radius of the bounding circle
* for the given ball with a rectangular shape in order
* to prepare it for bounds checking.
*
* @param ball The ball object to
* @param bounds The circle object that will store the bounds information
*/
private void updateBallBounds(Ball ball, Circle bounds) {
bounds.set( (ball.ballRect.x + (ball.ballRect.width/2)), //Center x pos
(ball.ballRect.y + (ball.ballRect.height/2)), //Center y pos
(ball.ballRect.width / 2) ); //Radius of ball
}
/**
* Builds the start and end Vectors for each of the segments
* of the provided rectangle. Also builds the center Vector for
* the ball.
* <p>
* Used to prepare for finding which segments of the rectangle the
* ball is intersecting
*
* @param brickRect The rectangle to process the line segments from
*/
private setVectors(Rectangle brickRect) {
leftStart.set(brickRect.x, brickRect.y);
leftEnd.set(brickRect.x, brickRect.height);
topStart.set(brickRect.x, brickRect.height);
topEnd.set(brickRect.width, brickRect.height);
rightStart.set(Poyline( brickRect.width, brickRect.y);
rightEnd .set(brickRect.width, brickRect.height);
bottomStart.set(brickRect.x, brickRect.y);
bottomEnd.set(brickRect.width, brickRect.y);
center.set(ballBounds.x, ballBounds.y);
}
/**
* Finds bricks in the list that the ball is currently
* colliding with.
* <p>
* For every rectangle that the ball is currently colliding with,
* the method calls the setVectors() method to prepare the start-end
* vertices for the processCollision() method.
* <p>
* WARNING: this may not handle multiple collision very well. It
* should work, but you most likely will not give very good results
* on multiple brick hit detected. You should think about including
* a break statement after the first collision is detected and let
* the Collider find an additional collision during the next render()
* call.
*/
public void detectCollisions() {
updateBallBounds(ball, ballBounds);
for (brick: brickList) {
if( Intersector.overlaps(ballBounds, brick.brickRect) ) {
setVectors(brick.brickRect);
processCollision(brick, brick.brickRect);
//break;
}
}
}
/**
* Detects how to handle the collision based on the segments being hit.
*
*@param brick the brick found by detectCollision() method. will be
* destroyed after collision is processed
*/
public void processCollision(Brick brick) {
if ( Intersector.intersectSegmentCircle( topStart, topEnd,
center * center,
ballBounds.radius ) ||
Intersector.intersectSegmentCircle( bottomStart, bottomEnd,
center * center,
ballBounds.radius )) {
vertical = true;
}
if ( Intersector.intersectSegmentCircle( leftStart, leftEnd,
center * center,
ballBounds.radius ) ||
Intersector.intersectSegmentCircle( rightStart, rightEnd,
center * center,
ballBounds.radius ) ) {
horizontal = true;
}
// The following could return the value to a calling entity.
// Then the game logic of what to do here would be decoupled.
if (vertical && horizontal) {
bounceType = "CORNER"
} else if (vertical && !horizontal) {
bounceType = "VERTICAL"
} else if () {
bounceType = "HORIZONTAL"
} else {
// The game blows up...
}
switch (bounceType) {
case "VERTICAL":
ball.ballSpeedY = -ball.ballSpeedY;
break;
case "HORIZONTAL":
ball.ballSpeedX = -ball.ballSpeedX;
break;
case "CORNER":
ball.ballSpeedY = -ball.ballSpeedY;
ball.ballSpeedX = -ball.ballSpeedX;
break;
default: // Try not to blow up the game...
break;
}
Score score = new Score(brick.getScore(), brick.x, brick.y)
scoreList.add(score);
brickList.remove(brick);
brick.destroy();
}
}
我确定这里有错误,它没有经过测试。除了前面的假设之外,它不会阻止砖块在您的数组中呈现(除非 destroy() 处理了这一点,并且希望不会在呈现时寻找空值......)。
基本结构可以做得更好...
- 与一些除外,尝试,捕捉东西。
- 你可以添加更多类型的构造函数和方法来覆盖更多的形状。
- 空间分区可以添加一种方法来映射构造的静态边界。然后,您的动态对象可以记录它们当前占用的分区,并且只查询记录在这些分区列表中的其他对象的冲突结果。
- 我认为这个类的实现应该在其他地方解耦和处理。
- 这也可以让您创建一个碰撞类或事件,并返回/触发。
希望这有帮助。
我还建议您查看 Box2D。您的要求似乎很简单,可以轻松学习如何使用它。此页面可以向您展示如何配置它并与 LibGDX 一起使用。这将允许您快速实现物体的材料属性、球上的旋转、速度变化、角反弹......,以及自动魔法的各种好处,这将为您的大脑节省一些周期。物理引擎为您完成所有数学运算。您只需初始化并执行它,监听事件(如碰撞)。
祝你游戏好运。