文章目录
- 前言
- 一、环境准备
- 添加依赖
- 基本概念
- 二、实现步骤
- 1.创建世界
- 2.添加物体
- 3.设置碰撞监听器
- 4.更新世界
- 三、完整代码示例
- 四、优化补充
- 总结
前言
dyn4j 提供了高效的碰撞检测和物理模拟功能,适用于游戏开发、动画制作以及其他需要物理交互的场景。通过简单的 API,用户可以快速构建物理世界并实现复杂的碰撞检测逻辑。
一、环境准备
Java 开发环境:安装 JDK 8 或更高版本。
Maven 或 Gradle:用于管理依赖项。
IDE:如 IntelliJ IDEA 或 Eclipse。
添加依赖
<dependency><groupId>org.dyn4j</groupId><artifactId>dyn4j</artifactId><version>5.0.2</version> <!-- 请检查最新版本 -->
</dependency>
基本概念
在使用 dyn4j 时,有几个核心概念需要了解:
World(世界):表示物理模拟的环境,所有物体和碰撞事件都发生在世界中。
Body(物体):表示物理世界中的实体,可以是静态或动态的。
Fixture(形状):附加到物体上的几何形状,用于定义碰撞区域。
Collision Listener(碰撞监听器):用于监听和处理碰撞事件。
二、实现步骤
以下是使用 dyn4j 实现碰撞检测的基本步骤。
1.创建世界
首先,我们需要创建一个 World 对象,它是所有物理模拟的基础。
World<Body> world = new World<>();world.setGravity(World.ZERO_GRAVITY);
2.添加物体
接下来,我们向世界中添加物体。每个物体都需要一个形状(如矩形、圆形)和质量属性。
Body npcBody = createBody(0, 0, 1, 1);Body itemBody = createBody(4, 0, 1, 1);world.addBody(npcBody);world.addBody(itemBody);/*** 创建物体*/private static Body createBody(double x, double y, double w, double h) {Body body = new Body();body.addFixture(Geometry.createRectangle(w, h));body.getTransform().setTranslation(x, y);// 如果不设置质量,碰撞监听不生效body.setMass(MassType.NORMAL);return body;}
3.设置碰撞监听器
world.addCollisionListener(new CollisionListener<>() {@Overridepublic boolean collision(BroadphaseCollisionData broadphaseCollisionData) {// 碰撞会调用到这里log.info("broadphaseCollisionData:{}, {}",broadphaseCollisionData.getBody1().getTransform().getTranslation(),broadphaseCollisionData.getBody2().getTransform().getTranslation());return true;}@Overridepublic boolean collision(NarrowphaseCollisionData narrowphaseCollisionData) {log.info("narrowphaseCollisionData:{}", narrowphaseCollisionData);return false;}@Overridepublic boolean collision(ManifoldCollisionData manifoldCollisionData) {log.info("manifoldCollisionData:{}", manifoldCollisionData);return false;}});
4.更新世界
for (int i = 0; i < 100; i++) {// 模拟移动itemBody.translate(-0.1, 0);// 手动判断是否碰撞if (world.getBroadphaseDetector().detect(itemBody, npcBody)) {log.info("npc: {}, item: {}", npcBody.getTransform().getTranslation(), itemBody.getTransform().getTranslation());break;}// 更新世界world.update(1d / 60d);}
三、完整代码示例
import lombok.extern.slf4j.Slf4j;
import org.dyn4j.dynamics.Body;
import org.dyn4j.geometry.Geometry;
import org.dyn4j.geometry.MassType;
import org.dyn4j.world.BroadphaseCollisionData;
import org.dyn4j.world.ManifoldCollisionData;
import org.dyn4j.world.NarrowphaseCollisionData;
import org.dyn4j.world.World;
import org.dyn4j.world.listener.CollisionListener;@Slf4j
public class WorldApp {public static void main(String[] args) {World<Body> world = new World<>();world.setGravity(World.ZERO_GRAVITY);Body npcBody = createBody(0, 0, 1, 1);Body itemBody = createBody(4, 0, 1, 1);world.addBody(npcBody);world.addBody(itemBody);world.addCollisionListener(new CollisionListener<>() {@Overridepublic boolean collision(BroadphaseCollisionData broadphaseCollisionData) {log.info("broadphaseCollisionData:{}, {}",broadphaseCollisionData.getBody1().getTransform().getTranslation(),broadphaseCollisionData.getBody2().getTransform().getTranslation());return false;}@Overridepublic boolean collision(NarrowphaseCollisionData narrowphaseCollisionData) {log.info("narrowphaseCollisionData:{}", narrowphaseCollisionData);return false;}@Overridepublic boolean collision(ManifoldCollisionData manifoldCollisionData) {log.info("manifoldCollisionData:{}", manifoldCollisionData);return false;}});for (int i = 0; i < 100; i++) {itemBody.translate(-0.1, 0);if (world.getBroadphaseDetector().detect(itemBody, npcBody)) {log.info("npc: {}, item: {}", npcBody.getTransform().getTranslation(), itemBody.getTransform().getTranslation());break;}world.update(1d / 60d);}}/*** 创建物体*/private static Body createBody(double x, double y, double w, double h) {Body body = new Body();body.addFixture(Geometry.createRectangle(w, h));body.getTransform().setTranslation(x, y);body.setMass(MassType.NORMAL);return body;}
}
会打印
11:31:49.723 [main] [] INFO c.z.g.t.l.WorldApp.collision(WorldApp.java:62) broadphaseCollisionData:(1.1999999999999975, 0.0), (0.0, 0.0)
11:31:49.723 [main] [] INFO c.z.g.t.l.WorldApp.main(WorldApp.java:84) npc: (0.0, 0.0), item: (1.0999999999999974, 0.0)
四、优化补充
在上述代码中,添加了碰撞监听器,使用了BroadphaseDetector().detect()
方法进行碰撞检测。而在实际的使用中,世界更新时(调用update或者step方法)会自动检测所有碰撞体,可以使用getCollisionDataIterator()
方法获取。这样可以避免循环世界所有的物体判断碰撞。
/*** 移动并检测是否碰撞* @param body 要检测的物体*/public static boolean isCollision(Body body, double x, double y) {// 保存上次位置Transform copy = body.getTransform().copy();body.translate(x, y);world.update(1d / 60d);// 获取所有碰撞体Iterator<WorldCollisionData<Body>> collisionDataIterator = world.getCollisionDataIterator();// 直接遍历碰撞体,判断是否存在碰撞while (collisionDataIterator.hasNext()) {WorldCollisionData<Body> collisionData = collisionDataIterator.next();if (collisionData.getBody1() == body || collisionData.getBody2() == body) {// 如果碰撞,回退上次位置body.getTransform().set(copy);return true;}}return false;}
总结
通过以上步骤,我们学习了如何使用 dyn4j 实现基本的碰撞检测功能。dyn4j 提供了丰富的物理模拟功能,可以帮助开发者快速构建复杂的物理交互场景。如果需要更高级的功能,可以参考官方文档进一步探索。
参考资料:dyn4j 官方文档