如何获取Ursina Entity所有顶点坐标并实现均匀重力系统?
问题:自定义Ursina重力系统与顶点获取问题
用户提供的代码:
from ursina import * bodies = set() G = 0.002 app = Ursina(render_mode='colliders') ground = Entity(model='plane', color=rgb(230,230,230), scale=10, collider='mesh') ground.collider.visible = True cube = Entity(model='cube', color=rgb(100, 100, 100), scale=2, position=Vec3(0, 5,0), collider='mesh', rotation=Vec3(45, 45, 45)) cube.collider.visible = True bodies.add((cube, 0)) def update(): global bodies new_bodies = set() for body, v in bodies: hit_info = raycast(Vec3(cube.X, cube.Y, cube.Z) , Vec3(0, -1, 0), ignore=(body,), distance=body.scale.y, debug=True) if not hit_info.hit: v += G body.y -= v else: v = 0 new_bodies.add((body, v)) bodies = new_bodies EditorCamera() DirectionalLight(parent=Entity(), y=2, z=3, shadows=True, rotation=(45, -45, 45)) app.run()
需求与问题:
我希望在update函数中实现均匀作用于物体的重力系统,而非Ursina内置FirstPersonController的重力效果。我想到的方法是从每个顶点向下进行射线检测(以适配非立方体物体),但尝试使用body.model.vertices获取顶点时出现错误:AttributeError: 'panda3d.core.NodePath' object has no attribute 'vertices'。
请问是否有获取Ursina Entity所有顶点坐标的方法?若没有,是否有更简便的重力实现方式?现有方法会导致立方体以顶点着地的问题,实际应平稳落至地面。
获取Ursina Entity顶点坐标的方法
Ursina的Entity.model加载后是Panda3D的NodePath对象,无法直接通过vertices属性访问顶点数据,正确的获取方式是通过模型的mesh属性:
- 对于内置模型(如
cube、plane)或自定义模型,可通过body.model.mesh.vertices获取局部空间下的原始顶点坐标。 - 若要用于世界空间的射线检测,需要将局部顶点转换为世界坐标:
# 获取局部顶点并转换为世界坐标 local_vertices = body.model.mesh.vertices world_vertices = [body.world_position + body.world_rotation * Vec3(v) for v in local_vertices]
注意:逐顶点射线检测性能开销较高,复杂模型不建议使用这种方式实现重力。
更简便的重力实现方式(解决顶点着地问题)
现有代码的核心问题是仅从物体中心发射射线,旋转后的立方体顶点先接触地面但中心仍悬空,导致顶点卡地。以下两种方案更高效且能解决该问题:
方案1:基于碰撞盒多点射线检测
针对带碰撞盒的物体,从碰撞盒底部的多个关键点(如四个角和中心)发射射线,只要有一个射线检测到地面,就判定物体着地,并调整位置避免穿透:
from ursina import * bodies = set() G = 0.002 app = Ursina(render_mode='colliders') ground = Entity(model='plane', color=rgb(230,230,230), scale=10, collider='mesh') ground.collider.visible = True cube = Entity(model='cube', color=rgb(100, 100, 100), scale=2, position=Vec3(0, 5,0), collider='mesh', rotation=Vec3(45, 45, 45)) cube.collider.visible = True bodies.add((cube, 0)) def update(): global bodies new_bodies = set() for body, v in bodies: # 获取碰撞盒的局部边界范围 bounds = body.collider.bounds # 定义碰撞盒底部的多个检测点(局部坐标) bottom_local_points = [ Vec3(bounds[0][0], bounds[1][0], bounds[2][0]), # 左下后 Vec3(bounds[0][1], bounds[1][0], bounds[2][0]), # 右下后 Vec3(bounds[0][0], bounds[1][0], bounds[2][1]), # 左下前 Vec3(bounds[0][1], bounds[1][0], bounds[2][1]), # 右下前 Vec3((bounds[0][0]+bounds[0][1])/2, bounds[1][0], (bounds[2][0]+bounds[2][1])/2) # 底部中心 ] # 转换为世界坐标 bottom_world_points = [body.world_position + body.world_rotation * p for p in bottom_local_points] on_ground = False min_ground_distance = float('inf') # 遍历所有底部点检测地面 for point in bottom_world_points: hit_info = raycast(point, Vec3(0, -1, 0), ignore=(body,), distance=0.1, debug=False) if hit_info.hit: on_ground = True if hit_info.distance < min_ground_distance: min_ground_distance = hit_info.distance if not on_ground: v += G body.y -= v else: # 调整物体位置至刚好接触地面 body.y += min_ground_distance - 0.01 # 微小偏移防止穿透 v = 0 new_bodies.add((body, v)) bodies = new_bodies EditorCamera() DirectionalLight(parent=Entity(), y=2, z=3, shadows=True, rotation=(45, -45, 45)) app.run()
方案2:使用intersects直接检测碰撞
Ursina内置的Entity.intersects()方法可快速检测物体与其他碰撞体的交集,无需手动发射射线,代码更简洁:
from ursina import * bodies = set() G = 0.002 app = Ursina(render_mode='colliders') ground = Entity(model='plane', color=rgb(230,230,230), scale=10, collider='mesh') ground.collider.visible = True cube = Entity(model='cube', color=rgb(100, 100, 100), scale=2, position=Vec3(0, 5,0), collider='mesh', rotation=Vec3(45, 45, 45)) cube.collider.visible = True bodies.add((cube, 0)) def update(): global bodies new_bodies = set() for body, v in bodies: # 先应用速度让物体下落 body.y -= v # 检测是否与地面碰撞 hit_info = body.intersects(ground) if hit_info.hit: # 回退位置避免穿透地面 body.y += hit_info.distance v = 0 else: # 未接触地面则继续加速 v += G new_bodies.add((body, v)) bodies = new_bodies EditorCamera() DirectionalLight(parent=Entity(), y=2, z=3, shadows=True, rotation=(45, -45, 45)) app.run()
这种方式自动适配各种碰撞体形状,性能更优,且能完美解决旋转物体顶点着地的问题。
内容的提问来源于stack exchange,提问作者AG-88301
相关产品推荐
相关产品推荐

