與架構(gòu)變遷:從 Box2D 移植到 TypeScript 引擎的完整技術(shù)脈絡(luò))
游戲開發(fā)【免費(fèi)下載鏈接】planck.js2D JavaScript Physics Engine項(xiàng)目地址https://gitcode.com/gh_mirrors/pl/planck.js點(diǎn)擊查看免費(fèi)下載planck.js 是一個(gè)以 TypeScript/JavaScript 實(shí)現(xiàn)的 2D 物理引擎MIT 協(xié)議源自 Box2D 的跨平臺(tái) HTML5 游戲開發(fā)移植。本文以倉(cāng)庫(kù)根目錄的 CHANGES.md 變更記錄為主線逐版還原 0.1 → 0.2 → 1.0.0 → 1.1.0 的演進(jìn)脈絡(luò)并結(jié)合 src、vite.config.mts 等源碼證據(jù)解讀每一次重構(gòu)背后的設(shè)計(jì)動(dòng)機(jī)與 API 遷移方式幫助讀者理解當(dāng)前引擎的模塊結(jié)構(gòu)、事件系統(tǒng)與命名規(guī)范并掌握從舊版 API 升級(jí)到新版的關(guān)鍵對(duì)照。版本演進(jìn)總覽當(dāng)前倉(cāng)庫(kù) package.json 版本為 1.5.0而 CHANGES.md 記錄了從早期移植到現(xiàn)代化重構(gòu)的四個(gè)關(guān)鍵階段版本核心變化性質(zhì)0.1目錄重排、類合并、標(biāo)志位改布爾字段、事件系統(tǒng)引入大范圍架構(gòu)重構(gòu)0.2TypeScript 定義加入、向量組合運(yùn)算 API 重命名、關(guān)節(jié)構(gòu)造器清理API 命名規(guī)范化1.0.0全量 TypeScript 遷移、性能優(yōu)化語(yǔ)言與運(yùn)行時(shí)升級(jí)1.1.0Vite 構(gòu)建遷移工程化升級(jí)從變更記錄看planck.js 的演進(jìn)方向非常清晰先是內(nèi)部架構(gòu)去 Box2D 化0.1再是公開 API 規(guī)范化0.2隨后是類型系統(tǒng)與構(gòu)建工具鏈的現(xiàn)代化1.0.0 / 1.1.0。0.1架構(gòu)重構(gòu)——從忠實(shí)移植到JavaScript 原生0.1 是信息量最大的一次版本幾乎重寫了整個(gè)引擎的組織方式。以下按主題分組解讀。目錄結(jié)構(gòu)與文件組織source code directory layout changed, classes moved around!從當(dāng)前倉(cāng)庫(kù)的目錄布局可以反推這次調(diào)整的結(jié)果物理與碰撞基礎(chǔ)類型集中在 src/commonVec2、Vec3、Mat22、Mat33、Rot、Transform、Sweep、Jacobian等碰撞算法集中在 src/collisionAABB、BroadPhase、DynamicTree、Distance、Manifold、Shape、TimeOfImpact形狀實(shí)現(xiàn)在 src/collision/shapeCircleShape、EdgeShape、PolygonShape、ChainShape、BoxShape及各Collide*配對(duì)碰撞函數(shù)動(dòng)力學(xué)與求解器集中在 src/dynamicsBody、Fixture、Contact、Joint、World、Solver關(guān)節(jié)實(shí)現(xiàn)位于 src/dynamics/joint。b2Class renamed to Class早期版本中所有類都繼承自一個(gè)b2Class基類0.1 起統(tǒng)一改名為Class。當(dāng)前源碼中已完全搜不到b2Class或GrowableStack的痕跡說(shuō)明這兩項(xiàng)已徹底移除。Dumping is removed, Drawing is moved to testbed序列化/反序列化能力被拆分場(chǎng)景dump功能被移除繪圖相關(guān)能力移入 testbed即planck-with-testbed構(gòu)建產(chǎn)物見(jiàn) vite.config.mts 的buildTestbed分支。這也解釋了package.json中./with-testbed導(dǎo)出子路徑的存在——核心引擎與可視化測(cè)試臺(tái)被明確解耦。GrowableStack replaced with native array, Timer is changedBox2D 風(fēng)格的自增長(zhǎng)棧數(shù)據(jù)結(jié)構(gòu)被原生數(shù)組取代計(jì)時(shí)器改為基于Date.now()的輕量實(shí)現(xiàn)見(jiàn) src/util/Timer.tsnow()直接返回Date.now()diff(time)計(jì)算差值。數(shù)學(xué)與幾何 API 拆分Math is changed and splitVec2.Min/Max renamed to Vec2.Upper/Lower and several other methods added數(shù)學(xué)工具被拆分到多個(gè)文件Vec2、Vec3、Mat22、Mat33、Rot、Transform、Sweep等見(jiàn) src/common同時(shí)Vec2.Min/Max更名為Vec2.Upper/Lower并補(bǔ)充了若干新方法。當(dāng)前 Vec2.ts 中可以看到大量以matrix.*前綴出現(xiàn)的內(nèi)部向量運(yùn)算輔助以及setVec2、add、setCombine、addCombine、subCombine、setMul、addMul、subMul等方法見(jiàn) Vec2.ts。TestOverlap moved from Collision to DistancetestOverlap從 Collision 模塊移入 Distance 模塊當(dāng)前位于 src/collision/Distance.ts它通過(guò)設(shè)置input.useRadii true調(diào)用Distance算法計(jì)算兩形狀最近距離并以output.distance 10.0 * EPSILON判定是否重疊。同時(shí) Distance.ts 保留了 legacy 導(dǎo)出Distance.testOverlap、Distance.Input、Distance.Output、Distance.Proxy、Distance.Cache方便舊代碼平滑遷移Distance.ts。Distance method, DistanceInput/Output and SimplexCache merged into a stateful Distance class原獨(dú)立的Distance函數(shù)、DistanceInput、DistanceOutput、SimplexCache被合并進(jìn)一個(gè)有狀態(tài)的 Distance 模塊。當(dāng)前 Distance.ts 中DistanceInput、DistanceOutput、SimplexCache仍作為獨(dú)立類存在分別見(jiàn) Distance.ts、Distance.ts、Distance.ts但Distance本體變成了可復(fù)用的函數(shù)式接口配合模塊級(jí)復(fù)用對(duì)象simplex、output、cache等減少 GC 壓力內(nèi)部統(tǒng)計(jì)stats.gjkCalls、stats.gjkIters也可用于基準(zhǔn)測(cè)試Distance.ts。Shape.computeDistanceProxy is added形狀基類Shape新增抽象方法computeDistanceProxysrc/collision/Shape.ts各形狀CircleShape、EdgeShape、PolygonShape、ChainShape分別實(shí)現(xiàn)為 GJK 距離算法提供支持點(diǎn)查詢代理。Distance內(nèi)部通過(guò)shape.computeDistanceProxy(this, index)裝載代理Distance.ts。接觸與碰撞架構(gòu)合并Contact and Collide classes merged, Contact registration/creation is changedContactSolver/VelocityConstraint/PositionConstraint merged with ContactContactManager/ContactListener merged into World (and Contact)這三條變更合起來(lái)看原先分散的碰撞、求解、管理職責(zé)被壓縮。當(dāng)前 src/dynamics/Contact.ts 一個(gè)文件內(nèi)同時(shí)包含VelocityConstraintPoint、速度約束求解initVelocityConstraint、solveVelocityConstraint與位置約束求解solvePositionConstraint、solvePositionConstraintTOI即舊版ContactSolver/VelocityConstraint/PositionConstraint的邏輯已被合并進(jìn) Contact 類。而ContactManager/ContactListener的職責(zé)則并入 src/dynamics/World.ts 與 Contact。Manifold files is added, WorldManifold.Initialize moved to Manifold.getWorldManifold新增獨(dú)立的 src/collision/Manifold.ts原WorldManifold.Initialize變?yōu)镸anifold.getWorldManifold。該方法接收世界變換與形狀半徑將局部流形換算為世界坐標(biāo)下的法線、接觸點(diǎn)與分離距離見(jiàn) Manifold.ts并處理e_circles、e_faceA、e_faceB三種流形類型。Manifold.ts 還靜態(tài)導(dǎo)出clipSegmentToLine、ClipVertex、getPointStates、PointStateManifold.ts。ContactFilter.ShouldCollide moved to Fixture?碰撞過(guò)濾判定下沉到 Fixture 層與 Fixture 的過(guò)濾數(shù)據(jù)group、categoryBits、maskBits耦合更緊密。碰撞配對(duì)階段仍由 BroadPhase 的updatePairs驅(qū)動(dòng)src/collision/BroadPhase.ts測(cè)試見(jiàn) src/test/Collision.test.ts。求解流程重組Island/World.Solve/SolveTOI moved to new SolverPosition/Velocity correction objects assigned to owner bodies孤島Island管理與世界級(jí)求解含 TOI 連續(xù)碰撞求解被移入新的 src/dynamics/Solver.ts其中定義TimeStep、ContactImpulse等求解輸入輸出類型位置/速度矯正對(duì)象則歸屬到各自的 Body 上消除了大量臨時(shí)對(duì)象傳遞。二進(jìn)制標(biāo)志位 → 布爾字段binary flags changes to boolean fields (awakeFlag, autoSleepFlag, bulletFlag, fixedRotationFlag, activeFlag, enabledFlag, islandFlag, touchingFlag, filterFlag, bulletHitFlag, toiFlag, clearForces, newFixture, locked)這是最影響內(nèi)部實(shí)現(xiàn)的一處改動(dòng)原本用單個(gè)整數(shù)按位存儲(chǔ)的十幾個(gè)狀態(tài)標(biāo)志全部改為獨(dú)立的布爾字段。好處是代碼可讀性與調(diào)試友好度大幅提升代價(jià)是需要逐一核對(duì)語(yǔ)義遷移。以 src/dynamics/Body.ts 為例當(dāng)前可見(jiàn)m_bulletFlag、m_autoSleepFlag、m_awakeFlag、m_activeFlag、m_fixedRotationFlag等字段并通過(guò)isBullet/setBulletBody.ts、isSleepingAllowed/setSleepingAllowedBody.ts、isAwake/setAwakeBody.ts、isActive/setActiveBody.ts、isFixedRotation/setFixedRotationBody.ts成對(duì)暴露。字符串類型系統(tǒng)Body.Is[Type]/Set[Type] addedShape, Body and Joint string types (circle, dynamic, mouse-joint, etc.)引擎從數(shù)值枚舉走向字符串類型標(biāo)識(shí)這是一次面向開發(fā)者的重大 API 變更形狀類型ShapeType circle | edge | polygon | chainsrc/collision/Shape.tsgetType()返回對(duì)應(yīng)字符串剛體類型BodyType static | kinematic | dynamicsrc/dynamics/Body.ts并同時(shí)保留Body.STATIC/KINEMATIC/DYNAMIC靜態(tài)常量與setStatic/setDynamic/setKinematic/setType/getType系列方法Body.ts關(guān)節(jié)類型DistanceJoint、FrictionJoint、GearJoint、MotorJoint、MouseJoint、PrismaticJoint、PulleyJoint、RevoluteJoint、RopeJoint、WeldJoint、WheelJoint各自定義static TYPE如distance-jointDistanceJoint.ts、mouse-jointMouseJoint.ts、wheel-jointWheelJoint.ts等Joint.getType()返回該字符串Joint.ts。字符串類型的價(jià)值在于序列化、調(diào)試輸出、以及testbed的 UI 展示關(guān)節(jié)樣式匹配、形狀渲染分支都可以直接以可讀字符串為鍵無(wú)需維護(hù)枚舉 ? 字符串的映射表。測(cè)試中可直接斷言b1.getFixtureList().getType() circlesrc/test/Basic.test.ts。世界監(jiān)聽器 → 事件系統(tǒng)World listeners changed to events: PostSolve, PreSolve, EndContact, BeginContact, SayGoodby to post-solve, pre-solve, end-contact, begin-contact, remove-body, remove-joint, remove-fixture這是 0.1 中最具代表性的公開 API 變更從接口式監(jiān)聽器轉(zhuǎn)向事件發(fā)布/訂閱。當(dāng)前World以on(name, listener)/off(name, listener)/publish(name, ...)三件套實(shí)現(xiàn)事件機(jī)制src/dynamics/World.ts支持的事件包括事件名回調(diào)參數(shù)觸發(fā)時(shí)機(jī)begin-contact(contact)兩個(gè) fixture 開始接觸World.tsend-contact(contact)兩個(gè) fixture 停止接觸World.tspre-solve(contact, oldManifold)接觸更新后、進(jìn)入求解器前可修改流形或禁用接觸World.tspost-solve(contact, impulse)求解完成后用于讀取沖量World.tsremove-body/remove-joint/remove-fixture(body)/(joint)/(fixture)對(duì)應(yīng)實(shí)體被顯式或隱式移除時(shí)World.ts此外還擴(kuò)展了add-body、add-joint、add-fixture三個(gè)新增事件World.ts。事件發(fā)布點(diǎn)在 Contact 與 World 內(nèi)部如beginContact/endContact/preSolve/postSolve均通過(guò)this.publish(...)觸發(fā)World.ts。官方文檔注明這些回調(diào)中不能創(chuàng)建/銷毀世界實(shí)體World.ts且同一時(shí)間步內(nèi)同一接觸可能收到多次回調(diào)?;卣{(diào)類 → 函數(shù)Callbacks classes changed to functions: DynamicTree.query DynamicTree.rayCast BroadPhase.updatePairs BroadPhase.rayCast BroadPhase.query World.queryAAB World.rayCastBox2D 中以回調(diào)對(duì)象 虛方法實(shí)現(xiàn)查詢的方式被替換為純函數(shù)回調(diào)DynamicTree.query(aabb, callback)與DynamicTree.rayCast(input, callback)src/collision/DynamicTree.tsBroadPhase.query、BroadPhase.rayCast、BroadPhase.updatePairs(addPairCallback)src/collision/BroadPhase.tsWorld.queryAABB(aabb, callback)src/dynamics/World.ts與World.rayCast(point1, point2, callback)World.ts回調(diào)返回false可提前終止 AABB 查詢r(jià)ayCast 回調(diào)返回?cái)?shù)值可控制射線maxFraction的收縮。0.2API 命名規(guī)范化與 TypeScript 定義向量組合運(yùn)算重命名wSet/wAdd/wSub(a, v, b, w) replaced with combine/setCombine/addCombine/subCombine(a, v, b, w)wSet/wAdd/wSub(a, v) replaced with mul/setMul/addMul/subMul(a, v)Vec2的加權(quán)賦值方法從帶w前綴的模糊命名改為語(yǔ)義明確的組合運(yùn)算命名。舊方法在 Vec2.ts 中仍保留但標(biāo)記deprecated并內(nèi)部委托給新方法wSet(a, v, b, w)→setCombine(a, v, b, w)語(yǔ)義為this a*v b*wwSet(a, v)→setMul(a, v)語(yǔ)義為this a*vVec2.tswAdd→addCombine/addMul語(yǔ)義為this a*v ( b*w)Vec2.tswSub→subCombine/subMul語(yǔ)義為this - a*v ( b*w)Vec2.ts。注意setCombine的注釋特別說(shuō)明this可能即是w// this may be w因此實(shí)現(xiàn)先計(jì)算局部變量再賦值避免別名沖突——這是向量庫(kù)常見(jiàn)的坑。此外Vec2.combine(a, v, b, w)靜態(tài)方法也基于setCombine實(shí)現(xiàn)Vec2.ts。關(guān)節(jié)構(gòu)造器清理Joints constructors cleanupTypeScript definitions added各關(guān)節(jié)構(gòu)造器從需要顯式傳入大量參數(shù)改為統(tǒng)一的definition 對(duì)象 可選 bodyA/bodyB風(fēng)格例如 Joint.ts 支持兩種構(gòu)造形式new Joint(def)或new Joint(def, bodyA, bodyB)其中bodyA可從def.bodyA解出。這一約定配合0.2引入的 TypeScript 定義文件讓關(guān)節(jié)創(chuàng)建更類型安全、更易讀。1.0.0全量 TypeScript 遷移與性能優(yōu)化Typescript migrationPerformance improvements1.0.0 將引擎主體含測(cè)試從 JavaScript 全面遷移到 TypeScript。當(dāng)前倉(cāng)庫(kù)結(jié)構(gòu)可見(jiàn)完整證據(jù)源碼全部為.ts文件src 下的*.ts、測(cè)試使用 Vitest*.test.ts位于 src/test與 src/serializer/test、類型測(cè)試使用tsdtest-d/planck.test-d.ts。性能優(yōu)化方面從代碼結(jié)構(gòu)可以推斷幾個(gè)方向?qū)ο髲?fù)用/池化模塊級(jí)復(fù)用DistanceOutput、SimplexCache、Simplex等對(duì)象[Distance.ts](https://link.gitcode.com/i/397dcbd86cb532fc38a5bf147b3c63f4#L740Vec2、Mat22等臨時(shí)對(duì)象通過(guò)內(nèi)部matrix.*工具復(fù)用src/util/Pool.ts 提供對(duì)象池構(gòu)建期常量折疊ASSERT、_ASSERT、CONSTRUCTOR_FACTORY在構(gòu)建時(shí)通過(guò) Vitedefine替換為false/truevite.config.mts運(yùn)行時(shí)斷言在生產(chǎn)構(gòu)建中被移除統(tǒng)計(jì)埋點(diǎn)stats.gjkCalls、stats.gjkIters等計(jì)數(shù)器Distance.ts服務(wù)于 benchmark 基準(zhǔn)測(cè)試npm run benchmark會(huì)結(jié)合 Git 提交信息對(duì)比性能見(jiàn) package.json。1.1.0Vite 構(gòu)建遷移Vite build migration構(gòu)建工具鏈統(tǒng)一遷移到 Vite由 vite.config.mts 完成以下工作雙產(chǎn)物構(gòu)建核心引擎planck入口 src/main.ts與可視化測(cè)試臺(tái)planck-with-testbed入口 testbed/main.ts分別打包vite.config.mts同時(shí)輸出 ES.mjs與 UMD.js兩種格式vite.config.mts類型聲明打包通過(guò)vite-plugin-dts-bundle-generator生成planck.d.tsvite.config.mts供package.json的exports字段分發(fā)package.jsonLicense 注入rollup-plugin-license在每個(gè)構(gòu)建產(chǎn)物頭部注入 MIT License 橫幅vite.config.mts壓縮產(chǎn)物npm run build額外用 terser 生成planck.min.js與planck-with-testbed.min.jspackage.json分別提供給 jsDelivr/unpkg CDN 使用package.json。從 1.1.0 起npm run dev/npm run testbed啟動(dòng) Vite 開發(fā)服務(wù)器并加載 testbed 交互式測(cè)試臺(tái)npm run test運(yùn)行 Vitest 測(cè)試npm run docs:dev基于 Vitepress 預(yù)覽 docs 文檔站package.json。從 0.x 遷移到當(dāng)前版本的快速對(duì)照綜合 0.1 與 0.2 的破壞性變更整理出面向升級(jí)者的核心對(duì)照表舊寫法0.x新寫法當(dāng)前依據(jù)Vec2.wSet(a, v, b, w)vec.setCombine(a, v, b, w)Vec2.tsVec2.wAdd(a, v)vec.addMul(a, v)Vec2.tsVec2.wSub(a, v, b, w)vec.subCombine(a, v, b, w)Vec2.tsVec2.Min/MaxVec2.Upper/LowerCHANGES.md 0.1 條目數(shù)值類型枚舉字符串類型circle、dynamic、mouse-joint等Shape.ts、Body.ts、MouseJoint.tsWorldManifold.Initialize(...)manifold.getWorldManifold(wm, xfA, radiusA, xfB, radiusB)Manifold.ts二進(jìn)制標(biāo)志位布爾字段 isXxx/setXxxBody.ts監(jiān)聽器接口BeginContact、SayGoodbye等事件world.on(begin-contact, ...)、world.on(remove-body, ...)World.ts回調(diào)對(duì)象函數(shù)回調(diào)world.queryAABB(aabb, cb)、world.rayCast(p1, p2, cb)World.ts、World.ts關(guān)節(jié)多參數(shù)構(gòu)造定義對(duì)象構(gòu)造new RevoluteJoint({...}, bodyA, bodyB)Joint.ts延伸閱讀CHANGELOG.md更細(xì)粒度的逐版本變更說(shuō)明docs/core-concepts.md 與 docs/world/simulation.md理解 World 事件與求解流程的使用語(yǔ)境src/dynamics/World.ts 與 src/common/Vec2.ts事件系統(tǒng)與向量 API 的第一手實(shí)現(xiàn)example 目錄下的 60 個(gè)示例如Breakable.ts、Pinball.ts、RayCast.ts新 API 的實(shí)際調(diào)用范式vite.config.mts 與 package.json構(gòu)建與發(fā)布產(chǎn)物全貌。贊分享游戲開發(fā)【免費(fèi)下載鏈接】planck.js2D JavaScript Physics Engine項(xiàng)目地址https://gitcode.com/gh_mirrors/pl/planck.js點(diǎn)擊查看免費(fèi)下載相關(guān)推薦Qlib 版本演進(jìn)全解析從 0.1.0 到 0.8.0 的架構(gòu)變遷與技術(shù)脈絡(luò)Qlib 版本演進(jìn)全解析從 0.1.0 到 0.8.0 的架構(gòu)變遷與技術(shù)脈絡(luò) Qlib 是一款面向 AI 量化研究的開源平臺(tái)其核心代碼自 0.1.0 起步金融科技人工智能機(jī)器學(xué)習(xí)數(shù)據(jù)分析強(qiáng)化學(xué)習(xí)VCMI 引擎版本演進(jìn)全解析從 1.8.0 開發(fā)版到 0.x 時(shí)代的完整技術(shù)變更脈絡(luò)VCMI 引擎版本演進(jìn)全解析從 1.8.0 開發(fā)版到 0.x 時(shí)代的完整技術(shù)變更脈絡(luò) 本文以倉(cāng)庫(kù)根目錄的 ChangeLog.md https://link.游戲開發(fā)flow-for-vscode 版本演進(jìn)全景解析從 LSP 遷移、安全加固到 TypeScript 重寫的完整技術(shù)脈絡(luò)flow for vscode 版本演進(jìn)全景解析從 LSP 遷移、安全加固到 TypeScript 重寫的完整技術(shù)脈絡(luò) Flow 是 JavaScript 的開發(fā)工具靜態(tài)分析代碼質(zhì)量上一篇手機(jī)號(hào)找回QQ號(hào)碼Python工具如何幫你3分鐘搞定賬號(hào)關(guān)聯(lián)驗(yàn)證下一篇超越傳統(tǒng)OCRPaddleOCR-VL-1.6-4bit如何處理傾斜文檔、表格和多語(yǔ)言內(nèi)容創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考