You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Unity中实现特定门单独锁/解锁控制及动态地图管控方案问询

Hey there! Let's break this down step by step to solve your door control problem first, then tackle that dynamic station map you're aiming for.


Part 1: Refactoring Door Control for Individual Door Management

Your current DoorsLockManager applies a global lock state to all doors, which doesn't support per-door control. Here's how to fix that with a modular, scalable approach:

Step 1: Create a Per-Door State Component

First, make a DoorState script to handle individual door logic—this will store each door's lock state, visuals, and link to its controller. Attach this to every door GameObject:

using UnityEngine;

public class DoorState : MonoBehaviour
{
    [Header("Door Configuration")]
    public bool isLocked = true; // Default to locked
    public Color lockedColor = new Color32(255, 0, 0, 255);
    public Color unlockedColor = new Color32(0, 255, 0, 255);
    
    [Header("Component References")]
    public HoriDoorManager doorController;
    private Renderer doorRenderer;

    // Event for map sync (we'll use this later!)
    public event System.Action<bool> OnLockStateUpdated;

    private void Awake()
    {
        doorRenderer = GetComponent<Renderer>();
        SetupUnlitMaterial();
        UpdateDoorAppearance();
    }

    private void SetupUnlitMaterial()
    {
        Shader unlitShader = Shader.Find("Unlit/Color");
        doorRenderer.material.shader = unlitShader;
        doorRenderer.material.SetFloat("_Metallic", 1);
    }

    // Public method to set lock state externally
    public void SetLockState(bool newLockState)
    {
        isLocked = newLockState;
        UpdateDoorAppearance();
        UpdateDoorController();
        OnLockStateUpdated?.Invoke(isLocked);
    }

    // Toggle lock state (for in-game interactions)
    public void ToggleLock()
    {
        SetLockState(!isLocked);
    }

    private void UpdateDoorAppearance()
    {
        doorRenderer.material.color = isLocked ? lockedColor : unlockedColor;
    }

    private void UpdateDoorController()
    {
        if (doorController != null)
        {
            doorController.doorLockState = isLocked;
        }
    }
}

Step 2: Rework the Global Door Manager

Turn DoorsLockManager into a centralized manager that tracks all doors and lets you control specific ones:

using System.Collections.Generic;
using UnityEngine;

public class DoorsLockManager : MonoBehaviour
{
    private List<DoorState> allDoors = new List<DoorState>();

    private void Start()
    {
        // Grab all door state components in the scene
        allDoors.AddRange(FindObjectsOfType<DoorState>());
        
        // Example: Unlock 3 random doors on game start
        UnlockRandomDoors(3);
    }

    // Unlock a specific number of random doors
    private void UnlockRandomDoors(int count)
    {
        if (count >= allDoors.Count)
        {
            Debug.LogWarning("Trying to unlock more doors than exist!");
            count = allDoors.Count;
        }

        // Shuffle doors and unlock the first N
        List<DoorState> shuffledDoors = new List<DoorState>(allDoors);
        shuffledDoors.Shuffle();

        for (int i = 0; i < count; i++)
        {
            shuffledDoors[i].SetLockState(false);
        }
    }

    // Public method to unlock a door by name
    public void UnlockDoorByName(string doorName)
    {
        DoorState targetDoor = allDoors.Find(door => door.gameObject.name == doorName);
        targetDoor?.SetLockState(false) ?? Debug.LogWarning($"Door {doorName} not found!");
    }

    // Lock/unlock all doors at once
    public void SetAllDoorsLockState(bool lockState)
    {
        foreach (var door in allDoors)
        {
            door.SetLockState(lockState);
        }
    }
}

// Extension method to shuffle lists (for random door selection)
public static class ListExtensions
{
    public static void Shuffle<T>(this IList<T> list)
    {
        System.Random rng = new System.Random();
        int n = list.Count;
        while (n > 1)
        {
            n--;
            int k = rng.Next(n + 1);
            (list[k], list[n]) = (list[n], list[k]);
        }
    }
}

Step 3: Tweak the HoriDoorManager

Simplify and add a safety check to avoid accidental triggers:

using UnityEngine;

public class HoriDoorManager : MonoBehaviour
{
    public DoorHori door1;
    public DoorHori door2;
    public bool doorLockState;

    void OnTriggerEnter(Collider other)
    {
        // Only respond to player triggers
        if (other.CompareTag("Player") && !doorLockState)
        {
            door1?.OpenDoor();
            door2?.OpenDoor();
        }
    }
}

Part 2: Optimal Implementation for a Dynamic Station Map

For a responsive, data-driven station map that syncs with door states, here's the best approach:

1. Data-Driven Map Foundation

  • Create a StationMapData ScriptableObject to store your station's layout:
    • Define rooms, doors, and their positions relative to the map UI.
    • Link each DoorState to its corresponding map entry (via a reference in DoorState).

2. UGUI Map UI

  • Build your map using Unity's UGUI:
    • Use Image components for rooms/doors (match the station's layout).
    • For each door UI element, subscribe to its linked DoorState.OnLockStateUpdated event to update color in real-time (red for locked, green for unlocked).

3. State Sync & Performance

  • Only sync map updates when the map is visible (disable event subscriptions when the map UI is closed to save performance).
  • Use object pooling for map elements if you have a huge station, to avoid frequent instantiation/destruction.

4. Interactive Features

  • Add click handlers to map doors to:
    • Show door status tooltips.
    • Jump to the door's location (if your game allows fast travel).
  • Add a player position marker that updates in real-time using the player's transform.

5. Scalability

  • Organize doors/rooms into zones (e.g., "Living Quarters", "Engine Bay") and let the map show/hide zones based on player progress.
  • Use a singleton MapManager to handle all map UI logic and sync with DoorsLockManager.

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

火山引擎 最新活动