左右翻转的本质

2D Sprite 默认位于 XY 平面并面向相机。左右翻转的目标是让画面的 X 方向反转,而不是让角色在 XY 平面中旋转。

facingDir 与 facingRight:逻辑朝向

当前代码把两个朝向成员写成:
facingDir 在 1 和 -1 之间切换,表达可参与计算的方向符号。当前 PlayerDashState 使用 player.dashSpeed * player.facingDir 决定向右或向左冲刺。
facingRight 在 true 和 false 之间切换,表达 Player 内部判断用的“当前是否朝右”。
这两个成员保存逻辑朝向;真正改变画面的是后面的翻转操作。逻辑状态、速度方向和视觉状态必须保持一致。

facingDir 为什么使用只读属性

facingDir 是自动属性,不是普通 public 字段:
public get 允许 PlayerDashState 等外部状态读取 player.facingDir;private set 禁止外部状态直接赋值,只有 Player 内部的 Flip 可以修改它。这样可以防止其他状态只改 facingDir,却没有同步 facingRight 和 Transform。
这里 facingDir 管数学方向,facingRight 管内部判断,Transform 管视觉翻转。字段、属性和 Unity 序列化的通用原理参见
Unity 引擎学习笔记2
。

Transform.Rotate:绕 Y 轴实现镜像

transform.Rotate(0f, 180f, 0f) 在当前旋转基础上绕 Y 轴旋转 180°。
对于正面朝向相机的 Sprite,Y 轴旋转会让局部 X 轴反向,所以从相机看来是左右镜像。
Rotate 是相对旋转方法,每次调用都会在现有角度上继续增加 180°。transform.rotation 则是保存完整旋转结果的 Quaternion 属性。

Transform.rotation 与 Rigidbody2D.rotation

transform.rotation:
  • 类型是 Quaternion。
  • 能表达 X、Y、Z 三个轴的完整旋转。
  • 绕 Y 轴 180°可以造成 Sprite 左右镜像。
Rigidbody2D.rotation:
  • 类型是 float,单位为度。
  • 只表示绕 Z 轴的 2D 物理旋转。
  • Z 轴旋转发生在屏幕平面内,180°会把角色倒转。
因此 Rigidbody2D.rotation 不是左右镜像接口。只有角色的 Collider 和物理身体确实需要在 XY 平面中转动时,才使用它或 MoveRotation。

SpriteRenderer.flipX:只翻转图片

flipX 在 SpriteRenderer 内部反转 Sprite 的 X 方向,只改变渲染结果,不旋转 Rigidbody2D、Collider2D 和 Transform 坐标系。
只有角色图片需要左右翻转时,flipX 的职责最明确。

Visual 子节点翻转:翻转一组视觉对象

把 SpriteRenderer 和需要一起镜像的视觉挂点放在 Visual 下,只旋转 Visual,可以让整组画面一起翻转,同时保持 PlayerRoot 的 Rigidbody2D 和 Collider2D 不变。
直接指定朝右为 0°、朝左为 180°,表达的是目标状态;连续调用 Rotate 表达的是在当前状态上继续旋转。

三种接口的职责

  • SpriteRenderer.flipX:镜像一张 Sprite 的渲染结果。
  • Visual.localRotation:镜像整个视觉子层级。
  • Rigidbody2D.rotation / MoveRotation:真实旋转 2D 物理身体和 Collider。
左右朝向首先是视觉问题。只有物理形状也需要跟着转动时,它才是 Rigidbody2D 的旋转问题。