在 Unity 中,前端模型(3D模型/UI)C# 后端代码的结合主要通过以下几种方式:


一、核心绑定方式

1. 组件(Component)—— 最常用

这是 Unity 的核心设计哲学:模型只是一个容器,行为由挂载的脚本决定

// 1. 创建一个脚本,挂载到模型上
public class PlateBehavior : MonoBehaviour
{
    public string plateName = "青花瓷盘";
    public float weight = 0.5f;
    
    void Start()
    {
        // 模型加载完成后自动执行
        Debug.Log($"{plateName} 已放置到桌子上");
    }
    
    void OnMouseDown()
    {
        // 点击模型时触发
        PickUpPlate();
    }
    
    void PickUpPlate()
    {
        // 和UI交互
        UIManager.Instance.ShowPlateInfo(plateName, weight);
    }
}

层级结构

PlateModel (FBX模型)
├── MeshRenderer (渲染模型)
├── BoxCollider (物理碰撞)
└── PlateBehavior.cs (C#脚本) ← 绑定的行为

2. 获取组件引用

// 方式1:拖拽赋值(最直观)
public class TableManager : MonoBehaviour
{
    public GameObject platePrefab;  // 在Inspector中拖拽预制体
    public Transform spawnPoint;    // 拖拽生成位置
    
    void Start()
    {
        // 实例化模型
        GameObject plate = Instantiate(platePrefab, spawnPoint.position, Quaternion.identity);
        
        // 获取模型上的组件
        PlateBehavior behavior = plate.GetComponent<PlateBehavior>();
        behavior.plateName = "红色盘子";  // 修改属性
        
        // 获取模型上的碰撞体
        BoxCollider collider = plate.GetComponent<BoxCollider>();
        collider.size = new Vector3(0.5f, 0.1f, 0.5f);
    }
}

// 方式2:代码查找
void FindModelComponents()
{
    // 按名称查找
    GameObject model = GameObject.Find("Plate_01");
    
    // 按标签查找
    GameObject[] plates = GameObject.FindGameObjectsWithTag("Tableware");
    
    // 获取子物体中的组件
    Transform child = transform.Find("ModelRoot/PlateBody");
    Renderer renderer = child.GetComponent<Renderer>();
}

3. 事件回调(碰撞、触发)

public class PlateCollision : MonoBehaviour
{
    // 碰撞事件(物理接触)
    void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject.CompareTag("Table"))
        {
            Debug.Log("盘子碰到桌子了");
            PlaySound("plate_put_down.wav");
        }
    }
    
    // 触发事件(穿透检测)
    void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("TrashArea"))
        {
            Destroy(gameObject);  // 盘子掉进垃圾桶
            ScoreManager.Instance.AddScore(-10);
        }
    }
    
    // 鼠标事件
    void OnMouseDown()
    {
        // 点击模型
        DragAndDrop.Instance.StartDragging(this);
    }
    
    void OnMouseEnter()
    {
        // 鼠标悬停高亮
        GetComponent<Renderer>().material.color = Color.yellow;
    }
}

二、模型与UI的联动

1. 模型状态驱动UI更新

public class PlateStatus : MonoBehaviour
{
    public enum State { Clean, Dirty, Broken }
    public State currentState = State.Clean;
    
    // 模型状态变化时通知UI
    public void SetState(State newState)
    {
        currentState = newState;
        
        // 更新UI
        UIManager.Instance.UpdatePlateStatusUI(gameObject.name, newState);
        
        // 改变模型外观
        switch (newState)
        {
            case State.Clean:
                GetComponent<Renderer>().material.color = Color.white;
                break;
            case State.Dirty:
                GetComponent<Renderer>().material.color = Color.gray;
                break;
            case State.Broken:
                Destroy(gameObject);
                break;
        }
    }
}

2. UI按钮控制模型

// UI按钮的OnClick事件绑定
public class ModelController : MonoBehaviour
{
    public GameObject targetModel;  // 要控制的3D模型
    
    // UI按钮点击时调用
    public void RotateModel(float angle)
    {
        targetModel.transform.Rotate(Vector3.up, angle);
    }
    
    public void ChangeModelColor(Color color)
    {
        targetModel.GetComponent<Renderer>().material.color = color;
    }
    
    public void ResetModelPosition()
    {
        targetModel.transform.position = Vector3.zero;
    }
}

三、实战:中餐厅摆台系统的代码结构

// 1. 餐具模型基类
public abstract class Tableware : MonoBehaviour
{
    public string itemName;
    public Sprite icon;  // UI图标
    
    public abstract void PlaceOnTable(Vector3 position);
    public abstract void PickUp();
}

// 2. 具体的盘子类
public class Plate : Tableware
{
    public override void PlaceOnTable(Vector3 position)
    {
        transform.position = position;
        transform.rotation = Quaternion.identity;
        
        // 播放放置动画
        GetComponent<Animator>().SetTrigger("Place");
        
        // 更新UI状态
        WorkbenchUI.Instance.RemoveItem(this);
    }
    
    public override void PickUp()
    {
        // 添加到UI工作台
        WorkbenchUI.Instance.AddItem(this);
        Destroy(gameObject);  // 移除3D模型
    }
}

// 3. 管理所有模型和UI的交互
public class TableManager : MonoBehaviour
{
    public GameObject[] tablewarePrefabs;  // 所有餐具预制体
    public Transform tableSurface;         // 桌子表面
    
    public void SpawnFromUI(string itemName)
    {
        // 从UI拖拽生成3D模型
        foreach (var prefab in tablewarePrefabs)
        {
            if (prefab.GetComponent<Tableware>().itemName == itemName)
            {
                GameObject instance = Instantiate(prefab, tableSurface);
                instance.transform.localPosition = GetRandomTablePosition();
                break;
            }
        }
    }
}

四、模型与代码结合的几种模式

模式

适用场景

实现方式

挂载式

单个物体有独立行为

脚本直接挂到模型上

管理器式

多个同类物体统一管理

一个Manager脚本控制所有模型

事件驱动

模型间交互复杂

使用UnityEvent或委托

MVC模式

大型项目

Model(数据) - View(模型) - Controller(逻辑)


五、最佳实践建议

  1. 预制体(Prefab)是关键

    // 做好一个模型+脚本的预制体
    public GameObject platePrefab;  // 包含PlateBehavior脚本
    
    // 运行时实例化
    GameObject plate = Instantiate(platePrefab, spawnPos, Quaternion.identity);
  2. 使用接口(Interface)解耦

    public interface IInteractable
    {
        void OnInteract();
        string GetInfo();
    }
    
    // 任何模型只要实现这个接口就能被交互
    public class Plate : MonoBehaviour, IInteractable { ... }
    public class Chair : MonoBehaviour, IInteractable { ... }
  3. 通过Inspector可视化绑定

    • 模型拖拽到脚本的公开变量

    • 使用 [SerializeField]私有变量也能在Inspector显示


总结

Unity中模型和C#代码的结合本质上是:

  • 模型 = 视觉载体(Mesh、材质、动画)

  • 脚本 = 行为逻辑(移动、交互、状态)

  • 组件系统 = 桥梁(GetComponent、AddComponent)

一句话:把脚本拖到模型上,或者用代码 AddComponent,模型就有了生命。

更多推荐