Игрок проходит сквозь стены в Panda3D — поля коллизий, созданные на основе границ сетки, кажутся игнорируемымиPython

Программы на Python
Anonymous
Игрок проходит сквозь стены в Panda3D — поля коллизий, созданные на основе границ сетки, кажутся игнорируемыми

Сообщение Anonymous »

Я создаю простой шутер от первого лица в Panda3D. Моя карта содержит низкополигональные бестекстурные сетки столкновений, имена которых начинаются с col_. Я генерирую твердые тела CollisionBox из жестких границ каждой сетки и хочу, чтобы эти блоки были «внутренними» коллайдерами для стен. У игрока есть CollisionBox, установленный как коллайдер from, и используется CollisionHandlerPusher.
Однако игрок по-прежнему может перемещаться сквозь стены. Я попробовал визуализировать коллизии и распечатать отладочную информацию; коллайдер игрока появляется в сцене, но перемещение по геометрии 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_ (это низкополигональные объекты без текстур, предназначенные исключительно для столкновений).

Вернуться в «Python»