文章目錄
- 前言
- 一、環境準備
- 添加依賴
- 基本概念
- 二、實現步驟
- 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 官方文檔