[Lua][Love Engine] 有效碰撞處理の類別與位掩碼 | fixture:setFilterData

来源:https://www.cnblogs.com/linxiaoxu/archive/2023/08/21/17646878.html
-Advertisement-
Play Games

如果物理實體有很多,那每個實體都要判斷和其他實體是否發生碰撞。有沒有比較簡便的方法呢,可以使用二進位與位掩碼,設置實體的類別,然後用位掩碼計算來得到兩者是否發生碰撞的結果。另外LOVE還提供了一個組別的功能,可以直接跳過計算結果,強制兩者發生碰撞和強制不發生碰撞 ...


有效的碰撞處理

只用IF判斷

假設在一個物理世界,不希望兩個同類實體發生碰撞,那麼

local begin_contact_callback = function(fixture_a, fixture_b)
  local entity_a_type = fixture_a:getUserData()
  local entity_b_type = fixture_b:getUserData()
  -- 如果碰撞的兩個實體不同
  if entity_a_type ~= entity_b_type then
	-- 
  end
end

但是如果新加了可互動元素,如一種道具,只能跟玩家實體碰撞,那麼

local begin_contact_callback = function(fixture_a, fixture_b)
  local a = fixture_a:getUserData()
  local b = fixture_b:getUserData()
  if (a == 'powerup' and b == 'player') or (a == 'player' and b == 'powerup') then
	--
  elseif a ~= b and a ~= 'powerup' and b~= 'powerup' then
	--
  end
end

如果再加上其他東西,比如只有玩家可以推動的方塊,代碼量會飛速膨脹

⭐ 使用二進位和位掩碼

假設游戲已經有幾十種實體,我們可以根據實體在游戲內的作用歸為五類,給每種實體綁定類別和位掩碼

實體類別 類別對應的二進位 位掩碼
場景(如雲、花) 0000 0000
玩家 0001 1110
道具 0010 1001
敵人 0100 1001
牆體 1000 1111

比如玩家實體和敵人實體,在函數中我們提取玩家的類別和敵人的位掩碼做位與運算

0001   玩家 類別
1001   敵人 位掩碼
----
0001   不為0 發生碰撞

再舉個例子,敵人碰撞到了道具

0100   敵人 類別
1001   道具 位掩碼
----
0000   為0 不發生碰撞

因此,在上面表格的情況下

  • 場景實體沒有被分配類別(要保證某1位為1),不會和任何實體發生碰撞
  • 玩家實體不能相互碰撞,能與道具、敵人、牆體發生碰撞
  • 道具實體能跟牆體、玩家發生碰撞
  • 敵人實體能跟牆體、玩家發生碰撞
  • 牆體實體能跟所有類別發生碰撞(除場景)

註:如果實體不能跟牆體發生碰撞,那麼一旦生成就會直接無限墜落至無底洞

綁定到實體

先生成實體的類別二進位和位掩碼,比如在squre.lua中,創建了一個實體squre

某種情況下,實體可以屬於多個類別,比如1011,這個實體既是牆體也是敵人、玩家,雖然邏輯上是不可能的,但相應的碰撞處理均會發生

兩個蘋果,第一個蘋果可以只是場景擺件,僅與地形碰撞;第二個蘋果可以是道具,與地形和玩家均可碰撞

square.category = tonumber('0001', 2)
square.mask = tonumber('1110', 2)
square.group = 0

綁定到fixture上,由於設置了類別和位掩碼,組號填0意味著沒有組別

square.fixture:setFilterData(square.category, square.mask, square.group)
-- Fixture:setCategory, Fixture:setMask or Fixture:setGroupIndex 

LOVE 引擎最多支持16位二進位的類別和位掩碼,即0000000000000000

⭐ fixture創建時預設類別為1D,位掩碼為65535D,組別均為0

代碼與效果

-- entities/block.lua
local world = require 'world'

return function(x, y, width, height, rigidbody, category, bitmask, group)
    e = {}
    e.body = love.physics.newBody(world, x, y, rigidbody)
    e.body:setMass(32)
    e.shape = love.physics.newRectangleShape(width, height)
    e.fixture = love.physics.newFixture(e.body, e.shape)
    e.fixture:setFilterData(category, bitmask, group)

    function e:draw()
        love.graphics.polygon('line', self.body:getWorldPoints(self.shape:getPoints()))
        local x, y = self.body:getPosition()
        love.graphics.print({{0, 1, 0}, (category .. '+' .. bitmask) or group}, x, y, nil)
    end
    return e
end

下麵我們定義了兩個類別,分別是001010

local entities = {block(400, 400, 300, 10, 'static', '001', '011', 0),
                  block(400, 300, 50, 50, 'dynamic', '011', '011', 0),
                  block(400, 200, 40, 40, 'dynamic', '010', '011', 0),
                  block(400, 100, 30, 30, 'dynamic', '010', '011', 0)}
love_RDKN36y4Zd

修改第二個和第三個方塊的位掩碼

local entities = {block(400, 400, 300, 10, 'static', '001', '011', 0),
                  block(400, 300, 50, 50, 'dynamic', '011', '000', 0),
                  block(400, 200, 40, 40, 'dynamic', '010', '001', 0),
                  block(400, 100, 30, 30, 'dynamic', '010', '011', 0)}
love_WhSDZWlQMQ

⭐ 組別

我們可以為各個實體設置組別,同組別將直接無視類別與位掩碼的計算結果,同組別且正數總是會碰撞,同組別且負數總不會碰撞。

    e.fixture:setFilterData( xx , xx , group)
    -- e.fixture:setGroupIndex(group)

考慮如下代碼

local entities = {block(400, 400, 300, 10, 'static', '001', '011', 0),
                  block(400, 300, 50, 50, 'dynamic', '010', '001', 0),
                  block(400, 200, 40, 40, 'dynamic', '010', '001', 0)}

第二個方塊跟第三個方塊不會碰撞,設置組別為1

local entities = {block(400, 400, 300, 10, 'static', '001', '011', 0),
                  block(400, 300, 50, 50, 'dynamic', '010', '001', 1),
                  block(400, 200, 40, 40, 'dynamic', '010', '001', 1)}
image-20230821192630627

再考慮如下代碼,

local entities = {block(400, 400, 300, 10, 'static', '001', '011', 0),
                  block(400, 300, 50, 50, 'dynamic', '010', '011', 1),
                  block(400, 200, 40, 40, 'dynamic', '010', '011', 1)}

第二個方塊跟第三個方塊會碰撞,將組別設置為-1,即使算出來要發生碰撞,由於相同組且是負數,永遠也不會碰撞

local entities = {block(400, 400, 300, 10, 'static', '001', '011', 0),
                  block(400, 300, 50, 50, 'dynamic', '010', '011', -1),
                  block(400, 200, 40, 40, 'dynamic', '010', '011', -1)}
image-20230821192825989
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • ## 面向對象三要素 封裝:顧名思義,將函數或變數集中定義在類中,而非散亂分佈。 繼承:擴展類的功能。 多態:在擴展類的功能的基礎之上,實現其內部方法的多樣性。 ### 多態的本質 針對某個類型的方法調用,其真正執行的方法取決於運行時期實際類型的方法。 ```java package Project ...
  • 之前用的python2.7+robotframework進行的自動化測試,python3的還沒嘗試,今天嘗試了下,搭建環境的時候也是各種報錯,搞了幾小時才搞好了。 一、python安裝 下載python然後安裝,地址:https://www.python.org/,安裝時勾選添加到環境變數,安裝後c ...
  • ## 一、前言 - 還在為排查Java程式線上問題頭痛嗎,看我們用阿裡開源的診斷神器 Arthas 來幫您 - 本文開篇主要介紹 阿裡開源的診斷神器Arthas 3.7.0版本,watch、jad、classloader 命令,以 Debian 11、openjdk 11 為例 ## 二、Artha ...
  • ## 題目描述 給你兩個 非空 的鏈表,表示兩個非負的整數。它們每位數字都是按照 逆序 的方式存儲的,並且每個節點只能存儲 一位 數字。請你將兩個數相加,並以相同形式返回一個表示和的鏈表。你可以假設除了數字 0 之外,這兩個數都不會以 0 開頭。 ## 例子 > 輸入:l1 = [2,4,3], l ...
  • 虛擬機類載入的時機和過程 一、類載入的時機 類從被載入到虛擬機記憶體中開始,到卸載出記憶體為止,它的整個生命周期包括:載入(Loading)、驗證(Verification)、準備(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)和卸載( ...
  • - Future :獲取非同步返回的結果需要使用輪詢的方式,消耗cup ```java ExecutorService executorService = Executors.newFixedThreadPool(10); Future future = executorService.submit( ...
  • 本文閱讀nacos-2.0.2的config源碼,編寫示例,分析推送配置、監聽配置的原理。 # 客戶端 ## 創建NacosConfigService對象 ```java Properties properties = new Properties(); properties.setProperty ...
  • 本教程將演示用Python開發一個簡單的數字猜測游戲的過程。 ### 競猜游戲的機制 我們正試圖開發一個游戲,從用戶那裡獲取上限和下限,在這個範圍內生成一個隨機數,要求用戶猜測這個數字,並計算用戶用了多少條線索才猜對了。這個游戲將只基於CLI。 ### 使用Python中的random 模塊的數字猜 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...