Однако игрок по-прежнему может перемещаться сквозь стены. Я попробовал визуализировать коллизии и распечатать отладочную информацию; коллайдер игрока появляется в сцене, но перемещение по геометрии col_* не приводит к коллизиям.
Я включаю минимальный скрипт ниже (комментарии переведены на английский язык). Что я делаю не так и как это исправить, чтобы игрок блокировался сетками col_?
Код:
Код: Выделить всё
from panda3d.core import (
CollisionTraverser, CollisionHandlerPusher, CollisionNode, CollisionBox,
Point3, BitMask32, Vec3
)
from direct.showbase.ShowBase import ShowBase
from direct.task import Task
import sys
class FPSGame(ShowBase):
def __init__(self):
ShowBase.__init__(self)
self.disableMouse()
# ========================
# MAP
# ========================
self.map = self.loader.loadModel("map.glb")
self.map.reparentTo(self.render)
# ========================
# PLAYER
# ========================
self.player = self.render.attachNewNode("player")
self.player.setPos(0, 0, 2)
self.camera.reparentTo(self.player)
self.camera.setPos(0, 0, 0)
self.speed = 6
# ========================
# COLLISION
# ========================
self.cTrav = CollisionTraverser()
self.pusher = CollisionHandlerPusher()
# Player collider
playerNode = CollisionNode("playerCollider")
playerNode.addSolid(CollisionBox(Point3(0,0,1), 0.5, 0.5, 1))
playerNode.setFromCollideMask(BitMask32.bit(1))
playerNode.setIntoCollideMask(BitMask32.allOff())
self.playerCollider = self.player.attachNewNode(playerNode)
self.pusher.addCollider(self.playerCollider, self.player)
self.cTrav.addCollider(self.playerCollider, self.pusher)
# ========================
# MAP COLLISION (THIS WAS MY "FIX")
# ========================
for np in self.map.findAllMatches('**/col_*'):
bounds = np.getTightBounds()
if bounds:
min_b, max_b = bounds
center = (min_b + max_b) / 2
size = (max_b - min_b) / 2
# 🔥 FIX: ensure no zero-size
min_size = 0.1
size.x = max(size.x, min_size)
size.y = max(size.y, min_size)
size.z = max(size.z, min_size)
collNode = CollisionNode('wall')
collNode.addSolid(CollisionBox(center, size.x, size.y, size.z))
collNode.setIntoCollideMask(BitMask32.bit(1))
collNode.setFromCollideMask(BitMask32.allOff())
# NOTE: I'm attaching to render here — could this be wrong?
self.render.attachNewNode(collNode)
# ========================
# INPUT
# ========================
self.keys = {"w":0,"s":0,"a":0,"d":0}
for k in self.keys:
self.accept(k, self.setKey, [k,1])
self.accept(k+"-up", self.setKey, [k,0])
self.accept("escape", sys.exit)
# ========================
# MOUSE
# ========================
self.centerX = self.win.getXSize()//2
self.centerY = self.win.getYSize()//2
self.win.movePointer(0, self.centerX, self.centerY)
# ========================
# TASK
# ========================
self.taskMgr.add(self.update, "update")
def setKey(self, key, val):
self.keys[key] = val
def update(self, task):
dt = globalClock.getDt()
# ===== MOUSE =====
if self.mouseWatcherNode.hasMouse():
md = self.win.getPointer(0)
dx = md.getX() - self.centerX
dy = md.getY() - self.centerY
self.player.setH(self.player.getH() - dx * 0.1)
self.camera.setP(self.camera.getP() - dy * 0.1)
self.win.movePointer(0, self.centerX, self.centerY)
# ===== MOVEMENT =====
dir = Vec3(0,0,0)
if self.keys["w"]:
dir += self.player.getQuat().getForward()
if self.keys["s"]:
dir -= self.player.getQuat().getForward()
if self.keys["a"]:
dir -= self.player.getQuat().getRight()
if self.keys["d"]:
dir += self.player.getQuat().getRight()
dir.setZ(0)
if dir.length() > 0:
dir.normalize()
# Using setFluidPos with an absolute position — could this conflict with pusher?
self.player.setFluidPos(self.player.getPos() + dir * self.speed * dt)
return Task.cont
game = FPSGame()
game.run()
- Я экспортировал сетки столкновений из Blender как низкополигональные бестекстурные сетки с именами col_wall01, col_floor и т. д. Они не имеют текстур и предназначены для невидимой геометрии столкновений.
- Я вычисляю getTightBounds() для каждой col_* NodePath, создайте CollisionBox, используя эти границы, затем установите этот CollisionNode в качестве коллайдера into с помощью BitMask32.bit(1).
- Узел столкновения игроков использует setFromCollideMask(BitMask32.bit(1)).
- Я включил визуализатор столкновений (он показывает поля столкновений), а отладочные отпечатки показывают центр и положение коллайдера игрока, но проход через стены по-прежнему возможен.
- Убедился, что маска выхода игрока равна маске входа стен (оба используют bit(1)).
- Зафиксированы половинные размеры коллайдера, чтобы избежать блоков нулевого размера.
- Движение переключено на относительное () в другом тестовом скрипте.
Код: Выделить всё
setPos(self.player, ...) - Использовал self.cTrav.showCollisions(self.render) и распечатывал позиции коллайдера.
- Почему игрок может проходить сквозь стены, даже если маски совпадают и поля столкновений существует?
- Неправильно ли прикрепить CollisionNode к self.render после вычисления границ с помощью np.getTightBounds() — следует ли мне прикрепить к сетке NodePath () вместо этого?
Код: Выделить всё
np.attachNewNode(collNode) - Есть ли проблемы с использованием setFluidPos(self.player.getPos() + ...) вместе с CollisionHandlerPusher?
- Есть ли предложения по надежным шагам отладки, чтобы определить, обнаружены ли конфликты, но не разрешены, или не обнаружены вообще?
- Я могу предоставить вывод отладки консоли и снимки экрана визуализатора столкновений, если это полезно.
- Я использую Panda3D 1.10.x (Windows). Карта экспортирована из Blender как GLB. Узлы сетки столкновений — это отдельные объекты с именами, начинающимися с col_ (это низкополигональные объекты без текстур, предназначенные исключительно для столкновений).