游戏建筑系统中适配旋转的部件位置限制函数实现求助
解决旋转部件在底板内的位置限制问题
要实现旋转状态下仍能将部件限制在底板范围内,核心是把部件的边界投影到底板的局部坐标系,这样就能统一用底板的轴向来计算限制范围,不受部件旋转影响。
实现步骤
- 将鼠标命中点、部件的轴向向量转换为底板的局部坐标空间,让所有计算基于底板坐标系展开
- 计算部件旋转后,在底板X/Z轴方向上的最大投影尺寸(部件旋转后自身轴向与底板轴向存在夹角,直接用原始尺寸会导致边界判断错误)
- 根据底板尺寸和部件投影尺寸,计算命中点在底板局部坐标系下的允许范围,执行clamp限制
- 将限制后的局部坐标转换回世界坐标系,作为最终的部件位置
修改后的代码
function clamp(hit: Vector3, obj: Model, platePart: BasePart) local part = obj.PrimaryPart if not part then return CFrame.new() end -- 获取底板的坐标系转换关系 local plateCFrame = platePart.CFrame local plateSizeHalf = platePart.Size / 2 local worldToPlate = plateCFrame:Inverse() -- 将命中点转换到底板局部空间 local hitLocal = worldToPlate * hit -- 计算部件在底板局部坐标系下的轴向投影尺寸 local partCFrame = part.CFrame local partSizeHalf = part.Size / 2 -- 把部件的轴向向量转到底板局部空间 local partRightLocal = worldToPlate:VectorToObjectSpace(partCFrame.RightVector) local partForwardLocal = worldToPlate:VectorToObjectSpace(partCFrame.LookVector) -- 计算部件在底板X/Z轴上的总延伸长度(考虑旋转后的投影) local projX = math.abs(partRightLocal.X * partSizeHalf.X) + math.abs(partForwardLocal.X * partSizeHalf.Z) local projZ = math.abs(partRightLocal.Z * partSizeHalf.X) + math.abs(partForwardLocal.Z * partSizeHalf.Z) -- 计算底板局部空间内的命中点允许范围 local minX = -plateSizeHalf.X + projX local maxX = plateSizeHalf.X - projX local minZ = -plateSizeHalf.Z + projZ local maxZ = plateSizeHalf.Z - projZ -- 对命中点进行范围限制 local clampedLocalX = math.clamp(hitLocal.X, minX, maxX) local clampedLocalZ = math.clamp(hitLocal.Z, minZ, maxZ) local clampedLocal = Vector3.new(clampedLocalX, hitLocal.Y, clampedLocalZ) -- 转换回世界坐标系,返回带部件旋转的最终CFrame local clampedWorldPos = plateCFrame * clampedLocal return CFrame.new(clampedWorldPos) * partCFrame.Rotation end
代码说明
- 坐标系转换:通过
worldToPlate将世界空间的点和向量映射到底板局部空间,彻底避开部件旋转对边界判断的干扰 - 投影尺寸计算:部件旋转后,自身轴向在底板轴向上的投影长度决定了它在该方向的实际延伸范围,相加后得到的总长度是判断边界的关键依据
- Clamp处理:用底板半尺寸减去部件投影延伸长度,得到命中点的安全范围,限制后再转回世界空间,确保部件无论怎么转都不会超出底板边界
内容的提问来源于stack exchange,提问作者rver
相关产品推荐
相关产品推荐

