Unity性能优化——Rigidbody2D详解

在移动或旋转一个物体时,往往会直接使用Transform来执行这些操作。比如使用如下代码来移动一个GameObject:

	void Update(){
		this.transform.Translate (Vector3.left * speed * Time.deltaTime);
	}

这种方法对于不具物理特性的GameObject来说,是可行的。但是一旦GameObject上附带有Rigidbody2D,这种方式就会带来性能的损失。

Rigidbody2D

先看看Rigidbody2D,先引用官方文档对Rigidbody2D工作原理的说明:

How a Rigidbody 2D works

Usually, the Unity Editor’s Transform component defines how a GameObject (and its child GameObjects) is positioned, rotated and scaled within the Scene. When it is changed, it updates other components, which may update things like where they render or where colliders are positioned. The 2D physics engine is able to move colliders and make them interact with each other, so a method is required for the physics engine to communicate this movement of colliders back to the Transform components. This movement and connection with colliders is what a Rigidbody 2D component is for.

The Rigidbody 2D component overrides the Transform and updates it to a position/rotation defined by the Rigidbody 2D. Note that while you can still override the Rigidbody 2D by modifying the Transform component yourself (because Unity exposes all properties on all components), doing so will cause problems such as GameObjects passing through or into each other, and unpredictable movement.

Any Collider 2D component added to the same GameObject or child GameObject is implicitly attached to that Rigidbody 2D. When a Collider 2D is attached to the Rigidbody 2D, it moves with it. A Collider 2D should never be moved directly using the Transform or any collider offset; the Rigidbody 2D should be moved instead. This offers the best performance and ensures correct collision detection. Collider 2Ds attached to the same Rigidbody 2D won’t collide with each other. This means you can create a set of colliders that act effectively as a single compound collider, all moving and rotating in sync with the Rigidbody 2D.

When designing a Scene, you are free to use a default Rigidbody 2D and start attaching colliders. These colliders allow any other colliders attached to different Rigidbody 2Ds to collide with each other.

Tip
Adding a Rigidbody 2D allows a sprite to move in a physically convincing way by applying forces from the scripting API. When the appropriate collider component is also attached to the sprite GameObject, it is affected by collisions with other moving GameObjects. Using physics simplifies many common gameplay mechanics and allows for realistic behavior with minimal coding.

重点已经用粗体标出来了。为英文不好的朋友大致翻译一下:

所有被附加在同一个具有Rigidbody2D组件的GameObject、以及其子GameObject上的Collider2D,都会被隐式地附加到该Rigidbody2D上。当Collider2D被附加到Rigidbody2D上后,它将随着Rigidbody2D移动。一个Collider2D不应该直接使用Transform或者其offset属性来移动它,而是应该使用Rigidbody2D的移动代替之。这样会得到最好的表现和正确的碰撞检测。被附加在同一个Rigidbody2D的Collider2D之间不会发生碰撞。所以我们可以创建一个包含多个Collider2D的复合Collider2D,这样所有的Collider2D的移动、旋转都将与Rigidbody2D的运动同步。

那么针对之前使用Transform移动的方式,我们应该改为如下方式:

	void FixedUpdate()
	{
		rigidbody2D.MovePosition (rigidbody2D.position + Vector2.left * speed * Time.fixedDeltaTime);
	}

或者如下方式:

	void Start () {
		rigidbody2D.velocity = Vector2.left * speed;
	}

注意前一种方式每一物理帧设置一次Rigidbody2D的位置,看起来Rigidbody2D在以一定速度移动,但实际上它的velocity依旧是零。

后一种方式则不存在上面的问题,设置好velocity后,物理系统会自动对它进行模拟,代码看起来也更简洁。

再看看Rigidbody2D的Body Type属性:

Unity性能优化——Rigidbody2D详解_第1张图片

它有三个可选项:Dynamic(动态,默认)、Kinematic(运动学)、Static(静态)。

这三种类型确定了不同的运动行为(移动和旋转)和碰撞方式。

注意虽然Rigidbody2D描述了与其他物体碰撞,但是如果没有附加Collider2D组件,它仍然是不能检测到碰撞的。

关于Body Type,这个属性不要在运行时去修改它。原因还是引用官方文档的说明:

Changing the Body Type of a Rigidbody 2D can be a tricky process. When a Body Type changes, various mass-related internal properties are recalculated immediately, and all existing contacts for the Collider 2Ds attached to the Rigidbody 2D need to be re-evaluated during the GameObject’s next FixedUpdate. Depending on how many contacts and Collider 2Ds are attached to the body, changing the Body Type can cause variations in performance.

粗体部分是重点,意思就是运行时去改变此属性会引起不同的表现。具体什么表现,就是前面说的会立即引发一系列的重计算,这会是性能的额外开销。

再看看三种不同的Body Type究竟确定了哪些不同的运动行为和碰撞方式。

Body Type —— Dynamic

A Dynamic Rigidbody 2D is designed to move under simulation. It has the full set of properties available to it such as finite mass and drag, and is affected by gravity and forces. A Dynamic body will collide with every other body type, and is the most interactive of body types. This is the default body type for a Rigidbody 2D, because it is the most common body type for things that need to move. It’s also the most performance-expensive body type, because of its dynamic nature and interactivity with everything around it. All Rigidbody 2D properties are available with this body type.

Do not use the Transform component to set the position or rotation of a Dynamic Rigidbody 2D. The simulation repositions a Dynamic Rigidbody 2D according to its velocity; you can change this directly via forces applied to it by scripts, or indirectly via collisions and gravity.

Dynamic Rigidbody2D被设计用来制作在物理模拟下会移动的物体。它会与所有类型的Rigidbody2D进行碰撞,是最常用的Rigidbody2D类型、默认的类型,同时也是最耗费性能的类型。

文档中粗体部分的意思就是千万不要使用Transform组件来设置Dynamic Rigidbody2D的position和rotation。

如果想要移动或旋转它,可以使用上面提到的方式,通过Rigidbody2D的接口来完成。

Body Type —— Kinematic

A Kinematic Rigidbody 2D is designed to move under simulation, but only under very explicit user control. While a Dynamic Rigidbody 2D is affected by gravity and forces, a Kinematic Rigidbody 2D isn’t. For this reason, it is fast and has a lower demand on system resources than a Dynamic Rigidbody 2D. Kinematic Rigidbody 2D is designed to be repositioned explicitly via Rigidbody2D.MovePosition or Rigidbody2D.MoveRotation. Use physics queries to detect collisions, and scripts to decide where and how the Rigidbody 2D should move.

A Kinematic Rigidbody 2D does still move via its velocity, but the velocity is not affected by forces or gravity. A Kinematic Rigidbody 2D does not collide with other Kinematic Rigidbody 2Ds or with Static Rigidbody 2Ds; it only collides with Dynamic Rigidbody 2Ds. Similar to a Static Rigidbody 2D (see below), a Kinematic Rigidbody 2D behaves like an immovable object (as if it has infinite mass) during collisions. Mass-related properties are not available with this Body Type.

Kinematic Rigidbody2D被设计用来制作在物理模拟下会移动、但是仅仅在明确的用户控制下运动的物体,它不会受到重力和AddForce、AddTorque等力相关的函数的影响。

文档中粗体部分的意思是Kinematic Rigidbody2D对系统资源的要求比Dynamic Rigidbody2D更低(所以更有效率)。Kinematic Rigidbody2D被设计用来通过Rigidbody2D.MovePosition或Rigidbody2D.MoveRotation来进行重定位。

对于Kinematic Rigidbody2D,velocity属性对它依旧有效,只不过施加力和重力都不会对velocity造成影响。

Kinematic Rigidbody2D仅仅只会与Dynamic的Rigidbody2D发生碰撞(在不勾选Use Full Kinematic Contacts的情况下),它在碰撞行为上类似于Static Rigidbody2D,可以理解为具有无限质量、无法被撼动(不能通过力或碰撞改变速度,但是可以设置其速度和位置、旋转)的刚体。

Body Type —— Static

A Static Rigidbody 2D is designed to not move under simulation at all; if anything collides with it, a Static Rigidbody 2D behaves like an immovable object (as though it has infinite mass). It is also the least resource-intensive body type to use. A Static body only collides with Dynamic Rigidbody 2Ds. Having two Static Rigidbody 2Ds collide is not supported, since they are not designed to move.

Only a very limited set of properties are available for this Body Type.

Static Rigidbody2D被设计用来制作在物理模拟下不会移动的物体。它在表现上可以理解为一个具有无限质量、不可移动的物体。此时velocity、AddForce、gravity、MovePosition、MoveRotation都是不可用的。

文档中粗体部分意思是Static Rigidbody2D对资源最不敏感(对性能要求低),Static Rigidbody2D仅仅会与Dynamic Rigidbody2D发生碰撞。两个Static Rigidbody2D之间也不会发生碰撞,因为他们本来就被设计成不可移动的。

Rigidbody2D属性

Simulated(模拟)

Use the Simulated property to stop (unchecked) and start (checked) a Rigidbody 2D and any attached Collider 2Ds and Joint 2Ds from interacting with the 2D physics simulation. Changing this property is much more memory and processor-efficient than enabling or disabling individual Collider 2D and Joint 2D components.

该属性就是字面意思,设置为true(勾选)时开启模拟;设置为false(不勾选)时关闭模拟。

模拟包括:

  • 运动
  • Collider2D的碰撞
  • Joint2D的约束效果
  • 是否驻留在内存

粗体部分的意思是更改此属性在内存和处理上,都比直接启用/禁用Collider2D组件和Joint2D组件更有效率。要知道原理的话,可以查看官方文档,这里就不再作详细解释了。

Use Full Kinematic Contacts

如果想要Kinematic Rigidbody2D与所有类型的Rigidbody2D发生碰撞,可以勾选此选项。勾选上后,它在碰撞上类似于Dynamic Rigidbody2D,但是不会受到力的影响。

当此属性被设置为false(不勾选)时,该Kinematic Rigidbody2D只会与Dynamic Rigidbody2D发生碰撞;它不会与其他的Kinematic Rigidbody2D或Static Rigidbody2D(设置为trigger时除外)发生碰撞。所以此时脚本上的碰撞检测函数(OnCollisionEnter2D,OnCollisionStay2D,OnCollisionExit2D)不会被触发。

所以一般情况下,如果想要制作一个完全由用户控制的Rigidbody2D、同时还能接受所有碰撞,就使用Kinematic Rigidbody2D并勾选Use Full Kinematic Contacts选项。

总结

1、在操作附加了Rigidbody2D的物体时,不要直接通过操作Transform来移动、旋转它。

2、要接受碰撞的Rigidbody2D必须添加Collider2D组件。

3、如果一个Rigidbody2D需要移动,但不接受力的作用,那么需要将它设置成Kinematic;如果它附加了Collider2D组件,在Rigidbody的Use Full Kinematic Contacts属性为false(不勾选)时,它只会与Dynamic的Rigidbody2D碰撞,而不会与Kinematic的或者Static的Rigidbody2D发生碰撞;如果需要它能与受所有类型的Rigidbody2D碰撞,那就设置Use Full Kinematic Contacts为true(勾选)。

4、如果一个Rigidbody2D需要移动,并且接受完全的物理模拟,包括重力、碰撞、施加力等,那么需要将Rigidbody2D设置成Dynamic,并附加Collider2D组件。

5、如果一个Rigidbody2D不需要移动,也不需要接收力的作用,但是需要接受碰撞,那么需要将Rigidbody2D设置为Static,并附加Collider2D组件。

6、在运行中不要修改Rigidbody2D的Body Type属性。

7、在运行中,如果想要停止/启用对一个Rigidbody2D进行物理模拟,那么将这个Rigidbody2D的Simulate属性设置为false/true会比关闭/打开它的Collider2D、Joint2D组件效率高。

你可能感兴趣的:(Unity)