Unity Term Book
Physics

Physics Material

Physics Material là asset điều khiển bề mặt vật lý — mức ma sát (friction) và độ nảy (bounciness) khi hai Collider chạm nhau, từ băng trơn đến bóng cao su.

Hãy tưởng tượng...

Physics Material giống như loại vật liệu bề mặt sân chơi. Sân bê tông thô ráp → bóng dừng lại nhanh (ma sát cao). Sàn đá đánh bóng → bóng trượt xa (ma sát thấp). Bề mặt cao su → bóng nảy lên cao (bounciness cao). Đệm cát → bóng thụp ngay (bounciness thấp). Trong Unity, bạn tạo Physics Material như một asset riêng, rồi gán vào bất kỳ Collider nào để thay đổi cách nó tương tác với thế giới vật lý.

Khái niệm chi tiết

Physics Material (file .physicMaterial trong 3D, .physicsMaterial2D trong 2D) là ScriptableObject-like asset với 4 thuộc tính chính: Dynamic Friction (ma sát khi đang trượt, 0–1), Static Friction (ma sát khi bắt đầu từ đứng yên, thường cao hơn Dynamic), Bounciness (0 = không nảy, 1 = nảy hoàn toàn), và hai chế độ kết hợp Friction CombineBounce Combine (Average/Min/Max/Multiply).

Khi hai Collider có Physics Material khác nhau va chạm, Unity kết hợp giá trị của chúng theo Combine Mode. Ví dụ với Average: friction = (frictionA

  • frictionB) / 2. Với Minimum: friction = min(frictionA, frictionB) — hữu ích cho bề mặt băng (1 bên = 0 luôn thắng). Thứ tự ưu tiên kết hợp: Average < Minimum < Maximum < Multiply.

Một lưu ý quan trọng: Bounciness = 1 trong Unity không phải nảy hoàn toàn không mất năng lượng. Unity vẫn áp dụng damping và gravity giữa các bounce. Để có bouncing gần hoàn hảo, cần kết hợp Bounciness = 1 với Bounce Combine = Maximum và giảm Rigidbody drag về 0.

Bạn có thể thay đổi Physics Material tại runtime bằng cách gán vào collider.material hoặc collider.sharedMaterial. Dùng sharedMaterial khi muốn thay đổi ảnh hưởng đến toàn bộ instance dùng cùng material (tiết kiệm bộ nhớ).

Preset vật liệu thực tế

🧱 Gạch

Dynamic Friction: 0.6

Static Friction: 0.6

Bounciness: 0.0

🧊 Băng

Dynamic Friction: 0.02

Static Friction: 0.02

Bounciness: 0.0

🏀 Cao su

Dynamic Friction: 0.8

Static Friction: 0.8

Bounciness: 0.8

🪵 Gỗ

Dynamic Friction: 0.48

Static Friction: 0.48

Bounciness: 0.0

Combine ModeCông thứcDùng khi
Average(A + B) / 2Mặc định, trung bình
Minimummin(A, B)Băng (1 bên = 0 thắng)
Maximummax(A, B)Cao su (bounce cực đại)
MultiplyA × BMặt dính, nhân bội

Hướng dẫn thực hành

1

Tạo Physics Material

Project Panel → chuột phải → Create → Physics Material (3D) hoặc Physics Material 2D. Đặt tên theo vật liệu (Rubber, Ice...).

2

Thiết lập giá trị Friction và Bounciness

Dynamic Friction (0–1), Static Friction (0–1), Bounciness (0–1). Tham khảo bảng preset hoặc tự thử nghiệm.

3

Chọn Combine Mode phù hợp

Friction/Bounce Combine: Average là mặc định. Dùng Minimum cho băng, Maximum cho cao su nảy.

4

Gán vào Collider

Chọn GameObject → Collider component → slot "Material" → kéo thả Physics Material từ Project vào.

5

Play và tinh chỉnh

Chạy game, quan sát cách vật thể di chuyển và điều chỉnh giá trị. Có thể edit Physics Material ngay khi đang play.

Trình mô phỏng tương tác

Điều chỉnh Friction và Bounciness rồi thả bóng để xem hiệu ứng thực tế.

Thiết lập thông số và nhấn "Thả bóng"

Ví dụ Code

Cơ bản

Thay đổi Physics Material tại runtime khi nhân vật đứng trên bề mặt khác nhau.

using UnityEngine;

public class SurfaceMaterialSwapper : MonoBehaviour
{
  public PhysicMaterial normalMat, iceMat, rubberMat;
  Collider col;

  void Start() => col = GetComponent<Collider>();

  void OnCollisionStay(Collision collision)
  {
      // Đọc surface tag từ mặt đất đang đứng
      string tag = collision.gameObject.tag;

      col.material = tag switch
      {
          "Ice"    => iceMat,
          "Rubber" => rubberMat,
          _        => normalMat,
      };
  }

  void OnCollisionExit(Collision _)
  {
      col.material = normalMat; // Phục hồi khi rời mặt đất
  }
}

Ví dụ Code

Nâng cao

Tạo Physics Material động tại runtime và điều chỉnh theo trạng thái game.

using UnityEngine;

// Tạo và quản lý PhysicMaterial động — không cần asset file
public class DynamicPhysicsMaterial : MonoBehaviour
{
  Collider col;
  PhysicMaterial dynMat;

  [Range(0f, 1f)] public float friction = 0.4f;
  [Range(0f, 1f)] public float bounciness = 0f;

  void Awake()
  {
      col = GetComponent<Collider>();

      // Tạo PhysicMaterial lúc runtime, không cần Project asset
      dynMat = new PhysicMaterial("Dynamic")
      {
          dynamicFriction  = friction,
          staticFriction   = friction * 1.2f,
          bounciness       = bounciness,
          frictionCombine  = PhysicMaterialCombine.Average,
          bounceCombine    = PhysicMaterialCombine.Maximum
      };

      col.material = dynMat;
  }

  // Gọi từ nơi khác để thay đổi realtime (ví dụ: khi nhân vật bị đóng băng)
  public void SetIce()
  {
      dynMat.dynamicFriction = 0.01f;
      dynMat.staticFriction  = 0.01f;
      col.material = dynMat; // Gán lại để Unity nhận giá trị mới
  }
}

📌 Ghi nhớ nhanh

  • 0 = không ma sát / không nảy, 1 = tối đa
  • Static Friction > Dynamic Friction (thực tế vật lý)
  • Minimum Combine: 1 bên = 0 → tổng = 0 (băng lý tưởng)
  • col.material tạo bản sao riêng; sharedMaterial dùng chung
  • Cần gán lại col.material sau khi chỉnh PhysicMaterial runtime

⚠️ Lỗi thường gặp

  • ❌ Chỉnh collider.material.bounciness = X mà không gán lại

    Unity không detect thay đổi nội bộ — giá trị không update

    ✅ Tạo giá trị mới và gán lại: col.material = updatedMat;

  • ❌ Đặt Bounciness = 1 nhưng bóng vẫn mất năng lượng

    Rigidbody.drag > 0 và gravity tiêu thụ năng lượng

    ✅ Đặt drag = 0 và Bounce Combine = Maximum