
当将 Ursina 的 on_click 回调函数定义在嵌套作用域(如 runner() 函数内部)时,若回调中使用 global nav 但 nav 实际在局部作用域中初始化,会导致变量引用错位,on_click 表面无响应。根本原因是 Python 作用域规则使 global 声明无法绑定到外层函数内的局部变量。
当将 ursina 的 `on_click` 回调函数定义在嵌套作用域(如 `runner()` 函数内部)时,若回调中使用 `global nav` 但 `nav` 实际在局部作用域中初始化,会导致变量引用错位,`on_click` 表面无响应。根本原因是 python 作用域规则使 `global` 声明无法绑定到外层函数内的局部变量。
在 Ursina 中,on_click 是一个事件钩子,它会在鼠标点击实体时异步触发,其执行上下文独立于主游戏循环。当你把 nav = [None, 0, 0] 定义在 runner() 函数内部时,它成为一个局部变量;而 click() 函数中的 global nav 声明则试图访问模块级(即全局作用域)的 nav —— 但该变量并不存在,或已被其他同名局部变量遮蔽。结果是:click() 执行时实际操作的是未定义/旧作用域的 nav,导致状态未更新,后续移动逻辑(如 nav[1] == 1)始终为假,on_click “看似不工作”。
✅ 正确做法:将共享状态变量声明在模块顶层(全局作用域),并在所有需要读写的函数中显式声明 global:
from ursina import *
import math
# ✅ 正确:nav 在模块顶层定义 → 全局可访问
nav = [None, 0, 0]
def click():
global nav
# ✅ 现在 global nav 能正确指向顶层 nav
if mouse.hovered_entity and hasattr(mouse.hovered_entity, 'color') and mouse.hovered_entity.color == color.green:
nav = [
(mouse.hovered_entity.x,
mouse.hovered_entity.y + mouse.hovered_entity.scale_y / 2,
mouse.hovered_entity.z),
1, # 启动移动
0 # 重置标志位
]
def normalize_direction_vector(x_a, y_a, x_b, y_b):
global nav
dx = x_b - x_a
dy = y_b - y_a
magnitude = math.sqrt(dx**2 + dy**2)
if magnitude <p>? <strong>关键注意事项</strong>:</p>
-
不要在函数内重新赋值
nav = [...]:这会创建局部变量,使global nav失效; -
on_click必须接收无参函数对象:写on_click=click,而非on_click=click(); -
确保实体有有效
collider:collider='box'是必需的,否则射线检测失败; -
悬停/点击前校验
mouse.hovered_entity:避免AttributeError(如示例中增加if mouse.hovered_entity and ...); -
推荐使用
time.dt进行时间缩放:替代固定数值旋转/移动,提升跨设备一致性。
通过将状态变量置于模块级并统一 global 声明,即可确保 on_click 回调与主循环共享同一份数据,彻底解决“点击无响应”问题。










