
🐾 个人主页 🐾
阿松爱睡觉,横竖醒不来 🏅你可以不屠龙,但不能不磨剑🗡
文章目录
- 一、前言
- 二、Dynamic(动态类型)
- 三、Kinematic(运动学类型)
- 四、Static(静态类型)
- 五、实际应用场景示例
-
- (一)平台游戏角色控制
- (二)移动平台系统
- [(三)动态切换Body Type](#(三)动态切换Body Type)
- 六、选择指南
一、前言
在Unity的物理系统中,无论是3D还是2D,Rigidbody的 Body Type有三种类型,每种类型都有不同的物理行为和适用场景。
三种Body Type类型:Dynamic(动态类型)、Kinematic(运动学类型)、Static(静态类型)
先来详细看下对比表格
| 特性 | Dynamic | Kinematic | Static |
|---|---|---|---|
| 受重力影响 | ✅ | ❌ | ❌ |
| 受外力影响 | ✅ | ❌ | ❌ |
| 可代码控制 | ✅ | ✅ | ❌ |
| 可碰撞检测 | ✅ | ✅ | ✅ |
| 可推动其他物体 | ✅ | ✅ | ✅ |
| 被其他物体推动 | ✅ | ❌ | ❌ |
| 性能消耗 | 中等 | 低 | 最低 |
| 可休眠 | ✅ | ❌ | ❌ |
下面分别具体的看下各个类型值的具体讲解和代码实例。(以2D世界为例------Rigidbody2D )
二、Dynamic(动态类型)
Dynamic是Unity开发中最常用的类型,完全受物理引擎的控制,主要有一下特性:
特性:
- ✅ 受重力影响
- ✅ 受外力作用(AddForce等)
- ✅ 与其他碰撞体发生碰撞
- ✅ 速度和质量影响运动
- ✅ 可以休眠以优化性能
代码示例:
csharp
public class DynamicBodyExample : MonoBehaviour
{
private Rigidbody2D rb;
void Start()
{
rb = GetComponent<Rigidbody2D>();
rb.bodyType = RigidbodyType2D.Dynamic;
// 动态物体可以施加力
rb.AddForce(Vector2.up * 10f, ForceMode2D.Impulse);
rb.gravityScale = 1f; // 受重力影响
}
void Update()
{
// 玩家控制
if (Input.GetKey(KeyCode.RightArrow))
{
rb.AddForce(Vector2.right * 5f);
}
}
}
应用场景:
- 玩家角色
- 敌人NPC
- 可交互的物体(箱子、球等)
- 发射的炮弹
- 任何需要物理交互的物体
三、Kinematic(运动学类型)
这个类型可以通过代码控制运动,不受物理力影响,但可以影响其他物体。
特性:
- ❌ 不受重力影响
- ❌ 不受外力影响
- ✅ 通过代码控制运动(velocity、MovePosition)
- ✅ 可以推动Dynamic物体
- ❌ 不会因碰撞而改变运动方向
代码示例:
csharp
public class KinematicBodyExample : MonoBehaviour
{
private Rigidbody2D rb;
public float moveSpeed = 5f;
void Start()
{
rb = GetComponent<Rigidbody2D>();
rb.bodyType = RigidbodyType2D.Kinematic;
rb.gravityScale = 0f; // 明确设置不受重力
}
void Update()
{
// 通过代码直接控制运动
Vector2 input = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
rb.velocity = input * moveSpeed;
// 或者使用MovePosition
// Vector2 newPosition = rb.position + input * moveSpeed * Time.deltaTime;
// rb.MovePosition(newPosition);
}
void OnCollisionEnter2D(Collision2D collision)
{
// 碰撞时不会自动改变运动,但可以推动Dynamic物体
if (collision.gameObject.CompareTag("Box"))
{
Debug.Log("推动了箱子!");
}
}
}
应用场景:
- 平台游戏中的移动平台
- 玩家控制的角色(如果需要精确控制)
- 电梯、传送带
- 通过代码精确控制的物体
- 需要推动其他物体但自身运动不受物理影响的物体
四、Static(静态类型)
完全静止的物体,性能最优,处于睡眠状态,性能开最小,但是只能用于一些静止不动的物体上。
特性:
- ❌ 完全静止,无法移动
- ❌ 不受任何物理影响
- ✅ 可以与Dynamic物体碰撞
- ✅ 最佳性能(物理引擎不需要计算其运动)
- ❌ 运行时无法改变位置
代码示例:
csharp
public class StaticBodyExample : MonoBehaviour
{
void Start()
{
Rigidbody2D rb = GetComponent<Rigidbody2D>();
rb.bodyType = RigidbodyType2D.Static;
// 静态物体无法在运行时移动
// rb.velocity = Vector2.zero; // 无效
// rb.AddForce(Vector2.right); // 无效
}
void OnCollisionEnter2D(Collision2D collision)
{
// 仍然可以检测到碰撞
if (collision.gameObject.CompareTag("Player"))
{
Debug.Log("玩家撞到了静态物体");
}
}
}
应用场景:
- 地形、墙壁
- 静止的障碍物
- 建筑物
- 任何永远不会移动的物体
五、实际应用场景示例
(一)平台游戏角色控制
csharp
public class PlatformerPlayer : MonoBehaviour
{
private Rigidbody2D rb;
public bool useDynamicPhysics = true;
void Start()
{
rb = GetComponent<Rigidbody2D>();
if (useDynamicPhysics)
{
// 使用Dynamic:真实的物理感觉,但控制较难
rb.bodyType = RigidbodyType2D.Dynamic;
rb.gravityScale = 3f;
rb.freezeRotation = true; // 防止旋转
}
else
{
// 使用Kinematic:精确控制,但物理感较弱
rb.bodyType = RigidbodyType2D.Kinematic;
rb.gravityScale = 0f;
}
}
void Update()
{
float moveInput = Input.GetAxis("Horizontal");
if (rb.bodyType == RigidbodyType2D.Dynamic)
{
// Dynamic控制:施加力
rb.AddForce(new Vector2(moveInput * 10f, 0));
}
else
{
// Kinematic控制:直接设置速度
rb.velocity = new Vector2(moveInput * 5f, rb.velocity.y);
}
// 跳跃
if (Input.GetKeyDown(KeyCode.Space) && IsGrounded())
{
if (rb.bodyType == RigidbodyType2D.Dynamic)
{
rb.AddForce(Vector2.up * 8f, ForceMode2D.Impulse);
}
else
{
rb.velocity = new Vector2(rb.velocity.x, 8f);
}
}
}
bool IsGrounded()
{
// 地面检测逻辑
return Physics2D.Raycast(transform.position, Vector2.down, 0.1f);
}
}
(二)移动平台系统
csharp
public class MovingPlatform : MonoBehaviour
{
private Rigidbody2D rb;
public Vector2[] waypoints;
public float speed = 2f;
private int currentWaypoint = 0;
void Start()
{
rb = GetComponent<Rigidbody2D>();
rb.bodyType = RigidbodyType2D.Kinematic; // 必须使用Kinematic
}
void FixedUpdate()
{
// 移动到下一个路径点
Vector2 target = waypoints[currentWaypoint];
Vector2 newPosition = Vector2.MoveTowards(rb.position, target, speed * Time.fixedDeltaTime);
rb.MovePosition(newPosition);
// 检查是否到达路径点
if (Vector2.Distance(rb.position, target) < 0.1f)
{
currentWaypoint = (currentWaypoint + 1) % waypoints.Length;
}
}
void OnCollisionEnter2D(Collision2D collision)
{
// 让站在平台上的物体随平台移动
if (collision.gameObject.CompareTag("Player"))
{
collision.transform.SetParent(transform);
}
}
void OnCollisionExit2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("Player"))
{
collision.transform.SetParent(null);
}
}
}
(三)动态切换Body Type
csharp
public class SwitchBodyType : MonoBehaviour
{
private Rigidbody2D rb;
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
// 切换到Dynamic(变成物理物体)
public void MakeDynamic()
{
rb.bodyType = RigidbodyType2D.Dynamic;
rb.gravityScale = 1f;
rb.velocity = Vector2.zero;
}
// 切换到Kinematic(变成可控制物体)
public void MakeKinematic()
{
rb.bodyType = RigidbodyType2D.Kinematic;
rb.velocity = Vector2.zero;
}
// 切换到Static(变成静态障碍物)
public void MakeStatic()
{
rb.bodyType = RigidbodyType2D.Static;
}
// 示例:当物体落地后变成静态,比如掉地上就失效捡不起来的物体
void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("Ground"))
{
// 延迟后变成静态
Invoke("BecomeStatic", 2f);
}
}
void BecomeStatic()
{
MakeStatic();
Debug.Log("物体已静止");
}
}
六、选择指南
- 需要真实物理效果 → 选择
Dynamic - 需要精确代码控制 → 选择
Kinematic - 完全静止的物体 → 选择
Static - 移动平台/电梯 → 必须使用 Kinematic
