Java 如何修复此碰撞检测块?
我一直在使用LibGDX框架用Java开发这个brickbreaker游戏。这是我的第一个java游戏。我有一点其他语言的经验,但有点麻烦。我已经设置了碰撞检测,大部分情况下都能正常工作。球有时会朝错误的方向反弹,有时会撞到不该撞到的挡块。我一直在寻找,但很难把它翻译成我的游戏 我的代码真的很糟糕,因为球只以45度角移动。不太现实,这将是我修复后的下一步Java 如何修复此碰撞检测块?,java,libgdx,collision-detection,Java,Libgdx,Collision Detection,我一直在使用LibGDX框架用Java开发这个brickbreaker游戏。这是我的第一个java游戏。我有一点其他语言的经验,但有点麻烦。我已经设置了碰撞检测,大部分情况下都能正常工作。球有时会朝错误的方向反弹,有时会撞到不该撞到的挡块。我一直在寻找,但很难把它翻译成我的游戏 我的代码真的很糟糕,因为球只以45度角移动。不太现实,这将是我修复后的下一步 public void checkBrickCollision() { for (int i=0;i<level.brickCo
public void checkBrickCollision()
{
for (int i=0;i<level.brickCount;i++) {
if (level.bricks[i].GetVisible() == true) {
if (level.bricks[i].getRect().overlaps(ball.getRect()))
{
int xd = (int) Math.abs( (ball.ballRect.x + ball.ballRect.width - level.bricks[i].brickRect.x - level.bricks[i].getRect().width) /2 );
int yd = (int) Math.abs( (ball.ballRect.y + ball.ballRect.height - level.bricks[i].brickRect.y - level.bricks[i].getRect().height) /2 );
if (xd > yd)
{
// Collision on top or bottom, reverse y velocity
ball.ballSpeedY = -ball.ballSpeedY;
Score score = new Score(level.bricks[i].getScore(),(int)level.bricks[i].brickRect.x,(int)level.bricks[i].brickRect.y);
scoreList.add(score);
level.bricks[i].Destroy();
System.out.println("Top/Bottom");
return;
}
if (yd > xd)
{
// Collision on left or right, reverse x velocity
ball.ballSpeedX = -ball.ballSpeedX;
Score score = new Score(level.bricks[i].getScore(),(int)level.bricks[i].brickRect.x,(int)level.bricks[i].brickRect.y);
scoreList.add(score);
level.bricks[i].Destroy();
System.out.println("Sides");
return;
}
if (xd == yd)
{
// Collision on corners, reverse both
ball.ballSpeedX = -ball.ballSpeedX;
ball.ballSpeedY = -ball.ballSpeedY;
Score score = new Score(level.bricks[i].getScore(),(int)level.bricks[i].brickRect.x,(int)level.bricks[i].brickRect.y);
scoreList.add(score);
level.bricks[i].Destroy();
System.out.println("Corners");
return;
}
}
}
}
}
public void checkBrickCollision()
{
对于(int i=0;i yd)
{
//顶部或底部碰撞,反向y速度
ball.ballspedible=-ball.ballspedible;
分数分数=新分数(level.bricks[i].getScore(),(int)level.bricks[i].brickRect.x,(int)level.bricks[i].brickRect.y);
分数表。添加(分数);
level.bricks[i].Destroy();
系统输出打印项次(“顶部/底部”);
返回;
}
如果(yd>xd)
{
//左侧或右侧碰撞,反向x速度
ball.ballSpeedX=-ball.ballSpeedX;
分数分数=新分数(level.bricks[i].getScore(),(int)level.bricks[i].brickRect.x,(int)level.bricks[i].brickRect.y);
分数表。添加(分数);
level.bricks[i].Destroy();
系统输出打印项次(“侧面”);
返回;
}
如果(xd==yd)
{
//在拐角处发生碰撞,将两个都反转
ball.ballSpeedX=-ball.ballSpeedX;
ball.ballspedible=-ball.ballspedible;
分数分数=新分数(level.bricks[i].getScore(),(int)level.bricks[i].brickRect.x,(int)level.bricks[i].brickRect.y);
分数表。添加(分数);
level.bricks[i].Destroy();
系统输出打印(“角落”);
返回;
}
}
}
}
}
我建议您将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);
}
List brickList=new ArrayList();
用于(砖:标高.砖){
砖列表。添加(新砖(砖));
}
//-------或-------
//如果砖块对象是精灵
用于(砖:标高.砖){
砌砖工。添加(砖);
}
我相信错误的砖块被检测为“命中”的问题与试图补偿球的纹理和边界是一个矩形有关。我建议使用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();
}
}
公共类碰撞器{
私有字符串bounceType=“”;
私有布尔垂直=假;
私有布尔水平=假;
//分割矩形的顶点
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();
私有向量2 bottomEnd=新向量2();
私有向量2中心=新向量2();
专用圆ballBounds=新圆();
//指针在构造期间传递一次
私人舞会;
私人名单制砖匠;
私人名单记分表;
/**
*构造函数要求给定ball和brickList指针。
*
*在分配参数后运行updateBallBounds()方法
*
*@param ball指向用于碰撞计算的球
*@param brickList指向要检查的砖对象列表
*@param scoreList指向用于跟踪分数的分数对象列表
*/
公共对撞机(球、名单、记分表){
这个球=球;
this.brickList=砌砖工;
updateBallBounds(this.ball,this.ballBounds);
}
/**
*设置边界圆的位置和半径
*对于给定的具有矩形形状的球
*为边界检查做准备。
*
*@param ball将球对象设置为
*@param bounds将存储边界信息的圆对象
*/
私有void updateBallBounds(球、圆边界){
bounds.set((ball.ballRect.x+(ball.ballRect.width/2)),//中心x位置
(ball.ballRect.y+(ball.ballRect.height/2)),//中心y位置
(ball.ballRect.width/2));//球的半径
}
/**
*为每个线段生成起始向量和结束向量
*提供的矩形的中心向量。还为
*球。
*
*用于准备查找矩形的哪些线段
*球相交了
*
*@param brickRect矩形以从中处理线段
*/
专用设置向量(矩形块){
leftStart.set(brickRect.x,brickRect.y);
leftEnd.set(brickRect.x,brickRect.height);
topStart.set(砖砌x,砖砌高度);
顶端设置(砖缝宽度、砖缝高度);
rightStart.set(多边形(brickRect.width,brickRect.y);
rightEnd.set(砖缝宽度、砖缝高度);
底部开始设置(brickRect.x,bri