目录
物理
移动时发生碰撞,为什么会抖动?
因为物理系统使用的是场景的简化副本,这个副本中仅包含碰撞体。这个物理场景可以使物理系统的计算更简化。
物理系统是如何工作的?
-
每当带有刚体的游戏对象在场景中移动时,在物理场景中移动自己的游戏对象副本。
-
施加作用力并计算碰撞。
-
将场景中的游戏对象移动到物理场景中计算出的新位置。
在此示例中,这会导致以下事件:
-
你在帧更新(Update)过程中移动角色到位置A。
-
物理系统将自己的游戏对象副本移到位置A。
-
物理系统发现:角色碰撞体现在位于另一个碰撞体(此处为箱子)内,然后将角色碰撞体移回以便不再位于箱子内(重新获得位置B)。
-
物理系统将 角色游戏对象 同步到位置B。
你不断移动 Ruby 到箱子内,而物理系统则将她移回。你要求代码执行的操作与物理系统执行的操作之间的这种冲突就会导致发生抖动。
(关于刚体的更多内容:)2D刚体与碰撞https://blog.csdn.net/yjy99yjy999/article/details/112839298
如何解决抖动?读取输入和移动的正确示范
在类中添加两个浮点变量,以便在 Update 函数内存储当前的水平和垂直输入数据。
public class RubyController : MonoBehaviour
{
Rigidbody2D rigidbody2d;
float horizontal;
float vertical;
void Start()
{
rigidbody2d = GetComponent<Rigidbody2D>();
}
void Update()
{
horizontal = Input.GetAxis("Horizontal");
vertical = Input.GetAxis("Vertical");
}
void FixedUpdate()
{
Vector2 position = rigidbody2d.position;
position.x = position.x + 3.0f * horizontal * Time.deltaTime;
position.y = position.y + 3.0f * vertical * Time.deltaTime;
rigidbody2d.MovePosition(position);
}
}
- Update 函数——每次游戏计算新图像时都会调用 Update,问题是调用速度不确定。
- FixedUpdate 函数——定期进行更新(例如,每隔 16ms)。
- 但是,不应该在 Fixedupdate 函数中读取用户输入。FixedUpdate 不会持续运行,因此有可能会错过用户输入。
对象暂停移动时,检测不到碰撞
解决方法:在 Rigidbody 组件中将 Sleeping Mode 设置为 Never Sleep。
为了优化资源,物理系统在刚体停止移动时会停止计算刚体的碰撞;此时刚体进入“睡眠状态”。但在你这个情况中,你希望始终进行计算,因为即使在 Ruby 停止移动时也需要检测她是否受到伤害,因此你要指示刚体永远不要进入睡眠状态。
只有Collider2D,没有Rigidbody2D的箱子
这是正确的。这是因为不需要通过物理来移动箱子,只需要一个碰撞体即可,无论有没有刚体,游戏对象都将与箱子交互。
使用复合碰撞体(制作地形)
- 父对象添加 Composite Collider 2D 组件
- 父对象添加 Rigidbody2D 组件,Rigidbody Body Type 属性设置为 Static。(将此属性设置为 Static 将阻止你的世界移动。此外还有助于物理系统优化计算,因为它现在知道刚体不能移动。)
- 所有子对象的Collider2D ,启用 Used By Composite 复选框。
2D视觉处理
遮挡(排序问题)、轴点(Pivot)、碰撞体形状
- 排序问题:你需要让 Unity 根据游戏对象的 y 坐标来绘制游戏对象。
- Edit > Project Settings。
- 在左侧类别菜单中,单击 Graphics。
- Transparency Sort Mode 字段:此字段决定了精灵的绘制顺序。将此设置改为 Custom Axis、设置 x = 0 y = 1 z = 0
- 轴点问题:将箱子、角色的轴点放在脚下,可以更好地解决遮挡的准确性。
- 在游戏对象的 Sprite Renderer 组件上,找到 Sprite Sort Point 字段。目前,此字段设置为 Center,这意味着会使用精灵的中心点来决定这个游戏对象应该在另一个游戏对象的前面还是后面。将其改为 Pivot。
- 使用 Sprite Editor 来更改轴心,将轴心放在底部。
- 碰撞体形状:
- 为什么不把碰撞体设置成箱子的大小?那是因为你的角色需要能够走到箱子“后面”,这样看起来更合理(否则箱子在地面上看起来是扁平的)。
- 碰撞体仅覆盖了 Ruby 的双腿,因为角色在碰撞之前需要能够稍微移到游戏对象的上方,这有助于使游戏更真实可信。
动画
混合树(Blend Tree)
脚本
比较浮点数
使用 Mathf.Approximately 而不是 ==,这是因为计算机存储浮点数的方式意味着精度会有很小的损失。
检查move.x 或move.y 是否不等于0:
if(!Mathf.Approximately(move.x, 0.0f) || !Mathf.Approximately(move.y, 0.0f))
在Start函数中获取组件的问题
如果对象A是由其他对象的脚本实例化创建,紧接着调用对象A的某个函数, 报告了空引用的错误,需要检查Null的字段是否在对象A的 Start() 中赋值的。
这是因为在你创建对象时 Unity 不会运行 Start,而是在下一帧才开始运行。因此,要解决此问题,请在Awake()中为该字段赋值。
与 Start 刚好相反,在创建对象时(调用 Instantiate 时)就会立即调用 Awake,因此,在调用任何函数之前已正确初始化需要赋值的字段。
UI
Canvas 的 Render Mode
-
Screen Space - Overlay:这是默认模式,可以让 Unity 在始终在游戏的上层绘制 UI。大多数应用程序使用此模式,因为它们希望 UI 始终位于最上层以便提供所有信息。
-
Screen Space - Camera:这种模式在与摄像机对齐的平面上绘制 UI。平面的大小确定为始终填充整个屏幕,这样你就可以四处移动摄像机,并且平面将随摄像机一起移动,从而显示与 Overlay 图形相同的形状。
-
但是,由于平面是在世界中绘制的,而不是在屏幕上层绘制的,因此世界中的对象可以绘制在 UI 的上层。
-
-
World Space:这种模式可在世界中的任何位置绘制平面。例如,你可以将此平面用作游戏中的计算机屏幕,或者用作墙壁,或者放在角色的上层。这在 3D 游戏中更有用,因为 UI 会随着距离变小。
Canvas Scaler
- Constant Size(Pixel 或 Physical):绝对尺寸,不随屏幕大小而变化。
- 无论屏幕大小或形状如何,UI 均保持大小不变。这样可以使 UI 在任何屏幕上都能看清楚,但在较小的屏幕上可能会被 UI 占据很大的空间,而且如果屏幕太小,元素也不能重叠。
- Scale With Screen Size:随屏幕大小缩放,保证完全相同的画面效果。
- 让 UI 缩放取决于你设置为 Reference Resolution 的屏幕大小。这样无论屏幕大小如何,UI 始终覆盖屏幕上的相同区域。