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

Unity C# 可复用多门多杠杆气闸制作方案问询

可复用2D Unity气闸系统脚本实现方案

需求明确

  • 每套气闸包含2扇门+至少2个控制杠杆
  • 初始状态:两扇门全部关闭
  • 操作逻辑:
    • 触发第一个杠杆:仅打开第一扇门
    • 触发第二个杠杆:关闭当前打开的门,同时打开另一扇门
  • 需完全替代原有依赖全局变量、硬编码场景对象的不可复用脚本

现有脚本的核心问题

  • Lever.cs使用静态变量leverStatus,所有杠杆共享同一状态,复用必互相干扰
  • 硬编码查找特定标签对象(如Vacuum、Lever-Door),无法实现独立气闸组
  • LeverDoor.cs逻辑冗余,Update中强制激活物体完全无意义

可复用脚本实现步骤

1. 通用门控制脚本 AirlockDoor.cs

负责单扇门的状态管理、视觉反馈与音效播放,可直接绑定到任意门物体:

using UnityEngine;

public class AirlockDoor : MonoBehaviour
{
    [Header("门基础设置")]
    [SerializeField] private bool initialOpen = false; // 初始状态默认关闭
    [SerializeField] private Animator doorAnimator; // 可选:门开关动画组件
    [SerializeField] private AudioClip openSound; // 可选:开门音效
    [SerializeField] private AudioClip closeSound; // 可选:关门音效

    private AudioSource audioSource;
    private bool isOpen;

    private void Awake()
    {
        audioSource = GetComponent<AudioSource>();
        isOpen = initialOpen;
        UpdateDoorState();
    }

    // 切换门的开关状态
    public void ToggleDoor()
    {
        isOpen = !isOpen;
        UpdateDoorState();
        PlayDoorSound();
    }

    // 直接指定门的开/关状态
    public void SetDoorState(bool shouldOpen)
    {
        if (isOpen != shouldOpen)
        {
            isOpen = shouldOpen;
            UpdateDoorState();
            PlayDoorSound();
        }
    }

    // 更新门的视觉/碰撞状态
    private void UpdateDoorState()
    {
        if (doorAnimator != null)
        {
            doorAnimator.SetBool("IsOpen", isOpen);
        }
        else
        {
            // 无动画时,直接控制碰撞体和渲染器
            Collider2D collider = GetComponent<Collider2D>();
            SpriteRenderer renderer = GetComponent<SpriteRenderer>();
            
            if (collider != null) collider.enabled = !isOpen;
            if (renderer != null) renderer.enabled = !isOpen;
        }
    }

    // 播放门操作音效
    private void PlayDoorSound()
    {
        if (audioSource == null) return;
        
        AudioClip clip = isOpen ? openSound : closeSound;
        if (clip != null) audioSource.PlayOneShot(clip);
    }

    // 外部获取门当前状态
    public bool IsDoorOpen() => isOpen;
}

2. 气闸组核心管理器 AirlockManager.cs

每套气闸对应一个管理器,负责统筹门与杠杆的逻辑,确保气闸组完全独立:

using UnityEngine;
using System.Collections;

public class AirlockManager : MonoBehaviour
{
    [Header("气闸组件关联")]
    [SerializeField] private AirlockDoor entranceDoor; // 入口门(第一扇门)
    [SerializeField] private AirlockDoor exitDoor; // 出口门(第二扇门)
    [SerializeField] private AudioClip leverUseSound; // 杠杆操作音效
    [SerializeField] private AudioClip pressureEqualizeSound; // 气压平衡音效(可选)

    private AudioSource audioSource;
    private bool entranceLeverActivated = false; // 标记入口杠杆是否已触发

    private void Awake()
    {
        audioSource = GetComponent<AudioSource>();
        // 初始化:两扇门全部关闭
        entranceDoor.SetDoorState(false);
        exitDoor.SetDoorState(false);
    }

    // 入口杠杆触发逻辑:仅打开入口门
    public void TriggerEntranceLever()
    {
        if (entranceLeverActivated) return; // 防止重复触发
        
        PlaySound(leverUseSound);
        entranceDoor.SetDoorState(true);
        entranceLeverActivated = true;
    }

    // 出口杠杆触发逻辑:关闭当前门 → 气压平衡 → 打开另一扇门
    public void TriggerExitLever()
    {
        PlaySound(leverUseSound);
        StartCoroutine(EqualizePressureAndSwitchDoors());
    }

    // 模拟气压平衡流程(可根据需求调整延迟时间)
    private IEnumerator EqualizePressureAndSwitchDoors()
    {
        // 先关闭当前打开的门
        if (entranceDoor.IsDoorOpen()) entranceDoor.SetDoorState(false);
        
        PlaySound(pressureEqualizeSound);
        yield return new WaitForSeconds(1.5f); // 气压平衡等待时间

        // 打开出口门
        exitDoor.SetDoorState(true);
    }

    private void PlaySound(AudioClip clip)
    {
        if (audioSource != null && clip != null) audioSource.PlayOneShot(clip);
    }
}

3. 通用交互杠杆脚本 InteractableLever.cs

处理玩家与杠杆的交互逻辑,可绑定到任意杠杆物体,通过Inspector指定对应气闸组:

using UnityEngine;

public class InteractableLever : MonoBehaviour
{
    [Header("交互设置")]
    [SerializeField] private AirlockManager targetAirlock; // 关联的气闸管理器
    [SerializeField] private bool isEntranceLever; // 标记是否为入口杠杆
    [SerializeField] private Animator leverAnimator; // 可选:杠杆触发动画
    [SerializeField] private string interactPrompt = "按E操作杠杆"; // 交互提示文本

    private bool playerInRange = false;
    private bool leverActivated = false;

    private void Update()
    {
        if (playerInRange && !leverActivated && Input.GetAxisRaw("Interact") != 0)
        {
            ActivateLever();
        }
    }

    private void ActivateLever()
    {
        leverActivated = true;
        // 播放杠杆动画
        if (leverAnimator != null) leverAnimator.SetTrigger("Activate");
        // 触发对应气闸逻辑
        if (isEntranceLever) targetAirlock.TriggerEntranceLever();
        else targetAirlock.TriggerExitLever();
    }

    private void OnTriggerEnter2D(Collider2D other)
    {
        if (other.CompareTag("Player"))
        {
            playerInRange = true;
            // 显示交互提示(需你的UIHandler实现对应方法)
            UIHandler.Instance.ShowUseInfo(interactPrompt);
        }
    }

    private void OnTriggerExit2D(Collider2D other)
    {
        if (other.CompareTag("Player"))
        {
            playerInRange = false;
            UIHandler.Instance.DisableUseInfo();
        }
    }
}

使用流程

  1. 创建空物体作为气闸组容器,挂载AirlockManager,在Inspector中关联两扇门与音效
  2. 给两扇门分别挂载AirlockDoor,设置初始状态为关闭,按需添加动画和音效
  3. 创建两个杠杆物体,分别挂载InteractableLever:
    • 入口杠杆:勾选isEntranceLever,关联对应AirlockManager
    • 出口杠杆:取消勾选isEntranceLever,关联同一个AirlockManager
  4. 确保玩家物体带有Player标签,且有2D触发器碰撞体用于交互检测
  5. 确保你的UIHandler实现ShowUseInfo(string)和DisableUseInfo()方法,用于显示交互提示

核心优势

  • 每套气闸独立管理,完全不会干扰其他场景或区域的气闸
  • 模块化设计,所有脚本可直接复制复用,无需修改核心逻辑
  • 逻辑分层清晰,新手易理解和调整,无全局变量或硬编码依赖

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 20:45:13