前言
到目前为止,我们或许已经可以制作一个类似于 谷歌小恐龙 这样的小游戏了,但是,当实际操作起来的时候,我们会发现:如何检测小恐龙与障碍物之间的碰撞?不会吧?碰撞检测很复杂的,难道还要自己造轮子?不不不, libGDX 自身提供了碰撞检测的方法:使用com.badloc.gdx.math.Rectangle 类。
Rectangle 碰撞检测
Rectangle 类创建一个矩形,它提供了碰撞检测,它的常用构造方法如下:
- Rectangle() : 创建一个空的矩形,坐标宽高都为0
- Rectangle(Rectangle rect) : 以 rect 创建一个新的矩形
- Rectangle(float x,float y,float width,float height) : 创建一个(x,y)且大小 width*height 的矩形
Rectangle de 使用
Rectangle 类包含了对矩形的各种操作:
rect.setX(x);
rect.x=x;
rect.setY(y);
rect.y=y;
rect.setPosition(x,y);
rect.setWidth(width);
rect.width=width;
rect.setHeight(height);
rect.height=height;
rect.setSize(width,height);
rect.setBounds(x,y,width,height);
Rectangle 还有如上讲到的碰撞检测方法:
boolean isContains=rect.contains(x,y);
isContains=rect.contains(vec2);
isContains=rect.contains(rect2);
isEquals=rect.equals(rect2);
isOverlaps=rect.overlaps(rect2);
碰撞深度检测
游戏中,很多的物体并不是一撞到就死,更多的只是拦截而已,也就是 碰撞箱,但 libGDX 并不提供碰撞箱,因此,我们需要造轮子。
碰撞箱目的是让两个物体无法重叠,因此我们只要求出两个 Rectangle 碰撞的深度,再根据深度移出某一个 Rectangle 就可以实现 碰撞箱 ,只需要两个方法:
public float testCollisionHeight(Rectangle rect,Rectangle otherRect) {
if(!(rect.overlaps(otherRect)))return 0;
if(rect.y>otherRect.y)
return ( ( otherRect.height + otherRect.y ) - rect.y );
else
return - ( ( rect.height + rect.y ) - otherRect.y ) ;
}
public float testCollisionWidth(Rectangle rect,Rectangle otherRect) {
if(!(rect.overlaps(otherRect)))return 0;
if(rect.x>otherRect.x)
return ( ( otherRect.width + otherRect.x ) - rect.x );
else
return -( ( rect.width + rect.x ) - otherRect.x );
}
上面两个方法返回的是 rect 应该向 x和y 移动多少(加法),也就是说,rect 是被动的,例如游戏中可以推的箱子等等,而 otherRect 是主动的,例如推箱子的角色等等。
实例:互推
为测试它们是否真的有效,我们举一个实例:
下载这张图片,命名为 badlogic.png 放在 asset 文件夹 
package com.libGDX.test;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Rectangle;
public class Test extends ApplicationAdapter {
private SpriteBatch batch;
private Texture texture;
private Sprite left;
private Sprite right;
private boolean before;
@Override
public void create() {
batch=new SpriteBatch();
texture=new Texture(Gdx.files.internal("badlogic.png"));
left=new Sprite(texture);
right=new Sprite(texture);
left.setBounds(0,200,100,100);
right.setBounds(400,200,100,100);
before=true;
}
@Override
public void render() {
Gdx.gl.glClearColor(1,1,1,1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
act(Gdx.graphics.getDeltaTime());
batch.begin();
left.draw(batch);
right.draw(batch);
batch.end();
}
private void act(float delta) {
if(Gdx.input.justTouched())before=!before;
left.setX(left.getX()+100*delta);
right.setX(right.getX()-100*delta);
if(before)
right.setX(right.getX()+testCollisionWidth(right.getBoundingRectangle(), left.getBoundingRectangle()));
else
left.setX(left.getX()+testCollisionWidth(left.getBoundingRectangle(),right.getBoundingRectangle()));
}
public float testCollisionHeight(Rectangle rect,Rectangle otherRect) {
if(!(rect.overlaps(otherRect)))return 0;
if(rect.y>otherRect.y)
return ( ( otherRect.height + otherRect.y ) - rect.y );
else
return - ( ( rect.height + rect.y ) - otherRect.y ) ;
}
public float testCollisionWidth(Rectangle rect,Rectangle otherRect) {
if(!(rect.overlaps(otherRect)))return 0;
if(rect.x>otherRect.x)
return ( ( otherRect.width + otherRect.x ) - rect.x );
else
return -( ( rect.width + rect.x ) - otherRect.x );
}
@Override
public void dispose(){
batch.dispose();
texture.dispose();
}
运行结果:
  
实例 :小恐龙躲障碍
学会了如此6批的东西,怎能不大展身手一番?那么,我们做一个小恐龙躲障碍(类似谷歌小恐龙)的小游戏吧! 下载下面两张图片,命名为 dinasour.png 和 cacti.png ,放到 asset 文件夹
 
在项目下创建 data 文件夹,再添加 scoreMax.txt:

package com.libGDX.test;
import java.util.Random;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.utils.Array;
public class Test extends ApplicationAdapter {
private SpriteBatch batch;
private Texture cactiTexture;
private Texture dinasourTexture;
private Array<Sprite> cactis;
private Sprite dinasour;
private Random r;
private int time;
private int jump;
private int score;
private FileHandle scoreFile;
private BitmapFont font;
private int maxScore;
public final int WORLD_WIDTH=500;
public final int WORLD_HEIGHT=200;
@Override
public void create() {
batch=new SpriteBatch();
cactiTexture=new Texture(Gdx.files.internal("cacti.png"));
dinasourTexture=new Texture(Gdx.files.internal("dinasour.png"));
cactis=new Array<>();
dinasour=new Sprite(dinasourTexture);
r=new Random();
scoreFile=new FileHandle("data/scoreMax.txt");
String str=scoreFile.readString();
if(str.equals(""))maxScore=0;
else maxScore=Integer.valueOf(str);
font=new BitmapFont();
font.setColor(Color.BLACK);
font.getData().setScale(3);
reset();
}
@Override
public void render() {
Gdx.gl.glClearColor(1,1,1,1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
act(Gdx.graphics.getDeltaTime());
batch.begin();
for(Sprite s : cactis)
s.draw(batch);
dinasour.draw(batch);
font.draw(batch,"UI "+String.valueOf(maxScore)+" "+String.valueOf(score),150,170);
batch.end();
}
private void reset() {
dinasour.setBounds(50,0,60,60);
maxScore=Integer.valueOf(scoreFile.readString());
score=0;
jump=0;
time=0;
for(int i=cactis.size-1;i>=0;--i) {
cactis.removeIndex(i);
}
}
private void act(float delta) {
time+=delta*100;
if(dinasour.getY()==0&&Gdx.input.justTouched())jump=18;
dinasour.setY(dinasour.getY()+jump);
if(dinasour.getY()>0)jump-=delta*60;
else {
dinasour.setY(0);
jump=0;
}
if(time%10==0)score++;
if(time%40==0&&r.nextInt(2)==0) {
Sprite cacti=new Sprite(cactiTexture);
cacti.setBounds(WORLD_WIDTH, 0, 50,r.nextInt(20)+40);
cactis.add(cacti);
}
Sprite cacti;
for(int i=cactis.size-1;i>=0;--i) {
cacti=cactis.get(i);
cacti.setX(cacti.getX()-500*delta);
if(dinasour.getBoundingRectangle().overlaps(cacti.getBoundingRectangle())) {
if(score>maxScore)scoreFile.writeString(String.valueOf(score),false);
reset();
}
if(cacti.getX()<0-50)
cactis.removeIndex(i);
}
}
@Override
public void dispose() {
batch.dispose();
dinasourTexture.dispose();
cactiTexture.dispose();
}
}
运行结果: 
|