You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity OnTrigger事件下如何为每个碰撞体配置独立TextArea与自定义行为

解决方案

现有问题梳理

  • 初始版本硬编码NoEntry/NoExit两种状态,用全局字符串数组按索引读取提示,无法给不同碰撞体做差异化配置
  • 已实现的ColliderInfo组件仅支持朝向指定Transform旋转的逻辑,不支持固定角度旋转,触发逻辑写死,扩展新行为需要反复修改核心代码
  • 触发检测和配置耦合度高,新增碰撞规则需要调整原有字段结构,维护成本高

重构实现

第一步:定义通用枚举与可序列化配置结构

首先把触发行为抽象成枚举和可序列化配置类,Unity可以直接在Inspector面板序列化显示这类结构,不需要额外插件:

// 触发行为类型枚举,后续加新逻辑直接在这里加枚举值即可
public enum TriggerActionType
{
    None,
    RotateTowardsTarget, // 朝向指定物体旋转后退
    RotateByFixedAngle, // 按固定角度旋转后退
    PlayerDeath, // 触发玩家死亡(坠落、触碰陷阱等)
    Teleport // 预留传送等其他行为
}

// 单个触发行为的配置块,所有行为参数统一存在这里
[System.Serializable]
public class TriggerActionConfig
{
    public TriggerActionType actionType = TriggerActionType.None;
    // 旋转类共用参数
    public float bounceBackDistance = 1f; // 触发后后退距离
    // RotateTowardsTarget 专属参数
    public Transform targetTransform;
    // RotateByFixedAngle 专属参数
    public Vector3 fixedEulerAngle = new Vector3(0, 180, 0);
    // 后续新行为的参数直接往下加即可,比如传送的目标点、死亡的延迟时间
}

第二步:重构ColliderInfo组件

替换原来单独的rotateTowards字段,把进入、退出触发的行为完全独立配置,保留原有的文本输入字段:

using UnityEngine;

public class ColliderInfo : MonoBehaviour
{
    [TextArea(3,6)]
    public string onEnterTip;
    [TextArea(3,6)]
    public string onExitTip;

    public TriggerActionConfig enterAction;
    public TriggerActionConfig exitAction;
}

第三步:编写触发逻辑执行器

把原来写死的旋转逻辑改成按配置类型分发执行,触发检测脚本只负责拿到碰撞体上的ColliderInfo、显示提示、调用行为执行逻辑:

using UnityEngine;
using TMPro;

public class PlayerTrigger : MonoBehaviour
{
    [SerializeField] private TextMeshProUGUI tipText;
    [SerializeField] private Transform playerRoot;
    [SerializeField] private float tipShowDuration = 2f;
    private float _tipTimer;

    private void Update()
    {
        if (_tipTimer > 0)
        {
            _tipTimer -= Time.deltaTime;
            if (_tipTimer <= 0) tipText.text = string.Empty;
        }
    }

    private void OnTriggerEnter(Collider other)
    {
        if (!other.TryGetComponent(out ColliderInfo colInfo)) return;
        // 显示进入提示
        if (!string.IsNullOrEmpty(colInfo.onEnterTip))
        {
            tipText.text = colInfo.onEnterTip;
            _tipTimer = tipShowDuration;
        }
        // 执行进入行为
        ExecuteAction(colInfo.enterAction);
    }

    private void OnTriggerExit(Collider other)
    {
        if (!other.TryGetComponent(out ColliderInfo colInfo)) return;
        // 显示退出提示
        if (!string.IsNullOrEmpty(colInfo.onExitTip))
        {
            tipText.text = colInfo.onExitTip;
            _tipTimer = tipShowDuration;
        }
        // 执行退出行为
        ExecuteAction(colInfo.exitAction);
    }

    // 核心行为分发逻辑,加新行为只需要在这里加switch分支
    private void ExecuteAction(TriggerActionConfig config)
    {
        if (config == null || config.actionType == TriggerActionType.None) return;
        switch (config.actionType)
        {
            case TriggerActionType.RotateTowardsTarget:
                if (config.targetTransform == null) break;
                Vector3 lookDir = config.targetTransform.position - playerRoot.position;
                lookDir.y = 0;
                playerRoot.rotation = Quaternion.LookRotation(lookDir);
                playerRoot.position -= playerRoot.forward * config.bounceBackDistance;
                break;
            case TriggerActionType.RotateByFixedAngle:
                playerRoot.Rotate(config.fixedEulerAngle, Space.Self);
                playerRoot.position -= playerRoot.forward * config.bounceBackDistance;
                break;
            case TriggerActionType.PlayerDeath:
                // 这里写自定义的玩家死亡逻辑,比如播动画、回复活点
                Debug.Log("触发死亡判定");
                break;
            case TriggerActionType.Teleport:
                // 预留传送逻辑
                break;
        }
    }
}

(可选)优化Inspector面板显示

如果不想在面板看到当前行为类型用不到的冗余字段,可以加一个简单的编辑器脚本,面板会自动根据选中的行为类型显示对应参数:

using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(ColliderInfo))]
public class ColliderInfoDrawer : Editor
{
    SerializedProperty _enterTip, _exitTip, _enterAction, _exitAction;
    private void OnEnable()
    {
        _enterTip = serializedObject.FindProperty("onEnterTip");
        _exitTip = serializedObject.FindProperty("onExitTip");
        _enterAction = serializedObject.FindProperty("enterAction");
        _exitAction = serializedObject.FindProperty("exitAction");
    }

    public override void OnInspectorGUI()
    {
        serializedObject.Update();
        EditorGUILayout.PropertyField(_enterTip);
        EditorGUILayout.PropertyField(_exitTip);
        DrawConfigBlock(_enterAction, "进入触发配置");
        DrawConfigBlock(_exitAction, "退出触发配置");
        serializedObject.ApplyModifiedProperties();
    }

    private void DrawConfigBlock(SerializedProperty config, string blockName)
    {
        EditorGUILayout.Space(8);
        EditorGUILayout.LabelField(blockName, EditorStyles.boldLabel);
        SerializedProperty actionType = config.FindPropertyRelative("actionType");
        EditorGUILayout.PropertyField(actionType);
        TriggerActionType curType = (TriggerActionType)actionType.enumValueIndex;
        EditorGUILayout.PropertyField(config.FindPropertyRelative("bounceBackDistance"));
        
        switch (curType)
        {
            case TriggerActionType.RotateTowardsTarget:
                EditorGUILayout.PropertyField(config.FindPropertyRelative("targetTransform"));
                break;
            case TriggerActionType.RotateByFixedAngle:
                EditorGUILayout.PropertyField(config.FindPropertyRelative("fixedEulerAngle"));
                break;
        }
    }
}

注意:上述编辑器脚本必须存放到项目内名为Editor的特殊文件夹下才能正常生效,该文件夹下的代码仅在编辑器环境运行,不会被打入正式游戏包。

配置方法

  • 所有碰撞体独立挂载ColliderInfo组件,直接在组件上填写对应进入/退出提示文本即可,不需要维护全局文本数组
  • NoEntry类碰撞体:进入行为选RotateByFixedAngle,Y轴角度设为180,调整后退距离,不需要拖任何目标物体
  • NoExit类碰撞体:退出行为选RotateTowardsTarget,把场景中需要玩家后退后面向的点位/物体拖到目标字段即可
  • 死亡陷阱类碰撞体:进入行为选PlayerDeath,填好死亡提示文本即可
  • 后续新增触发逻辑,只需要在枚举里加值、在配置类加对应参数、在执行逻辑里加分支,不需要改动原有组件结构

内容的提问来源于stack exchange,提问作者Daniel Lip

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 18:57:48