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

Python Ursina中平滑旋转功能失效问题求助

Python Ursina中平滑旋转功能失效问题求助

兄弟,我看完你的代码,发现几个关键问题导致角色完全不转,咱们一步步拆解解决:

核心问题1:混淆了方向向量和旋转角度

你现在用target_rot = (target_position - self.position)得到的是方向向量,但self.rotation.y需要的是欧拉角(角度值),这俩完全不是一个概念!你直接拿向量的y分量来算旋转增量,逻辑根本不对,自然转不起来。

正确的做法是把方向向量转换成y轴的旋转角度——Ursina里y轴是向上的,水平旋转由x和z轴的向量决定,咱们用math.atan2来计算对应的角度:

import math
target_dir = target_position - self.position
# 把向量转换成y轴旋转角度(转成度数,因为Ursina的rotation用度数)
target_rot_y = math.degrees(math.atan2(target_dir.x, target_dir.z))

核心问题2:浮点数精度导致判断永远不触发

你用if self.rotation == target_rot:来判断是否到达目标,这里有两个致命问题:

  • 类型不匹配:self.rotation是欧拉角对象,target_rot是方向向量,永远不可能相等
  • 就算都是角度,浮点数累加的精度问题也会让这个条件几乎永远不成立,导致self.pass_一直是True,函数再也不会重新计算目标值,相当于只执行了一次初始化就停了

解决办法是用角度差值的阈值来判断,比如当当前角度和目标角度的差小于1度时,就认为到达目标:

angle_diff = target_rot_y - self.rotation.y
# 处理角度绕圈的问题(比如从350°转到10°,应该转20°而不是-340°)
angle_diff = (angle_diff + 180) % 360 - 180

# 当差值小于1度时,认为到达目标
if abs(angle_diff) < 1:
    self.rotation.y = target_rot_y  # 直接修正到目标角度,避免抖动
    self.pass_ = False
    return True

额外问题:全局变量容易冲突

你用了global target_rot,如果有多个实体调用这个函数,它们会共用同一个目标值,互相干扰。应该改成实例变量,比如self.target_rot_y,每个对象自己存自己的目标角度。


修正后的完整代码

先在你的Entity子类的__init__里初始化必要的实例变量:

from ursina import Entity, time
import math

class YourEntity(Entity):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.pass_ = False  # 标记是否已经设置了目标角度
        self.target_rot_y = 0  # 存储目标y轴旋转角度

然后是修正后的smooth_look_at函数:

def smooth_look_at(self, target_position, speed=10):
    if not self.pass_:
        # 计算方向向量并转换成目标角度
        target_dir = target_position - self.position
        self.target_rot_y = math.degrees(math.atan2(target_dir.x, target_dir.z))
        self.pass_ = True

    # 计算角度差值并处理绕圈问题
    angle_diff = self.target_rot_y - self.rotation.y
    angle_diff = (angle_diff + 180) % 360 - 180

    # 平滑旋转:用差值乘以速度和dt,保证帧率无关
    self.rotation.y += angle_diff * speed * time.dt

    # 判断是否到达目标
    if abs(angle_diff) < 1:
        self.rotation.y = self.target_rot_y
        self.pass_ = False
        return True
    return False

为什么这样改?

  1. 用atan2正确计算了水平旋转角度,匹配Ursina的坐标系规则
  2. 处理了角度绕圈的问题,角色会选择最短路径旋转
  3. 用阈值判断代替直接相等,避免浮点数精度坑
  4. 用angle_diff * speed * time.dt来旋转,速度不受帧率影响,旋转更平滑
  5. 最后直接设置到目标角度,防止角色在目标附近微小抖动

这样你的角色应该就能正常平滑旋转了,试试吧!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.13 20:12:58