unity进阶篇4-物理系统(碰撞体和刚体)的使用

关于物理系统的使用

b站视频61-63 相关文档

Collider (碰撞体)

  • 如何实现两个物体的碰撞:例, 主角和箱子/树木的碰撞

点击Hierarchy里的物体,查看Inspector界面,然后Add Component,选择Box Collider 2D

Box Collider 2D 和 Box Collider 是不一样的,没有写2D的默认是3D

  • 如何调整Collider的区域
  1. 在Inspector展开Box Collider 2D
  2. 点击Edit Collider,然后会在物体处出现绿色边框
  3. 可以手动点击绿色边框进行调整,或在offset和size处调整绿色边框大小
  • 两个物体发生碰撞后,一个物体进行了旋转,如果不想让它旋转怎么办
  1. 在物体的Inspector里展开Rigidbody 2D(刚体)
  2. Constraints(约束/限制)里有Freeze Rotation x/y/z轴
  3. 旋转时因为2D画像沿着z轴旋转,所以我们将Freeze Rotation Z 打勾就行了
  • 为什么两个物体相互碰撞时会出现剧烈抖动。

由于在移动的人物/物体里使用的移动代码时Transform,这是一个变化位置组件,它不会影响到物理碰撞的组件,它只会影响到它下一步的位置,它不管这个position在不在碰撞范围内,Transform的组件先进去,然后Rigidbody再将Transform还原到之前位置(挤出),所以一进一出就产生了抖动。

1
2
3
4
5
6
Vector2 position = transform.position;
//更改position的x坐标值,让它每帧加0.1,update就是一帧一帧循环的。
position.x = position.x + Speed*horizontal*Time.deltaTime;
position.y = position.y + Speed*vertical*Time.deltaTime;
//更新位置的数据后,我们需要讲更新后的数据输入到新的位置(更新transform)
transform.position = position;

所以我们不能用transform来变化它的位置

我们需要用刚体组件来变化它的位置

这是用Transform组件编写的移动代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class RubyController : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{

}

public float Speed = 0.1f;
// Update is called once per frame
void Update()
{
//获取水平输入
float horizontal = Input.GetAxis("Horizontal");
//获取垂直输入
float vertical = Input.GetAxis("Vertical");

//创建一个Vector2的对象position,用来获取当前角色位置。
Vector2 position = transform.position;
//更改position的x坐标值,让它每帧加0.1,update就是一帧一帧循环的。
position.x = position.x + Speed*horizontal*Time.deltaTime;
position.y = position.y + Speed*vertical*Time.deltaTime;
//更新位置的数据后,我们需要讲更新后的数据输入到新的位置(更新transform)
transform.position = position;
}
}

这是用Rigidbody便携的移动代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RubyController : MonoBehaviour
{
// Start is called before the first frame update

private Rigidbody2D rigidbody2D;

float horizontal;
float vertical;
//将速度暴露出来,使其可调
public float Speed = 0.1f;

private void Start()
{
rigidbody2D = GetComponent<Rigidbody2D>();
}

// Update is called once per frame
void Update()
{
//获取水平输入
horizontal = Input.GetAxis("Horizontal");
//获取垂直输入
vertical = Input.GetAxis("Vertical");
}

//固定时间间隔执行的更新方法
private void FixedUpdate()
{
//创建一个Vector2的对象position,用来获取当前角色位置。
Vector2 position = transform.position;
//更改position的x坐标值,让它每帧加0.1,update就是一帧一帧循环的。
position.x = position.x + Speed*horizontal*Time.deltaTime;
position.y = position.y + Speed*vertical*Time.deltaTime;
//更新位置的数据后,我们需要讲更新后的数据输入到新的位置(更新transform)
rigidbody2D.position = position;
}
}

每次游戏计算新图像时都会调用 Update,问题是调用速度不确定。在一台速度较慢的计算机上,调用速度可能是每秒 20 张图像,而在一台非常快的计算机上,调用速度可能是每秒 3000 张图像。

为了使物理计算保持稳定,需要定期进行更新(例如,每隔 16ms)。Unity 还有另一个名为 FixedUpdate 的函数,只要你想直接影响物理组件或对象(例如刚体),就需要使用该函数。

不要把水平输入和垂直输入放到FixedUpdate

1
2
3
4
5
6
7
void Update()
{
//获取水平输入
horizontal = Input.GetAxis("Horizontal");
//获取垂直输入
vertical = Input.GetAxis("Vertical");
}

如果将水平输入和垂直输入放到FixedUpdate,由于它会在一定时间间隔内更新,所以会产生跳帧现象。

FixedUpdate Unity官方资料

**Compute Physics system calculations after FixedUpdate. 0.02 seconds (50 calls per second) is the default time between calls. **

默认是每0.02秒刷新一次,每秒50帧。

  • 如果我们想更改FIxedUpdate 的时间间隔怎么办
  1. Edit
  2. Project Settings…
  3. Time
  4. Fixed Timestep
  • 如果我们想给Tilemap添加碰撞体如何添加,如:我们想让主角不能闯过某些场景
  1. 点击自己创建的Tilemap
  2. Add Component
  3. Tilemap Collider 2D
  4. 然后会发现在Scene里布置的Tilemap全部都有绿色的方格
  • 如何只选择一些特殊的不应该通过的场景保留绿色方格呢。
  1. 点击创造场景的预制件(如果放到统一一个文件夹可以直接全选),然后将Sprite改成None
  2. 选择你想要主角不通过的场景的预制件,将其选择Sprite就行了。
  • 有一些是Rule Override Tile,我要如何一旦前面的Tile改变属性,被Override Tile 也会改变属性。
  1. 将Rule Override Tile删除
  2. 建立Advance Rule Override Tile,这个Override tile 能直接改变属性不因为前面覆盖的所影响。
  3. 更改也是像之前的Rule Override Tile更改
  • 如何优化Tilemap的碰撞体

目前,正如在 Scene 视图中看到的,每个瓦片都是一个单独的碰撞体。 这种方法效果良好,但会产生两个问题:

  • 物理系统的计算量更大;如果你的世界很大,可能会减慢你的游戏速度。
  • 在瓦片之间的边界上会产生小问题。由于瓦片是两个并排的碰撞体,并且两者之间存在微小间隙,因此有时计算上的微小误差也可能导致仍会发生碰撞的罕见情况。

为了解决这些问题,Unity 提供了一个名为 Composite Collider 2D 的组件。此组件可以获取对象(或对象的子对象)上的所有碰撞体,并由此创建一个大碰撞体

  1. 在Tilemap上 Add Component
  2. 添加Composite Collider 2D,它会自动添加Rigidbody2D
  3. 在之前添加的Tilemap Collider 2D 里勾选Used by Composite
  4. 将Rigidbody2D 从Dynamic -> Static(将动态设置成静态) ,不然它会因为碰撞而产生图像旋转。
  • Copyrights © 2022-2024 Jessy Huang
  • Visitors: | Views:

请我喝杯咖啡吧~