Skip to content

2D物理系统

unity-2d-physics-system-deep-dive

核心理解

2D 物理系统可以记成:

c
Sprite:负责显示
Collider2D:负责碰撞形状
Rigidbody2D:负责物理运动
Physics2D:负责射线、范围检测等主动查询

Unity 2D 物理只在 XY 平面运动,只绕 Z 轴旋转。不要把 Rigidbody2D 和 3D 的 BoxCollider 混用,也不要把 RigidbodyBoxCollider2D 混用。

Rigidbody2D 三种类型

c
Dynamic:受重力、碰撞、力影响。玩家、箱子、掉落物。
Kinematic:由脚本控制运动。移动平台、机关、电梯。
Static:不动。地面、墙、固定平台。

平台游戏里常见配置:

玩家:Rigidbody2D Dynamic + CapsuleCollider2D
地面:BoxCollider2D,通常不用 Rigidbody2D
金币:CircleCollider2D + Is Trigger
移动平台:Rigidbody2D Kinematic + BoxCollider2D

最重要习惯

不要用 transform.position 硬推一个带 Rigidbody2D 的角色。官方也提醒,直接改 Transform 容易导致不可预测移动或穿透。物理物体应该通过 Rigidbody2D 移动。

c
Update:读输入
FixedUpdate:改 Rigidbody2D

2D 平台角色基础写法

Unity 6 推荐 linearVelocity;老教程常见 velocity

c
using UnityEngine;

public class Player2DController : MonoBehaviour
{
    public float moveSpeed = 7f;
    public float jumpSpeed = 12f;
    public Transform groundCheck;
    public float groundRadius = 0.12f;
    public LayerMask groundLayer;

    private Rigidbody2D rb;
    private float moveX;
    private bool jumpPressed;

    private void Awake()
    {
        rb = GetComponent<Rigidbody2D>();
    }

    private void Update()
    {
        moveX = Input.GetAxisRaw("Horizontal");

        if (Input.GetButtonDown("Jump"))
        {
            jumpPressed = true;
        }
    }

    private void FixedUpdate()
    {
        bool grounded = Physics2D.OverlapCircle(
            groundCheck.position,
            groundRadius,
            groundLayer
        );

        rb.linearVelocity = new Vector2(moveX * moveSpeed, rb.linearVelocity.y);

        if (jumpPressed && grounded)
        {
            rb.linearVelocity = new Vector2(rb.linearVelocity.x, jumpSpeed);
        }

        jumpPressed = false;
    }
}

这里有三个关键点:

moveX 放在 Update 里读,避免输入漏掉。
真正移动放在 FixedUpdate。
地面检测用 Physics2D.OverlapCircle + LayerMask。

Collision 和 Trigger

普通碰撞会阻挡:

c
private void OnCollisionEnter2D(Collision2D collision)
{
    if (collision.gameObject.CompareTag("Enemy"))
    {
        Debug.Log("撞到敌人");
    }
}

触发器不阻挡,只发事件:

c
private void OnTriggerEnter2D(Collider2D other)
{
    if (other.CompareTag("Player"))
    {
        Destroy(gameObject);
    }
}

金币、传送门、检查点、伤害区,多数用 Is Trigger

主动检测

常用 API:

c
Physics2D.Raycast(...)
Physics2D.OverlapCircle(...)
Physics2D.OverlapBox(...)
Rigidbody2D.Cast(...)

用途:

c
Raycast:向某方向探测,适合看前方有没有墙
OverlapCircle:检测某个圆形范围,适合地面检测、攻击范围
OverlapBox:检测矩形范围,适合近战攻击判定
Rigidbody2D.Cast:沿运动方向提前检测碰撞

材质、关节、效果器

c
Physics Material 2D:控制摩擦和弹性
Joint2D:弹簧、铰链、轮子、绳索、固定连接
Effector2D:单向平台、传送带、浮力、区域力
Physics 2D Settings:全局重力、迭代次数、碰撞矩阵

例子:

c
冰面:Friction 低
弹力球:Bounciness 高
单向平台:Platform Effector 2D
传送带:Surface Effector 2D
绳子/摆锤:Hinge Joint 2D 或 Distance Joint 2D

最常见坑

c
2D3D 组件混用
用 Transform 移动物理角色
把 GetButtonDown 放进 FixedUpdate 导致跳跃漏输入
忘记给地面设置 groundLayer
金币 Collider 没勾 Is Trigger
Trigger 双方都没有合适的 Rigidbody2D
高速子弹穿墙,没有用连续碰撞或射线检测
玩家一碰撞就倒下,忘记冻结 Z Rotation
Tilemap 每格一个碰撞,没用 CompositeCollider2D 优化

一句话总结:

c
Rigidbody2D 管运动,Collider2D 管形状,Trigger 管事件,Physics2D 管主动探测,LayerMask 管筛选,Physics Material 2D 管摩擦弹性。

参考:Unity 官方 Rigidbody2DRigidbody2D Body TypesCollider2DPhysics2D.RaycastRigidbody2D.linearVelocityPhysics Material 2DPhysics 2D Settings

文章评价

读完这篇,留下你的看法

暂无审核通过的评价。

登录账号后才能评价。

本站访客数0总站访问量0本页访问量0