IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> libGDX-6:矩形与碰撞检测 Rectangle -> 正文阅读

[游戏开发]libGDX-6:矩形与碰撞检测 Rectangle

前言

到目前为止,我们或许已经可以制作一个类似于 谷歌小恐龙 这样的小游戏了,但是,当实际操作起来的时候,我们会发现:如何检测小恐龙与障碍物之间的碰撞?不会吧?碰撞检测很复杂的,难道还要自己造轮子?不不不, 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 还有如上讲到的碰撞检测方法:

//检测(x,y)处的点是否在矩形内
boolean isContains=rect.contains(x,y);
//vec2 是 com.badloc.gdx.math.Vector2 的变量,也表示一个坐标
isContains=rect.contains(vec2);
//检测rect2(Rectangle)是否完全在矩形内
isContains=rect.contains(rect2);
//检测rect与rect2是否完全相同(大小,坐标)
isEquals=rect.equals(rect2);
//检测rect与rect2是否存在重叠(碰撞检测就用这个)
isOverlaps=rect.overlaps(rect2);

碰撞深度检测

游戏中,很多的物体并不是一撞到就死,更多的只是拦截而已,也就是 碰撞箱,但 libGDX 并不提供碰撞箱,因此,我们需要造轮子。

碰撞箱目的是让两个物体无法重叠,因此我们只要求出两个 Rectangle 碰撞的深度,再根据深度移出某一个 Rectangle 就可以实现 碰撞箱 ,只需要两个方法:

//检测碰撞y深度
public float testCollisionHeight(Rectangle rect,Rectangle otherRect) {
	if(!(rect.overlaps(otherRect)))return 0;	//无触碰情况
	
	if(rect.y>otherRect.y)
		//this在上
		return ( ( otherRect.height + otherRect.y ) - rect.y );
	else
		//this在下
		return  - ( ( rect.height + rect.y ) - otherRect.y ) ;
}
	
//检测碰撞x深度
public float testCollisionWidth(Rectangle rect,Rectangle otherRect) {
	if(!(rect.overlaps(otherRect)))return 0;	//无触碰情况
	
	if(rect.x>otherRect.x)
		//this在右
		return  ( ( otherRect.width + otherRect.x ) - rect.x );
	else
		//this在左
		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;
	//优先级,是否left优先
	private boolean before;
	@Override
	public void create() {
		batch=new SpriteBatch();
		//加载纹理
		texture=new Texture(Gdx.files.internal("badlogic.png"));
		
		//根据纹理创建 Sprite
		left=new Sprite(texture);
		right=new Sprite(texture);
		
		//设置大小和位置
		left.setBounds(0,200,100,100);
		right.setBounds(400,200,100,100);
		
		//left 优先
		before=true;
	}
	
	@Override
	public void render() {
		//白色清屏
		Gdx.gl.glClearColor(1,1,1,1);
		Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
		//Gdx.graphics.getDeltaTime() 是增量时间
		act(Gdx.graphics.getDeltaTime());
		
		batch.begin();
		//绘制 Sprite
		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)
			/* left 优先,right 移动使用加法,
			 * 第三节有讲过 Sprite 的 getBoundRectangle()方法,
			 * 根据自身的坐标大小返回一个 Rectangle
			 */
			right.setX(right.getX()+testCollisionWidth(right.getBoundingRectangle(), left.getBoundingRectangle()));
		else 
			//right 优先
			left.setX(left.getX()+testCollisionWidth(left.getBoundingRectangle(),right.getBoundingRectangle()));
	}
	
	//检测碰撞y深度
	public float testCollisionHeight(Rectangle rect,Rectangle otherRect) {
		if(!(rect.overlaps(otherRect)))return 0;	//无触碰情况
		
		if(rect.y>otherRect.y)
			//this在上
			return ( ( otherRect.height + otherRect.y ) - rect.y );
		else
			//this在下
			return  - ( ( rect.height + rect.y ) - otherRect.y ) ;
	}
	
	//检测碰撞x深度
	public float testCollisionWidth(Rectangle rect,Rectangle otherRect) {
		if(!(rect.overlaps(otherRect)))return 0;	//无触碰情况
		
		if(rect.x>otherRect.x)
			//this在右
			return  ( ( otherRect.width + otherRect.x ) - rect.x );
		else
			//this在左
			return -( ( rect.width + rect.x ) - otherRect.x );
	}
	@Override
	public void dispose(){
		batch.dispose();
		texture.dispose();
	}

运行结果:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

实例 :小恐龙躲障碍

学会了如此6批的东西,怎能不大展身手一番?那么,我们做一个小恐龙躲障碍(类似谷歌小恐龙)的小游戏吧!
下载下面两张图片,命名为 dinasour.pngcacti.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;	//存储分数的 .txt 文件
	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();
		
		//获取历史最高分数,data/scoreMax.txt 分数文件
		scoreFile=new FileHandle("data/scoreMax.txt");
		String str=scoreFile.readString();
		if(str.equals(""))maxScore=0;	//如果scoreMax 没有内容,则为零
		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) {
		//累加时间(*100)
		time+=delta*100;
		//点击即跳跃
		if(dinasour.getY()==0&&Gdx.input.justTouched())jump=18;
		//小恐龙y坐标变化,jump正数跳跃,负数下降
		dinasour.setY(dinasour.getY()+jump);
		//如果小恐龙未落地,则持续减少 jump
		if(dinasour.getY()>0)jump-=delta*60;
		else {	//否则jump重置,小恐龙落地
			dinasour.setY(0);
			jump=0;
		}
		
		//每0.1s(10/100) 加一分
		if(time%10==0)score++;
		
		//每0.4s 有50% 的几率刷新仙人掌
		if(time%40==0&&r.nextInt(2)==0) {
			Sprite cacti=new Sprite(cactiTexture);
			//设置仙人掌属性,高在40~60之间
			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();
	}
}

运行结果:
在这里插入图片描述

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2021-08-30 12:32:08  更:2021-08-30 12:32:18 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/2 11:37:40-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码