[Lua][Love Engine] 有效碰撞处理の类别与位掩码 | fixture:setFilterData ...

金歌  金牌会员 | 2023-8-30 20:44:46 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 922|帖子 922|积分 2766

有效的碰撞处理

只用IF判断

假设在一个物理世界,不希望两个同类实体发生碰撞,那么
  1. local begin_contact_callback = function(fixture_a, fixture_b)
  2.   local entity_a_type = fixture_a:getUserData()
  3.   local entity_b_type = fixture_b:getUserData()
  4.   -- 如果碰撞的两个实体不同
  5.   if entity_a_type ~= entity_b_type then
  6.         --
  7.   end
  8. end
复制代码
但是如果新加了可互动元素,如一种道具,只能跟玩家实体碰撞,那么
  1. local begin_contact_callback = function(fixture_a, fixture_b)
  2.   local a = fixture_a:getUserData()
  3.   local b = fixture_b:getUserData()
  4.   if (a == 'powerup' and b == 'player') or (a == 'player' and b == 'powerup') then
  5.         --
  6.   elseif a ~= b and a ~= 'powerup' and b~= 'powerup' then
  7.         --
  8.   end
  9. end
复制代码
如果再加上其他东西,比如只有玩家可以推动的方块,代码量会飞速膨胀
⭐ 使用二进制和位掩码

假设游戏已经有几十种实体,我们可以根据实体在游戏内的作用归为五类,给每种实体绑定类别和位掩码
实体类别类别对应的二进制位掩码场景(如云、花)00000000玩家00011110道具00101001敌人01001001墙体10001111比如玩家实体和敌人实体,在函数中我们提取玩家的类别和敌人的位掩码做位与运算
  1. 0001   玩家 类别
  2. 1001   敌人 位掩码
  3. ----
  4. 0001   不为0 发生碰撞
复制代码
再举个例子,敌人碰撞到了道具
  1. 0100   敌人 类别
  2. 1001   道具 位掩码
  3. ----
  4. 0000   为0 不发生碰撞
复制代码
因此,在上面表格的情况下

  • 场景实体没有被分配类别(要保证某1位为1),不会和任何实体发生碰撞
  • 玩家实体不能相互碰撞,能与道具、敌人、墙体发生碰撞
  • 道具实体能跟墙体、玩家发生碰撞
  • 敌人实体能跟墙体、玩家发生碰撞
  • 墙体实体能跟所有类别发生碰撞(除场景)
注:如果实体不能跟墙体发生碰撞,那么一旦生成就会直接无限坠落至无底洞
绑定到实体

先生成实体的类别二进制和位掩码,比如在squre.lua中,创建了一个实体squre
某种情况下,实体可以属于多个类别,比如1011,这个实体既是墙体也是敌人、玩家,虽然逻辑上是不可能的,但相应的碰撞处理均会发生
两个苹果,第一个苹果可以只是场景摆件,仅与地形碰撞;第二个苹果可以是道具,与地形和玩家均可碰撞
  1. square.category = tonumber('0001', 2)
  2. square.mask = tonumber('1110', 2)
  3. square.group = 0
复制代码
绑定到fixture上,由于设置了类别和位掩码,组号填0意味着没有组别
  1. square.fixture:setFilterData(square.category, square.mask, square.group)
  2. -- Fixture:setCategory, Fixture:setMask or Fixture:setGroupIndex
复制代码
LOVE 引擎最多支持16位二进制的类别和位掩码,即0000000000000000
⭐ fixture创建时默认类别为1D,位掩码为65535D,组别均为0
代码与效果
  1. -- entities/block.lua
  2. local world = require 'world'
  3. return function(x, y, width, height, rigidbody, category, bitmask, group)
  4.     e = {}
  5.     e.body = love.physics.newBody(world, x, y, rigidbody)
  6.     e.body:setMass(32)
  7.     e.shape = love.physics.newRectangleShape(width, height)
  8.     e.fixture = love.physics.newFixture(e.body, e.shape)
  9.     e.fixture:setFilterData(category, bitmask, group)
  10.     function e:draw()
  11.         love.graphics.polygon('line', self.body:getWorldPoints(self.shape:getPoints()))
  12.         local x, y = self.body:getPosition()
  13.         love.graphics.print({{0, 1, 0}, (category .. '+' .. bitmask) or group}, x, y, nil)
  14.     end
  15.     return e
  16. end
复制代码
下面我们定义了两个类别,分别是001和010
  1. local entities = {block(400, 400, 300, 10, 'static', '001', '011', 0),
  2.                   block(400, 300, 50, 50, 'dynamic', '011', '011', 0),
  3.                   block(400, 200, 40, 40, 'dynamic', '010', '011', 0),
  4.                   block(400, 100, 30, 30, 'dynamic', '010', '011', 0)}
复制代码
修改第二个和第三个方块的位掩码
  1. local entities = {block(400, 400, 300, 10, 'static', '001', '011', 0),
  2.                   block(400, 300, 50, 50, 'dynamic', '011', '000', 0),
  3.                   block(400, 200, 40, 40, 'dynamic', '010', '001', 0),
  4.                   block(400, 100, 30, 30, 'dynamic', '010', '011', 0)}
复制代码
⭐ 组别

我们可以为各个实体设置组别,同组别将直接无视类别与位掩码的计算结果,同组别且正数总是会碰撞,同组别且负数总不会碰撞。
  1.     e.fixture:setFilterData( xx , xx , group)
  2.     -- e.fixture:setGroupIndex(group)
复制代码
考虑如下代码
  1. local entities = {block(400, 400, 300, 10, 'static', '001', '011', 0),
  2.                   block(400, 300, 50, 50, 'dynamic', '010', '001', 0),
  3.                   block(400, 200, 40, 40, 'dynamic', '010', '001', 0)}
复制代码
第二个方块跟第三个方块不会碰撞,设置组别为1
  1. local entities = {block(400, 400, 300, 10, 'static', '001', '011', 0),
  2.                   block(400, 300, 50, 50, 'dynamic', '010', '001', 1),
  3.                   block(400, 200, 40, 40, 'dynamic', '010', '001', 1)}
复制代码
再考虑如下代码,
  1. local entities = {block(400, 400, 300, 10, 'static', '001', '011', 0),
  2.                   block(400, 300, 50, 50, 'dynamic', '010', '011', 1),
  3.                   block(400, 200, 40, 40, 'dynamic', '010', '011', 1)}
复制代码
第二个方块跟第三个方块会碰撞,将组别设置为-1,即使算出来要发生碰撞,由于相同组且是负数,永远也不会碰撞
  1. local entities = {block(400, 400, 300, 10, 'static', '001', '011', 0),
  2.                   block(400, 300, 50, 50, 'dynamic', '010', '011', -1),
  3.                   block(400, 200, 40, 40, 'dynamic', '010', '011', -1)}
复制代码

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

金歌

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表