You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ursina引擎中如何禁用远处实体以降低游戏卡顿?

Ursina引擎中如何禁用远处实体以降低游戏卡顿?

嘿,我完全懂你这种挫败感——明明方块总数算下来才1875个(25×25×3),却已经出现帧率问题,而且还得保留每个方块的独立性(毕竟MC克隆的核心就是可破坏/交互的单个方块),不能随便合并成大网格,确实有点难搞。针对你试过的方法,我给你几个优化思路:

1. 优化距离检测效率,别再遍历所有方块

你之前的全量遍历+高频检测是卡顿的核心原因之一——哪怕每60帧跑一次,遍历1900个方块的计算量也不小。不如参考MC的区块思路,把你的25×25世界拆成小区块(比如5×5的区块,每个区块管理25个方块),这样你只需要先判断哪些区块在玩家的有效范围内,再处理这些区块里的方块,遍历的数量会大幅减少。

举个代码例子:

from ursina import *

# 先定义区块类,管理一组方块
class BlockChunk(Entity):
    def __init__(self, position=(0,0,0), **kwargs):
        super().__init__(position=position, **kwargs)
        self.blocks = []  # 存储区块内的所有方块

# 初始化世界时,把方块分配到对应区块
chunks = {}
for x in range(25):
    for z in range(25):
        chunk_pos = (x//5 *5, 0, z//5 *5)  # 区块的起始坐标
        if chunk_pos not in chunks:
            chunks[chunk_pos] = BlockChunk(position=chunk_pos)
        # 创建方块并加入对应区块
        block = Entity(parent=chunks[chunk_pos], position=(x, 0, z), model='cube')
        chunks[chunk_pos].blocks.append(block)

# 然后只在玩家移动时(或者低频检测)更新区块状态
def update():
    # 每10帧检测一次,减少频率
    if not frame_count % 10:
        player_pos = player.position
        # 遍历所有区块,判断是否在玩家10单位范围内
        for chunk_pos, chunk in chunks.items():
            # 用平方距离代替欧几里得距离,避免开根号,计算更快
            distance_sq = (player_pos.x - chunk_pos.x)**2 + (player_pos.z - chunk_pos.z)**2
            if distance_sq > 100:  # 10的平方
                chunk.enabled = False  # 禁用整个区块,包括所有子方块
            else:
                chunk.enabled = True

这样一来,你不需要逐个处理每个方块,而是直接控制整个区块的启用/禁用,效率会高很多,而且检测次数也少了。

2. 确保禁用操作真正停止所有资源消耗

你说禁用方块后帧率没提升,可能是因为block.disable()只是隐藏了渲染,但某些方块的组件(比如碰撞检测、自定义update脚本)还在后台运行。试试在禁用时额外关闭这些开销:

# 如果是单个方块处理,除了disable,还要关闭碰撞和自定义脚本
def toggle_block(block, enable):
    block.enabled = enable
    block.collision = enable  # 禁用碰撞检测,减少物理开销
    # 如果你的方块有自定义的update函数,也要手动暂停
    if hasattr(block, 'custom_update'):
        block.custom_update.enabled = enable

Ursina里的enabled=False会禁用实体的所有组件,但如果你给方块加了额外的独立脚本,可能需要单独处理。另外,也可以用block.visible = False只隐藏渲染,但保留碰撞,不过如果不需要交互的话,直接禁用整个实体更彻底。

3. 别只靠相机裁剪面,要结合实体禁用

你设置的camera.clip_plane_far = 10只是让远处的方块不渲染,但这些方块依然存在于场景中,会占用内存、参与物理计算(如果有的话),甚至可能在后台执行脚本。所以裁剪面只能作为辅助,必须配合实体禁用才能真正减少资源占用。

4. 补充:如果还是有卡顿,试试批量渲染优化

虽然你不想合并网格,但可以给远处的区块用简化网格(比如把整个区块合并成一个大立方体),同时保留近处区块的单个方块。这样既保证了近处的交互性,又减少了远处的渲染开销。比如:

# 给区块添加简化网格的逻辑
class BlockChunk(Entity):
    def __init__(self, position=(0,0,0), **kwargs):
        super().__init__(position=position, **kwargs)
        self.blocks = []
        self.simplified_mesh = None

    def create_simplified_mesh(self):
        # 把区块内的方块合并成一个网格(Ursina里可以用Mesh.combine)
        self.simplified_mesh = Entity(parent=self, model=Mesh.combine([b.model for b in self.blocks]), color=color.gray)
        self.simplified_mesh.enabled = False

# 然后在检测区块距离时,切换显示简化网格还是单个方块
def update():
    if not frame_count % 10:
        player_pos = player.position
        for chunk_pos, chunk in chunks.items():
            distance_sq = (player_pos.x - chunk_pos.x)**2 + (player_pos.z - chunk_pos.z)**2
            if distance_sq > 100 and distance_sq <= 200:  # 中等距离显示简化网格
                chunk.enabled = False
                chunk.simplified_mesh.enabled = True
            elif distance_sq > 200:  # 超远距离直接隐藏
                chunk.enabled = False
                chunk.simplified_mesh.enabled = False
            else:  # 近距离显示单个方块
                chunk.enabled = True
                chunk.simplified_mesh.enabled = False

这样既解决了帧率问题,又保留了核心的方块交互功能。

最后再提醒一下:测试的时候打开Ursina的性能面板(按F1),看看是CPU还是GPU瓶颈——如果是CPU占满,那优化检测逻辑和实体禁用就对了;如果是GPU瓶颈,那简化网格或者降低渲染分辨率会更有效。

备注:内容来源于stack exchange,提问作者LimeSpeedCrystal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 11:14:29