Unity引擎开发幻境空间超级元宇宙技术总结(技术编程深度篇)二

csharp

    // 获取属性
    public T GetProperty<T>(string key, T defaultValue = default)
    {
        if (properties.TryGetValue(key, out object value))
        {
            try
            {
                return (T)Convert.ChangeType(value, typeof(T));
            }
            catch
            {
                return defaultValue;
            }
        }
        return defaultValue;
    }
}

// 虚拟土地资产
[Serializable]
public class VirtualLandAsset : BlockchainAsset
{
    public VirtualLandAsset(string id, string owner) : base(id, owner, "VirtualLand")
    {
    }
    
    // 设置土地坐标
    public void SetCoordinates(int x, int y)
    {
        SetProperty("x", x);
        SetProperty("y", y);
    }
    
    // 设置土地尺寸
    public void SetSize(int width, int height)
    {
        SetProperty("width", width);
        SetProperty("height", height);
    }
    
    // 获取土地坐标X
    public int GetX()
    {
        return GetProperty<int>("x");
    }
    
    // 获取土地坐标Y
    public int GetY()
    {
        return GetProperty<int>("y");
    }
    
    // 获取土地宽度
    public int GetWidth()
    {
        return GetProperty<int>("width", 1);
    }
    
    // 获取土地高度
    public int GetHeight()
    {
        return GetProperty<int>("height", 1);
    }
}

// 虚拟物品资产
[Serializable]
public class VirtualItemAsset : BlockchainAsset
{
    public VirtualItemAsset(string id, string owner) : base(id, owner, "VirtualItem")
    {
    }
    
    // 设置物品类型
    public void SetItemType(string itemType)
    {
        SetProperty("itemType", itemType);
    }
    
    // 设置物品稀有度
    public void SetRarity(string rarity)
    {
        SetProperty("rarity", rarity);
    }
    
    // 获取物品类型
    public string GetItemType()
    {
        return GetProperty<string>("itemType", "unknown");
    }
    
    // 获取物品稀有度
    public string GetRarity()
    {
        return GetProperty<string>("rarity", "common");
    }
}

// 区块链交易记录
[Serializable]
public class BlockchainTransaction
{
    [SerializeField] private string transactionId;
    [SerializeField] private string fromAddress;
    [SerializeField] private string toAddress;
    [SerializeField] private string assetId;
    [SerializeField] private string transactionType;
    [SerializeField] private string timestamp;
    [SerializeField] private Dictionary<string, object> metadata = new Dictionary<string, object>();
    
    public string TransactionId => transactionId;
    public string FromAddress => fromAddress;
    public string ToAddress => toAddress;
    public string AssetId => assetId;
    public string TransactionType => transactionType;
    public string Timestamp => timestamp;
    public Dictionary<string, object> Metadata => metadata;
    
    public BlockchainTransaction(string id, string from, string to, string asset, string type)
    {
        transactionId = id;
        fromAddress = from;
        toAddress = to;
        assetId = asset;
        transactionType = type;
        timestamp = DateTime.UtcNow.ToString("o");
    }
    
    // 添加元数据
    public void AddMetadata(string key, object value)
    {
        metadata[key] = value;
    }
    
    // 获取交易签名
    public string GetSignature()
    {
        // 构建签名数据
        string dataToSign = $"{transactionId}|{fromAddress}|{toAddress}|{assetId}|{transactionType}|{timestamp}|{JsonConvert.SerializeObject(metadata)}";
        
        // 简化的签名实现
        byte[] dataBytes = Encoding.UTF8.GetBytes(dataToSign);
        using (SHA256 sha256 = SHA256.Create())
        {
            byte[] hashBytes = sha256.ComputeHash(dataBytes);
            return Convert.ToBase64String(hashBytes);
        }
    }
}

// 区块链服务接口
public interface IBlockchainService
{
    Task<bool> InitializeAsync(string userAddress, string privateKey);
    Task<BlockchainAsset> GetAssetAsync(string assetId);
    Task<bool> TransferAssetAsync(string assetId, string toAddress);
    Task<BlockchainAsset> CreateAssetAsync(string assetType, Dictionary<string, object> properties);
    Task<bool> UpdateAssetAsync(string assetId, Dictionary<string, object> properties);
    Task<List<BlockchainAsset>> GetUserAssetsAsync(string userAddress);
    Task<List<BlockchainTransaction>> GetAssetHistoryAsync(string assetId);
}

// 模拟区块链服务实现
public class MockBlockchainService : IBlockchainService
{
    private string _userAddress;
    private string _privateKey;
    private Dictionary<string, BlockchainAsset> _assets = new Dictionary<string, BlockchainAsset>();
    private Dictionary<string, List<BlockchainTransaction>> _transactions = new Dictionary<string, List<BlockchainTransaction>>();
    
    // 初始化区块链服务
    public Task<bool> InitializeAsync(string userAddress, string privateKey)
    {
        _userAddress = userAddress;
        _privateKey = privateKey;
        return Task.FromResult(true);
    }
    
    // 获取资产
    public Task<BlockchainAsset> GetAssetAsync(string assetId)
    {
        if (_assets.TryGetValue(assetId, out BlockchainAsset asset))
        {
            return Task.FromResult(asset);
        }
        return Task.FromResult<BlockchainAsset>(null);
    }
    
    // 转移资产
    public Task<bool> TransferAssetAsync(string assetId, string toAddress)
    {
        if (_assets.TryGetValue(assetId, out BlockchainAsset asset))
        {
            // 检查所有权
            if (asset.OwnerAddress != _userAddress)
            {
                return Task.FromResult(false);
            }
            
            // 创建新资产以更新所有者
            BlockchainAsset newAsset;
            if (asset is VirtualLandAsset landAsset)
            {
                newAsset = new VirtualLandAsset(assetId, toAddress);
                ((VirtualLandAsset)newAsset).SetCoordinates(landAsset.GetX(), landAsset.GetY());
                ((VirtualLandAsset)newAsset).SetSize(landAsset.GetWidth(), landAsset.GetHeight());
            }
            else if (asset is VirtualItemAsset itemAsset)
            {
                newAsset = new VirtualItemAsset(assetId, toAddress);
                ((VirtualItemAsset)newAsset).SetItemType(itemAsset.GetItemType());
                ((VirtualItemAsset)newAsset).SetRarity(itemAsset.GetRarity());
            }
            else
            {
                newAsset = new BlockchainAsset(assetId, toAddress, asset.AssetType);
            }
            
            // 复制所有属性
            foreach (var pair in asset.Properties)
            {
                newAsset.SetProperty(pair.Key, pair.Value);
            }
            
            // 更新资产
            _assets[assetId] = newAsset;
            
            // 记录交易
            string transactionId = Guid.NewGuid().ToString();
            BlockchainTransaction transaction = new BlockchainTransaction(
                transactionId, _userAddress, toAddress, assetId, "Transfer");
            
            if (!_transactions.ContainsKey(assetId))
            {
                _transactions[assetId] = new List<BlockchainTransaction>();
            }
            _transactions[assetId].Add(transaction);
            
            return Task.FromResult(true);
        }
        
        return Task.FromResult(false);
    }
    
    // 创建资产
    public Task<BlockchainAsset> CreateAssetAsync(string assetType, Dictionary<string, object> properties)
    {
        string assetId = Guid.NewGuid().ToString();
        
        BlockchainAsset asset;
        if (assetType == "VirtualLand")
        {
            asset = new VirtualLandAsset(assetId, _userAddress);
            
            if (properties.TryGetValue("x", out object x) && properties.TryGetValue("y", out object y))
            {
                ((VirtualLandAsset)asset).SetCoordinates(Convert.ToInt32(x), Convert.ToInt32(y));
            }
            
            if (properties.TryGetValue("width", out object width) && properties.TryGetValue("height", out object height))
            {
                ((VirtualLandAsset)asset).SetSize(Convert.ToInt32(width), Convert.ToInt32(height));
            }
        }
        else if (assetType == "VirtualItem")
        {
            asset = new VirtualItemAsset(assetId, _userAddress);
            
            if (properties.TryGetValue("itemType", out object itemType))
            {
                ((VirtualItemAsset)asset).SetItemType(itemType.ToString());
            }
            
            if (properties.TryGetValue("rarity", out object rarity))
            {
                ((VirtualItemAsset)asset).SetRarity(rarity.ToString());
            }
        }
        else
        {
            asset = new BlockchainAsset(assetId, _userAddress, assetType);
        }
        
        // 添加剩余的属性
        foreach (var pair in properties)
        {
            if (pair.Key != "x" && pair.Key != "y" && pair.Key != "width" && pair.Key != "height" && 
                pair.Key != "itemType" && pair.Key != "rarity")
            {
                asset.SetProperty(pair.Key, pair.Value);
            }
        }
        
        // 存储资产
        _assets[assetId] = asset;
        
        // 记录创建交易
        string transactionId = Guid.NewGuid().ToString();
        BlockchainTransaction transaction = new BlockchainTransaction(
            transactionId, "0x0000000000000000000000000000000000000000", _userAddress, assetId, "Create");
        
        if (!_transactions.ContainsKey(assetId))
        {
            _transactions[assetId] = new List<BlockchainTransaction>();
        }
        _transactions[assetId].Add(transaction);
        
        return Task.FromResult(asset);
    }
    
    // 更新资产
    public Task<bool> UpdateAssetAsync(string assetId, Dictionary<string, object> properties)
    {
        if (_assets.TryGetValue(assetId, out BlockchainAsset asset))
        {
            // 检查所有权
            if (asset.OwnerAddress != _userAddress)
            {
                return Task.FromResult(false);
            }
            
            // 更新属性
            foreach (var pair in properties)
            {
                asset.SetProperty(pair.Key, pair.Value);
            }
            
            // 记录更新交易
            string transactionId = Guid.NewGuid().ToString();
            BlockchainTransaction transaction = new BlockchainTransaction(
                transactionId, _userAddress, _userAddress, assetId, "Update");
                
            foreach (var pair in properties)
            {
                transaction.AddMetadata(pair.Key, pair.Value);
            }
            
            if (!_transactions.ContainsKey(assetId))
            {
                _transactions[assetId] = new List<BlockchainTransaction>();
            }
            _transactions[assetId].Add(transaction);
            
            return Task.FromResult(true);
        }
        
        return Task.FromResult(false);
    }
    
    // 获取用户资产
    public Task<List<BlockchainAsset>> GetUserAssetsAsync(string userAddress)
    {
        List<BlockchainAsset> userAssets = new List<BlockchainAsset>();
        
        foreach (var asset in _assets.Values)
        {
            if (asset.OwnerAddress == userAddress)
            {
                userAssets.Add(asset);
            }
        }
        
        return Task.FromResult(userAssets);
    }
    
    // 获取资产历史
    public Task<List<BlockchainTransaction>> GetAssetHistoryAsync(string assetId)
    {
        if (_transactions.TryGetValue(assetId, out List<BlockchainTransaction> history))
        {
            return Task.FromResult(history);
        }
        
        return Task.FromResult(new List<BlockchainTransaction>());
    }
}

// 实际区块链服务实现 (与具体区块链集成)
public class EthereumBlockchainService : IBlockchainService
{
    private string _userAddress;
    private string _privateKey;
    private string _nodeUrl;
    private string _contractAddress;
    
    // 构造函数
    public EthereumBlockchainService(string nodeUrl, string contractAddress)
    {
        _nodeUrl = nodeUrl;
        _contractAddress = contractAddress;
    }
    
    // 初始化区块链服务
    public async Task<bool> InitializeAsync(string userAddress, string privateKey)
    {
        _userAddress = userAddress;
        _privateKey = privateKey;
        
        // 检查连接性
        bool isConnected = await CheckConnectionAsync();
        return isConnected;
    }
    
    // 检查连接性
    private async Task<bool> CheckConnectionAsync()
    {
        // 构建API请求检查节点连接性
        using (UnityWebRequest request = UnityWebRequest.Get(_nodeUrl))
        {
            await request.SendWebRequest();
            return !request.isNetworkError && !request.isHttpError;
        }
    }
    
    // 获取资产
    public async Task<BlockchainAsset> GetAssetAsync(string assetId)
    {
        // 构建API请求以获取资产数据
        string url = $"{_nodeUrl}/api/assets/{assetId}";
        
        using (UnityWebRequest request = UnityWebRequest.Get(url))
        {
            await request.SendWebRequest();
            
            if (request.isNetworkError || request.isHttpError)
            {
                Debug.LogError($"Failed to fetch asset: {request.error}");
                return null;
            }
            
            string json = request.downloadHandler.text;
            return JsonConvert.DeserializeObject<BlockchainAsset>(json);
        }
    }
    
    // 转移资产
    public async Task<bool> TransferAssetAsync(string assetId, string toAddress)
    {
        // 构建交易数据
        Dictionary<string, object> transactionData = new Dictionary<string, object>
        {
            { "from", _userAddress },
            { "to", toAddress },
            { "assetId", assetId },
            { "action", "transfer" }
        };
        
        // 序列化交易数据
        string json = JsonConvert.SerializeObject(transactionData);
        
        // 构建API请求
        string url = $"{_nodeUrl}/api/transactions";
        
        using (UnityWebRequest request = UnityWebRequest.Post(url, "POST"))
        {
            byte[] bodyRaw = Encoding.UTF8.GetBytes(json);
            request.uploadHandler = new UploadHandlerRaw(bodyRaw);
            request.downloadHandler = new DownloadHandlerBuffer();
            request.SetRequestHeader("Content-Type", "application/json");
            request.SetRequestHeader("Authorization", $"Bearer {_privateKey}");
            
            await request.SendWebRequest();
            
            if (request.isNetworkError || request.isHttpError)
            {
                Debug.LogError($"Transfer failed: {request.error}");
                return false;
            }
            
            return true;
        }
    }
    
    // 创建资产
    public async Task<BlockchainAsset> CreateAssetAsync(string assetType, Dictionary<string, object> properties)
    {
        // 构建创建资产的数据
        Dictionary<string, object> assetData = new Dictionary<string, object>
        {
            { "owner", _userAddress },
            { "type", assetType },
            { "properties", properties }
        };
        
        // 序列化数据
        string json = JsonConvert.SerializeObject(assetData);
        
        // 构建API请求
        string url = $"{_nodeUrl}/api/assets";
        
        using (UnityWebRequest request = UnityWebRequest.Post(url, "POST"))
        {
            byte[] bodyRaw = Encoding.UTF8.GetBytes(json);
            request.uploadHandler = new UploadHandlerRaw(bodyRaw);
            request.downloadHandler = new DownloadHandlerBuffer();
            request.SetRequestHeader("Content-Type", "application/json");
            request.SetRequestHeader("Authorization", $"Bearer {_privateKey}");
            
            await request.SendWebRequest();
            
            if (request.isNetworkError || request.isHttpError)
            {
                Debug.LogError($"Create asset failed: {request.error}");
                return null;
            }
            
            string responseJson = request.downloadHandler.text;
            return JsonConvert.DeserializeObject<BlockchainAsset>(responseJson);
        }
    }
    
    // 更新资产
    public async Task<bool> UpdateAssetAsync(string assetId, Dictionary<string, object> properties)
    {
        // 构建更新资产的数据
        Dictionary<string, object> updateData = new Dictionary<string, object>
        {
            { "owner", _userAddress },
            { "properties", properties }
        };
        
        // 序列化数据
        string json = JsonConvert.SerializeObject(updateData);
        
        // 构建API请求
        string url = $"{_nodeUrl}/api/assets/{assetId}";
        
        using (UnityWebRequest request = UnityWebRequest.Put(url, json))
        {
            byte[] bodyRaw = Encoding.UTF8.GetBytes(json);
            request.uploadHandler = new UploadHandlerRaw(bodyRaw);
            request.downloadHandler = new DownloadHandlerBuffer();
            request.SetRequestHeader("Content-Type", "application/json");
            request.SetRequestHeader("Authorization", $"Bearer {_privateKey}");
            
            await request.SendWebRequest();
            
            if (request.isNetworkError || request.isHttpError)
            {
                Debug.LogError($"Update asset failed: {request.error}");
                return false;
            }
            
            return true;
        }
    }
    
    // 获取用户资产
    public async Task<List<BlockchainAsset>> GetUserAssetsAsync(string userAddress)
    {
        // 构建API请求以获取用户资产
        string url = $"{_nodeUrl}/api/users/{userAddress}/assets";
        
        using (UnityWebRequest request = UnityWebRequest.Get(url))
        {
            await request.SendWebRequest();
            
            if (request.isNetworkError || request.isHttpError)
            {
                Debug.LogError($"Failed to fetch user assets: {request.error}");
                return new List<BlockchainAsset>();
            }
            
            string json = request.downloadHandler.text;
            return JsonConvert.DeserializeObject<List<BlockchainAsset>>(json);
        }
    }
    
    // 获取资产历史
    public async Task<List<BlockchainTransaction>> GetAssetHistoryAsync(string assetId)
    {
        // 构建API请求以获取资产交易历史
        string url = $"{_nodeUrl}/api/assets/{assetId}/history";
        
        using (UnityWebRequest request = UnityWebRequest.Get(url))
        {
            await request.SendWebRequest();
            
            if (request.isNetworkError || request.isHttpError)
            {
                Debug.LogError($"Failed to fetch asset history: {request.error}");
                return new List<BlockchainTransaction>();
            }
            
            string json = request.downloadHandler.text;
            return JsonConvert.DeserializeObject<List<BlockchainTransaction>>(json);
        }
    }
}

// 持久化世界管理器
public class PersistentWorldManager : MonoBehaviour
{
    [Header("Blockchain Settings")]
    [SerializeField] private bool useMockBlockchain = true;
    [SerializeField] private string nodeUrl = "https://api.example.org/blockchain";
    [SerializeField] private string contractAddress = "0x1234567890123456789012345678901234567890";
    
    [Header("User Settings")]
    [SerializeField] private string userAddress = "0xMyUserAddress";
    [SerializeField] private string privateKey = "MyPrivateKey";
    
    [Header("World Settings")]
    [SerializeField] private int worldSizeX = 100;
    [SerializeField] private int worldSizeY = 100;
    [SerializeField] private GameObject landPrefab;
    [SerializeField] private GameObject buildingPrefab;
    [SerializeField] private GameObject itemPrefab;
    
    // 区块链服务
    private IBlockchainService _blockchainService;
    
    // 世界网格
    private Dictionary<Vector2Int, GameObject> _worldGrid = new Dictionary<Vector2Int, GameObject>();
    
    // 用户拥有的资产
    private List<BlockchainAsset> _userAssets = new List<BlockchainAsset>();
    
    // 是否已初始化
    private bool _isInitialized = false;
    
    private async void Start()
    {
        // 初始化区块链服务
        if (useMockBlockchain)
        {
            _blockchainService = new MockBlockchainService();
        }
        else
        {
            _blockchainService = new EthereumBlockchainService(nodeUrl, contractAddress);
        }
        
        // 初始化服务
        bool initialized = await _blockchainService.InitializeAsync(userAddress, privateKey);
        
        if (!initialized)
        {
            Debug.LogError("Failed to initialize blockchain service");
            return;
        }
        
        _isInitialized = true;
        
        // 加载用户资产
        await LoadUserAssetsAsync();
        
        // 构建初始世界
        BuildWorld();
    }
    
    // 加载用户资产
    private async Task LoadUserAssetsAsync()
    {
        if (!_isInitialized)
            return;
            
        _userAssets = await _blockchainService.GetUserAssetsAsync(userAddress);
        Debug.Log($"Loaded {_userAssets.Count} assets for user {userAddress}");
    }
    
    // 构建世界
    private void BuildWorld()
    {
        // 清除现有世界
        foreach (var obj in _worldGrid.Values)
        {
            Destroy(obj);
        }
        _worldGrid.Clear();
        
        // 根据用户拥有的土地资产构建世界
        foreach (var asset in _userAssets)
        {
            if (asset.AssetType == "VirtualLand" && asset is VirtualLandAsset landAsset)
            {
                // 获取土地坐标和尺寸
                int x = landAsset.GetX();
                int y = landAsset.GetY();
                int width = landAsset.GetWidth();
                int height = landAsset.GetHeight();
                
                // 实例化土地
                for (int dx = 0; dx < width; dx++)
                {
                    for (int dy = 0; dy < height; dy++)
                    {
                        Vector2Int gridPos = new Vector2Int(x + dx, y + dy);
                        Vector3 worldPos = new Vector3(gridPos.x * 10, 0, gridPos.y * 10);
                        
                        if (!_worldGrid.ContainsKey(gridPos))
                        {
                            GameObject landObj = Instantiate(landPrefab, worldPos, Quaternion.identity);
                            landObj.name = $"Land_{gridPos.x}_{gridPos.y}";
                            
                            // 添加持久性组件
                            PersistentObject persistentObj = landObj.AddComponent<PersistentObject>();
                            persistentObj.Initialize(landAsset);
                            
                            _worldGrid[gridPos] = landObj;
                        }
                    }
                }
            }
        }
        
        // 加载建筑物和物品
        foreach (var asset in _userAssets)
        {
            if (asset.AssetType == "Building")
            {
                int x = asset.GetProperty<int>("x");
                int y = asset.GetProperty<int>("y");
                Vector2Int gridPos = new Vector2Int(x, y);
                
                if (_worldGrid.ContainsKey(gridPos))
                {
                    Vector3 worldPos = _worldGrid[gridPos].transform.position + Vector3.up * 0.5f;
                    
                    GameObject buildingObj = Instantiate(buildingPrefab, worldPos, Quaternion.identity);
                    buildingObj.name = $"Building_{asset.AssetId}";
                    
                    // 添加持久性组件
                    PersistentObject persistentObj = buildingObj.AddComponent<PersistentObject>();
                    persistentObj.Initialize(asset);
                }
            }
            else if (asset.AssetType == "VirtualItem" && asset is VirtualItemAsset itemAsset)
            {
                // 检查物品是否放置在世界中
                if (asset.Properties.ContainsKey("x") && asset.Properties.ContainsKey("y"))
                {
                    int x = asset.GetProperty<int>("x");
                    int y = asset.GetProperty<int>("y");
                    Vector2Int gridPos = new Vector2Int(x, y);
                    
                    if (_worldGrid.ContainsKey(gridPos))
                    {
                        Vector3 worldPos = _worldGrid[gridPos].transform.position + Vector3.up * 1.0f;
                        
                        GameObject itemObj = Instantiate(itemPrefab, worldPos, Quaternion.identity);
                        itemObj.name = $"Item_{asset.AssetId}";
                        
                        // 根据物品类型自定义外观
                        CustomizeItemAppearance(itemObj, itemAsset);
                        
                        // 添加持久性组件
                        PersistentObject persistentObj = itemObj.AddComponent<PersistentObject>();
                        persistentObj.Initialize(asset);
                    }
                }
            }
        }
    }
    
    // 自定义物品外观
    private void CustomizeItemAppearance(GameObject itemObj, VirtualItemAsset itemAsset)
    {
        string itemType = itemAsset.GetItemType();
        string rarity = itemAsset.GetRarity();
        
        // 获取渲染器组件
        Renderer renderer = itemObj.GetComponent<Renderer>();
        if (renderer != null)
        {
            // 根据稀有度设置颜色
            switch (rarity.ToLower())
            {
                case "common":
                    renderer.material.color = Color.white;
                    break;
                case "uncommon":
                    renderer.material.color = Color.green;
                    break;
                case "rare":
                    renderer.material.color = Color.blue;
                    break;
                case "epic":
                    renderer.material.color = Color.magenta;
                    break;
                case "legendary":
                    renderer.material.color = Color.yellow;
                    break;
                default:
                    renderer.material.color = Color.gray;
                    break;
            }
        }
        
        // 根据物品类型设置比例或其他属性
        switch (itemType.ToLower())
        {
            case "weapon":
                itemObj.transform.localScale = new Vector3(0.2f, 1.0f, 0.2f);
                break;
            case "armor":
                itemObj.transform.localScale = new Vector3(0.5f, 0.7f, 0.5f);
                break;
            case "potion":
                itemObj.transform.localScale = new Vector3(0.3f, 0.5f, 0.3f);
                break;
            default:
                itemObj.transform.localScale = Vector3.one * 0.5f;
                break;
        }
    }
    
    // 购买新的土地
    public async Task<bool> PurchaseLandAsync(int x, int y, int width, int height)
    {
        if (!_isInitialized)
            return false;
            
        // 创建属性字典
        Dictionary<string, object> properties = new Dictionary<string, object>
        {
            { "x", x },
            { "y", y },
            { "width", width },
            { "height", height }
        };
        
        // 创建新的土地资产
        BlockchainAsset newLand = await _blockchainService.CreateAssetAsync("VirtualLand", properties);
        
        if (newLand != null)
        {
            // 添加到用户资产列表
            _userAssets.Add(newLand);
            
            // 更新世界
            BuildWorld();
            
            return true;
        }
        
        return false;
    }
    
    // 放置建筑物
    public async Task<bool> PlaceBuildingAsync(int x, int y, string buildingType)
    {
        if (!_isInitialized)
            return false;
            
        // 检查用户是否拥有该位置的土地
        Vector2Int gridPos = new Vector2Int(x, y);
        bool ownsTile = false;
        
        foreach (var asset in _userAssets)
        {
            if (asset.AssetType == "VirtualLand" && asset is VirtualLandAsset landAsset)
            {
                int landX = landAsset.GetX();
                int landY = landAsset.GetY();
                int width = landAsset.GetWidth();
                int height = landAsset.GetHeight();
                
                if (x >= landX && x < landX + width && y >= landY && y < landY + height)
                {
                    ownsTile = true;
                    break;
                }
            }
        }
        
        if (!ownsTile)
        {
            Debug.LogError($"User does not own the land at position ({x}, {y})");
            return false;
        }
        
        // 创建属性字典
        Dictionary<string, object> properties = new Dictionary<string, object>
        {
            { "x", x },
            { "y", y },
            { "buildingType", buildingType }
        };
        
        // 创建新的建筑物资产
        BlockchainAsset newBuilding = await _blockchainService.CreateAssetAsync("Building", properties);
        
        if (newBuilding != null)
        {
            // 添加到用户资产列表
            _userAssets.Add(newBuilding);
            
            // 更新世界
            BuildWorld();
            
            return true;
        }
        
        return false;
    }
    
    // 放置物品
    public async Task<bool> PlaceItemAsync(int x, int y, string itemType, string rarity)
    {
        if (!_isInitialized)
            return false;
            
        // 检查用户是否拥有该位置的土地
        Vector2Int gridPos = new Vector2Int(x, y);
        bool ownsTile = false;
        
        foreach (var asset in _userAssets)
        {
            if (asset.AssetType == "VirtualLand" && asset is VirtualLandAsset landAsset)
            {
                int landX = landAsset.GetX();
                int landY = landAsset.GetY();
                int width = landAsset.GetWidth();
                int height = landAsset.GetHeight();
                
                if (x >= landX && x < landX + width && y >= landY && y < landY + height)
                {
                    ownsTile = true;
                    break;
                }
            }
        }
        
        if (!ownsTile)
        {
            Debug.LogError($"User does not own the land at position ({x}, {y})");
            return false;
        }
        
        // 创建属性字典
        Dictionary<string, object> properties = new Dictionary<string, object>
        {
            { "x", x },
            { "y", y },
            { "itemType", itemType },
            { "rarity", rarity }
        };
        
        // 创建新的物品资产
        BlockchainAsset newItem = await _blockchainService.CreateAssetAsync("VirtualItem", properties);
        
        if (newItem != null)
        {
            // 添加到用户资产列表
            _userAssets.Add(newItem);
            
            // 更新世界
            BuildWorld();
            
            return true;
        }
        
        return false;
    }
    
    // 转移资产
    public async Task<bool> TransferAssetAsync(string assetId, string toAddress)
    {
        if (!_isInitialized)
            return false;
            
        bool success = await _blockchainService.TransferAssetAsync(assetId, toAddress);
        
        if (success)
        {
            // 从用户资产列表中移除
            _userAssets.RemoveAll(a => a.AssetId == assetId);
            
            // 更新世界
            BuildWorld();
        }
        
        return success;
    }
    
    // 更新资产属性
    public async Task<bool> UpdateAssetPropertiesAsync(string assetId, Dictionary<string, object> properties)
    {
        if (!_isInitialized)
            return false;
            
        bool success = await _blockchainService.UpdateAssetAsync(assetId, properties);
        
        if (success)
        {
            // 刷新用户资产
            await LoadUserAssetsAsync();
            
            // 更新世界
            BuildWorld();
        }
        
        return success;
    }
    
    // 获取资产历史
    public async Task<List<BlockchainTransaction>> GetAssetHistoryAsync(string assetId)
    {
        if (!_isInitialized)
            return new List<BlockchainTransaction>();
            
        return await _blockchainService.GetAssetHistoryAsync(assetId);
    }
}

// 持久性对象组件
public class PersistentObject : MonoBehaviour
{
    // 关联的区块链资产
    private BlockchainAsset _asset;
    
    // 初始化
    public void Initialize(BlockchainAsset asset)
    {
        _asset = asset;
        
        // 根据资产类型设置组件行为
        SetupBehaviorByAssetType();
    }
    
    // 根据资产类型设置行为
    private void SetupBehaviorByAssetType()
    {
        if (_asset.AssetType == "VirtualLand")
        {
            // 为土地添加适当的组件
            gameObject.AddComponent<LandBehavior>();
        }
        else if (_asset.AssetType == "Building")
        {
            // 为建筑添加适当的组件
            BuildingBehavior building = gameObject.AddComponent<BuildingBehavior>();
            building.Initialize(_asset.GetProperty<string>("buildingType", "default"));
        }
        else if (_asset.AssetType == "VirtualItem" && _asset is VirtualItemAsset itemAsset)
        {
            // 为物品添加适当的组件
            ItemBehavior item = gameObject.AddComponent<ItemBehavior>();
            item.Initialize(itemAsset.GetItemType(), itemAsset.GetRarity());
        }
    }
    
    // 获取资产ID
    public string GetAssetId()
    {
        return _asset?.AssetId;
    }
    
    // 获取资产
    public BlockchainAsset GetAsset()
    {
        return _asset;
    }
}

// 土地行为组件
public class LandBehavior : MonoBehaviour
{
    private void OnMouseDown()
    {
        // 处理土地点击事件
        Debug.Log($"Land clicked: {gameObject.name}");
    }
}

// 建筑行为组件
public class BuildingBehavior : MonoBehaviour
{
    private string _buildingType;
    
    public void Initialize(string buildingType)
    {
        _buildingType = buildingType;
        
        // 根据建筑类型设置外观
        SetupAppearance();
    }
    
    private void SetupAppearance()
    {
        // 设置建筑外观
        // 在实际实现中,可能会加载不同的模型或材质
    }
    
    private void OnMouseDown()
    {
        // 处理建筑点击事件
        Debug.Log($"Building clicked: {gameObject.name} (Type: {_buildingType})");
    }
}

// 物品行为组件
public class ItemBehavior : MonoBehaviour
{
    private string _itemType;
    private string _rarity;
    
    public void Initialize(string itemType, string rarity)
    {
        _itemType = itemType;
        _rarity = rarity;
        
        // 根据物品类型和稀有度设置行为
        SetupBehavior();
    }
    
    private void SetupBehavior()
    {
        // 设置物品行为
        // 在实际实现中,可能会根据物品类型添加不同的交互组件
    }
    
    private void OnMouseDown()
    {
        // 处理物品点击事件
        Debug.Log($"Item clicked: {gameObject.name} (Type: {_itemType}, Rarity: {_rarity})");
    }
}

25. 高级用户界面与交互系统

25.1 虚拟现实交互框架

csharp

// 虚拟现实交互框架
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR;
using UnityEngine.XR.Interaction.Toolkit;

// 手部跟踪数据结构
public struct HandTrackingData
{
    public Transform wristTransform;
    public Transform thumbProximal;
    public Transform thumbIntermediate;
    public Transform thumbDistal;
    public Transform thumbTip;
    public Transform indexProximal;
    public Transform indexIntermediate;
    public Transform indexDistal;
    public Transform indexTip;
    public Transform middleProximal;
    public Transform middleIntermediate;
    public Transform middleDistal;
    public Transform middleTip;
    public Transform ringProximal;
    public Transform ringIntermediate;
    public Transform ringDistal;
    public Transform ringTip;
    public Transform pinkyProximal;
    public Transform pinkyIntermediate;
    public Transform pinkyDistal;
    public Transform pinkyTip;
    
    // 手指弯曲度 (0-1,0为伸直,1为完全弯曲)
    public float thumbCurl;
    public float indexCurl;
    public float middleCurl;
    public float ringCurl;
    public float pinkyCurl;
    
    // 手掌朝向
    public Vector3 palmNormal;
    public Vector3 palmDirection;
}

// 手势识别器接口
public interface IGestureRecognizer
{
    bool RecognizeGesture(HandTrackingData handData, out string gestureName, out float confidence);
    void AddGesture(string name, List<HandTrackingData> samples);
    void RemoveGesture(string name);
    void ClearGestures();
}

// 基于手指弯曲的简单手势识别器
public class FingerCurlGestureRecognizer : IGestureRecognizer
{
    // 手势定义
    private class GestureDefinition
    {
        public string name;
        public Vector5 curlPattern; // 使用Vector5存储5个手指的弯曲模式
        public float threshold;  // 匹配阈值
        
        public GestureDefinition(string name, Vector5 curlPattern, float threshold = 0.2f)
        {
            this.name = name;
            this.curlPattern = curlPattern;
            this.threshold = threshold;
        }
    }
    
    private List<GestureDefinition> _gestures = new List<GestureDefinition>();
    
    // 构造函数 - 添加默认手势
    public FingerCurlGestureRecognizer()
    {
        // 添加一些常见手势
        
        // 握拳 - 所有手指都弯曲
        _gestures.Add(new GestureDefinition("Fist", new Vector5(1, 1, 1, 1, 1)));
        
        // 指向 - 食指伸直,其他手指弯曲
        _gestures.Add(new GestureDefinition("Point", new Vector5(1, 0, 1, 1, 1)));
        
        // 大拇指向上 - 拇指伸直,其他手指弯曲
        _gestures.Add(new GestureDefinition("ThumbsUp", new Vector5(0, 1, 1, 1, 1)));
        
        // 手掌张开 - 所有手指伸直
        _gestures.Add(new GestureDefinition("OpenPalm", new Vector5(0, 0, 0, 0, 0)));
        
        // 手枪形状 - 食指伸直,拇指伸直,其他弯曲
        _gestures.Add(new GestureDefinition("Gun", new Vector5(0, 0, 1, 1, 1)));
        
        // OK手势 - 拇指和食指接触,其他手指伸展
        _gestures.Add(new GestureDefinition("OK", new Vector5(0.5f, 0.5f, 0, 0, 0)));
    }
    
    // 识别手势
    public bool RecognizeGesture(HandTrackingData handData, out string gestureName, out float confidence)
    {
        gestureName = string.Empty;
        confidence = 0f;
        
        // 从手部数据中提取手指弯曲信息
        Vector5 currentCurl = new Vector5(
            handData.thumbCurl,
            handData.indexCurl,
            handData.middleCurl,
            handData.ringCurl,
            handData.pinkyCurl
        );
        
        // 检查每个已注册的手势
        float bestMatch = float.MaxValue;
        
        foreach (var gesture in _gestures)
        {
            // 计算当前手指弯曲与手势模式的差异
            float diff = Vector5.Distance(currentCurl, gesture.curlPattern);
            
            if (diff < bestMatch && diff < gesture.threshold)
            {
                bestMatch = diff;
                gestureName = gesture.name;
                confidence = 1f - (diff / gesture.threshold);
            }
        }
        
        return !string.IsNullOrEmpty(gestureName);
    }
    
    // 添加新手势
    public void AddGesture(string name, List<HandTrackingData> samples)
    {
        if (samples == null || samples.Count == 0)
            return;
            
        // 计算所有样本的平均弯曲值
        Vector5 averageCurl = Vector5.zero;
        
        foreach (var sample in samples)
        {
            averageCurl.x += sample.thumbCurl;
            averageCurl.y += sample.indexCurl;
            averageCurl.z += sample.middleCurl;
            averageCurl.w += sample.ringCurl;
            averageCurl.v += sample.pinkyCurl;
        }
        
        averageCurl.x /= samples.Count;
        averageCurl.y /= samples.Count;
        averageCurl.z /= samples.Count;
        averageCurl.w /= samples.Count;
        averageCurl.v /= samples.Count;
        
        // 移除同名的现有手势
        _gestures.RemoveAll(g => g.name == name);
        
        // 添加新手势
        _gestures.Add(new GestureDefinition(name, averageCurl));
    }
    
    // 移除手势
    public void RemoveGesture(string name)
    {
        _gestures.RemoveAll(g => g.name == name);
    }
    
    // 清除所有手势
    public void ClearGestures()
    {
        _gestures.Clear();
    }
}

// 自定义Vector5结构
public struct Vector5
{
    public float x, y, z, w, v;
    
    public Vector5(float x, float y, float z, float w, float v)
    {
        this.x = x;
        this.y = y;
        this.z = z;
        this.w = w;
        this.v = v;
    }
    
    public static Vector5 zero => new Vector5(0, 0, 0, 0, 0);
    
    // 计算两个Vector5之间的欧几里得距离
    public static float Distance(Vector5 a, Vector5 b)
    {
        float dx = a.x - b.x;
        float dy = a.y - b.y;
        float dz = a.z - b.z;
        float dw = a.w - b.w;
        float dv = a.v - b.v;
        
        return Mathf.Sqrt(dx * dx + dy * dy + dz * dz + dw * dw + dv * dv);
    }
}

// VR交互管理器
public class VRInteractionManager : MonoBehaviour
{
    [Header("References")]
    [SerializeField] private XRController leftController;
    [SerializeField] private XRController rightController;
    [SerializeField] private GameObject leftHandModel;
    [SerializeField] private GameObject rightHandModel;
    
    [Header("Interaction Settings")]
    [SerializeField] private float grabThreshold = 0.5f;
    [SerializeField] private float pinchThreshold = 0.3f;
    [SerializeField] private float pointThreshold = 0.1f;
    [SerializeField] private float raycastDistance = 10f;
    [SerializeField] private LayerMask interactableLayers;
    
    [Header("Haptic Feedback")]
    [SerializeField] private float hapticAmplitude = 0.5f;
    [SerializeField] private float hapticDuration = 0.1f;
    
    // 手部跟踪数据
    private HandTrackingData _leftHandData;
    private HandTrackingData _rightHandData;
    
    // 手势识别器
    private IGestureRecognizer _gestureRecognizer;
    
    // 当前交互对象
    private Dictionary<InteractionHand, IVRInteractable> _currentInteractables = new Dictionary<InteractionHand, IVRInteractable>();
    
    // 手部枚举
    public enum InteractionHand
    {
        Left,
        Right
    }
    
    private void Awake()
    {
        // 初始化手势识别器
        _gestureRecognizer = new FingerCurlGestureRecognizer();
        
        // 初始化交互字典
        _currentInteractables[InteractionHand.Left] = null;
        _currentInteractables[InteractionHand.Right] = null;
        
        // 确保手模型设置正确
        if (leftHandModel != null)
        {
            InitializeHandModel(leftHandModel, ref _leftHandData);
        }
        
        if (rightHandModel != null)
        {
            InitializeHandModel(rightHandModel, ref _rightHandData);
        }
    }
    
    private void Update()
    {
        // 更新手部追踪数据
        if (leftHandModel != null)
        {
            UpdateHandData(leftHandModel, ref _leftHandData);
            ProcessHandInteractions(InteractionHand.Left, _leftHandData);
        }
        
        if (rightHandModel != null)
        {
            UpdateHandData(rightHandModel, ref _rightHandData);
            ProcessHandInteractions(InteractionHand.Right, _rightHandData);
        }
    }
    
    // 初始化手部模型引用
    private void InitializeHandModel(GameObject handModel, ref HandTrackingData handData)
    {
        // 查找所有手部骨骼
        Transform wrist = FindChildRecursive(handModel.transform, "Wrist");
        
        if (wrist != null)
        {
            handData.wristTransform = wrist;
            
            // 初始化拇指骨骼
            handData.thumbProximal = FindChildRecursive(wrist, "Thumb_Proximal");
            handData.thumbIntermediate = FindChildRecursive(wrist, "Thumb_Intermediate");
            handData.thumbDistal = FindChildRecursive(wrist, "Thumb_Distal");
            handData.thumbTip = FindChildRecursive(wrist, "Thumb_Tip");
            
            // 初始化食指骨骼
            handData.indexProximal = FindChildRecursive(wrist, "Index_Proximal");
            handData.indexIntermediate = FindChildRecursive(wrist, "Index_Intermediate");
            handData.indexDistal = FindChildRecursive(wrist, "Index_Distal");
            handData.indexTip = FindChildRecursive(wrist, "Index_Tip");
            
            // 初始化中指骨骼
            handData.middleProximal = FindChildRecursive(wrist, "Middle_Proximal");
            handData.middleIntermediate = FindChildRecursive(wrist, "Middle_Intermediate");
            handData.middleDistal = FindChildRecursive(wrist, "Middle_Distal");
            handData.middleTip = FindChildRecursive(wrist, "Middle_Tip");
            
            // 初始化无名指骨骼
            handData.ringProximal = FindChildRecursive(wrist, "Ring_Proximal");
            handData.ringIntermediate = FindChildRecursive(wrist, "Ring_Intermediate");
            handData.ringDistal = FindChildRecursive(wrist, "Ring_Distal");
            handData.ringTip = FindChildRecursive(wrist, "Ring_Tip");
            
            // 初始化小指骨骼
            handData.pinkyProximal = FindChildRecursive(wrist, "Pinky_Proximal");
            handData.pinkyIntermediate = FindChildRecursive(wrist, "Pinky_Intermediate");
            handData.pinkyDistal = FindChildRecursive(wrist, "Pinky_Distal");
            handData.pinkyTip = FindChildRecursive(wrist, "Pinky_Tip");
        }
    }
    
    // 递归查找子物体
    private Transform FindChildRecursive(Transform parent, string name)
    {
        if (parent == null)
            return null;
            
        for (int i = 0; i < parent.childCount; i++)
        {
            Transform child = parent.GetChild(i);
            if (child.name.Contains(name))
                return child;
                
            Transform found = FindChildRecursive(child, name);
            if (found != null)
                return found;
        }
        
        return null;
    }
    
    // 更新手部追踪数据
    private void UpdateHandData(GameObject handModel, ref HandTrackingData handData)
    {
        if (handData.wristTransform == null)
            return;
            
        // 计算手掌朝向
        if (handData.indexProximal != null && handData.pinkyProximal != null && handData.wristTransform != null)
        {
            Vector3 indexToWrist = handData.wristTransform.position - handData.indexProximal.position;
            Vector3 pinkyToWrist = handData.wristTransform.position - handData.pinkyProximal.position;
            
            handData.palmNormal = Vector3.Cross(indexToWrist, pinkyToWrist).normalized;
            handData.palmDirection = Vector3.Cross(handData.palmNormal, Vector3.up).normalized;
        }
        
        // 计算手指弯曲度
        handData.thumbCurl = CalculateFingerCurl(handData.thumbProximal, handData.thumbIntermediate, handData.thumbDistal, handData.thumbTip);
        handData.indexCurl = CalculateFingerCurl(handData.indexProximal, handData.indexIntermediate, handData.indexDistal, handData.indexTip);
        handData.middleCurl = CalculateFingerCurl(handData.middleProximal, handData.middleIntermediate, handData.middleDistal, handData.middleTip);
        handData.ringCurl = CalculateFingerCurl(handData.ringProximal, handData.ringIntermediate, handData.ringDistal, handData.ringTip);
        handData.pinkyCurl = CalculateFingerCurl(handData.pinkyProximal, handData.pinkyIntermediate, handData.pinkyDistal, handData.pinkyTip);
    }
    
    // 计算手指弯曲度 (0-1)
    private float CalculateFingerCurl(Transform proximal, Transform intermediate, Transform distal, Transform tip)
    {
        if (proximal == null || intermediate == null || distal == null)
            return 0f;
            
        // 计算手指骨骼之间的角度
        float angle1 = Vector3.Angle(intermediate.position - proximal.position, distal.position - intermediate.position);
        float angle2 = tip != null ? Vector3.Angle(distal.position - intermediate.position, tip.position - distal.position) : 0f;
        
        // 根据角度计算弯曲度
        float maxAngle = 80f;  // 假设最大弯曲角度为80度
        return Mathf.Clamp01((angle1 + angle2) / (2f * maxAngle));
    }
    
    // 处理手部交互
    private void ProcessHandInteractions(InteractionHand hand, HandTrackingData handData)
    {
        // 识别手势
        string gestureName;
        float confidence;
        bool gestureRecognized = _gestureRecognizer.RecognizeGesture(handData, out gestureName, out confidence);
        
        // 获取控制器
        XRController controller = (hand == InteractionHand.Left) ? leftController : rightController;
        
        // 处理不同的手势和交互
        if (gestureRecognized)
        {
            switch (gestureName)
            {
                case "Point":
                    ProcessPointingInteraction(hand, handData, controller);
                    break;
                    
                case "Fist":
                case "Grab":
                    ProcessGrabInteraction(hand, handData, controller);
                    break;
                    
                case "Pinch":
                    ProcessPinchInteraction(hand, handData, controller);
                    break;
                    
                case "OpenPalm":
                    ProcessReleaseInteraction(hand, handData, controller);
                    break;
                    
                default:
                    CheckControllerButtons(hand, controller);
                    break;
            }
        }
        else
        {
            // 如果没有识别出特定手势,检查控制器按钮输入
            CheckControllerButtons(hand, controller);
        }
    }
    
    // 处理指向交互
    private void ProcessPointingInteraction(InteractionHand hand, HandTrackingData handData, XRController controller)
    {
        // 创建射线,从食指尖端向前
        Vector3 rayOrigin = handData.indexTip.position;
        Vector3 rayDirection = handData.indexTip.forward;
        
        Debug.DrawRay(rayOrigin, rayDirection * raycastDistance, Color.blue);
        
        // 执行射线检测
        RaycastHit hit;
        if (Physics.Raycast(rayOrigin, rayDirection, out hit, raycastDistance, interactableLayers))
        {
            // 尝试获取可交互对象
            IVRInteractable interactable = hit.collider.GetComponent<IVRInteractable>();
            
            if (interactable != null)
            {
                // 调用悬停事件
                interactable.OnHover(hand);
                
                // 如果按下触发按钮,尝试激活对象
                if (controller != null && controller.inputDevice.TryGetFeatureValue(CommonUsages.triggerButton, out bool triggerPressed) && triggerPressed)
                {
                    interactable.OnActivate(hand);
                    
                    // 提供触觉反馈
                    if (controller.inputDevice.TryGetHapticCapabilities(out HapticCapabilities capabilities) && capabilities.supportsImpulse)
                    {
                        controller.inputDevice.SendHapticImpulse(0, hapticAmplitude, hapticDuration);
                    }
                }
                
                // 更新当前交互对象
                if (_currentInteractables[hand] != interactable)
                {
                    if (_currentInteractables[hand] != null)
                    {
                        _currentInteractables[hand].OnHoverExit(hand);
                    }
                    
                    _currentInteractables[hand] = interactable;
                }
            }
            else
            {
                // 如果射线没有击中可交互对象,清除当前交互
                if (_currentInteractables[hand] != null)
                {
                    _currentInteractables[hand].OnHoverExit(hand);
                    _currentInteractables[hand] = null;
                }
            }
        }
        else
        {
            // 如果射线没有击中任何对象,清除当前交互
            if (_currentInteractables[hand] != null)
            {
                _currentInteractables[hand].OnHoverExit(hand);
                _currentInteractables[hand] = null;
            }
        }
    }
    
    // 处理抓取交互
    private void ProcessGrabInteraction(InteractionHand hand, HandTrackingData handData, XRController controller)
    {
        // 检查手部周围的可抓取对象
        Collider[] colliders = Physics.OverlapSphere(handData.wristTransform.position, 0.1f, interactableLayers);
        
        if (colliders.Length > 0)
        {
            // 找到最近的可交互对象
            float closestDistance = float.MaxValue;
            IVRInteractable closestInteractable = null;
            
            foreach (var collider in colliders)
            {
                IVRInteractable interactable = collider.GetComponent<IVRInteractable>();
                
                if (interactable != null && interactable.CanGrab(hand))
                {
                    float distance = Vector3.Distance(handData.wristTransform.position, collider.transform.position);
                    
                    if (distance < closestDistance)
                    {
                        closestDistance = distance;
                        closestInteractable = interactable;
                    }
                }
            }
            
            // 如果找到可抓取对象,进行抓取
            if (closestInteractable != null)
            {
                closestInteractable.OnGrab(hand);
                
                // 提供触觉反馈
                if (controller != null && controller.inputDevice.TryGetHapticCapabilities(out HapticCapabilities capabilities) && capabilities.supportsImpulse)
                {
                    controller.inputDevice.SendHapticImpulse(0, hapticAmplitude, hapticDuration);
                }
                
                // 更新当前交互对象
                _currentInteractables[hand] = closestInteractable;
            }
        }
    }
    
    // 处理捏取交互
    private void ProcessPinchInteraction(InteractionHand hand, HandTrackingData handData, XRController controller)
    {
        // 检查拇指和食指之间的距离
        if (handData.thumbTip != null && handData.indexTip != null)
        {
            float distance = Vector3.Distance(handData.thumbTip.position, handData.indexTip.position);
            
            // 如果距离足够小,执行捏取
            if (distance < pinchThreshold)
            {
                // 检查捏取点周围的可交互对象
                Vector3 pinchPosition = (handData.thumbTip.position + handData.indexTip.position) / 2f;
                Collider[] colliders = Physics.OverlapSphere(pinchPosition, 0.05f, interactableLayers);
                
                if (colliders.Length > 0)
                {
                    // 找到最近的可交互对象
                    float closestDistance = float.MaxValue;
                    IVRInteractable closestInteractable = null;
                    
                    foreach (var collider in colliders)
                    {
                        IVRInteractable interactable = collider.GetComponent<IVRInteractable>();
                        
                        if (interactable != null && interactable.CanPinch(hand))
                        {
                            float objDistance = Vector3.Distance(pinchPosition, collider.transform.position);
                            
                            if (objDistance < closestDistance)
                            {
                                closestDistance = objDistance;
                                closestInteractable = interactable;
                            }
                        }
                    }
                    
                    // 如果找到可捏取对象,进行捏取
                    if (closestInteractable != null)
                    {
                        closestInteractable.OnPinch(hand);
                        
                        // 提供触觉反馈
                        if (controller != null && controller.inputDevice.TryGetHapticCapabilities(out HapticCapabilities capabilities) && capabilities.supportsImpulse)
                        {
                            controller.inputDevice.SendHapticImpulse(0, hapticAmplitude, hapticDuration);
                        }
                        
                        // 更新当前交互对象
                        _currentInteractables[hand] = closestInteractable;
                    }
                }
            }
        }
    }
    
    // 处理释放交互
    private void ProcessReleaseInteraction(InteractionHand hand, HandTrackingData handData, XRController controller)
    {
        // 如果当前有交互对象,尝试释放
        if (_currentInteractables[hand] != null)
        {
            _currentInteractables[hand].OnRelease(hand);
            _currentInteractables[hand] = null;
        }
    }
    
    // 检查控制器按钮
    private void CheckControllerButtons(InteractionHand hand, XRController controller)
    {
        if (controller == null || !controller.inputDevice.isValid)
            return;
            
        // 检查抓取按钮
        if (controller.inputDevice.TryGetFeatureValue(CommonUsages.gripButton, out bool gripPressed) && gripPressed)
        {
            ProcessGrabInteraction(hand, hand == InteractionHand.Left ? _leftHandData : _rightHandData, controller);
        }
        
        // 检查触发按钮
        if (controller.inputDevice.TryGetFeatureValue(CommonUsages.triggerButton, out bool triggerPressed) && triggerPressed)
        {
            // 如果当前有交互对象,尝试激活
            if (_currentInteractables[hand] != null)
            {
                _currentInteractables[hand].OnActivate(hand);
                
                // 提供触觉反馈
                if (controller.inputDevice.TryGetHapticCapabilities(out HapticCapabilities capabilities) && capabilities.supportsImpulse)
                {
                    controller.inputDevice.SendHapticImpulse(0, hapticAmplitude, hapticDuration);
                }
            }
            else
            {
                // 如果没有当前交互对象,尝试射线交互
                ProcessPointingInteraction(hand, hand == InteractionHand.Left ? _leftHandData : _rightHandData, controller);
            }
        }
        
        // 检查主按钮 (通常是A/X按钮)
        if (controller.inputDevice.TryGetFeatureValue(CommonUsages.primaryButton, out bool primaryPressed) && primaryPressed)
        {
            // 执行主按钮操作
            if (_currentInteractables[hand] != null)
            {
                _currentInteractables[hand].OnButtonPress(hand, "Primary");
            }
        }
        
        // 检查次按钮 (通常是B/Y按钮)
        if (controller.inputDevice.TryGetFeatureValue(CommonUsages.secondaryButton, out bool secondaryPressed) && secondaryPressed)
        {
            // 执行次按钮操作
            if (_currentInteractables[hand] != null)
            {
                _currentInteractables[hand].OnButtonPress(hand, "Secondary");
            }
        }
    }
}

// VR可交互对象接口
public interface IVRInteractable
{
    void OnHover(VRInteractionManager.InteractionHand hand);
    void OnHoverExit(VRInteractionManager.InteractionHand hand);
    void OnActivate(VRInteractionManager.InteractionHand hand);
    void OnGrab(VRInteractionManager.InteractionHand hand);
    void OnPinch(VRInteractionManager.InteractionHand hand);
    void OnRelease(VRInteractionManager.InteractionHand hand);
    void OnButtonPress(VRInteractionManager.InteractionHand hand, string buttonName);
    bool CanGrab(VRInteractionManager.InteractionHand hand);
    bool CanPinch(VRInteractionManager.InteractionHand hand);
}

// 基础VR可交互对象
public class BaseVRInteractable : MonoBehaviour, IVRInteractable
{
    [Header("Interaction Settings")]
    [SerializeField] protected bool canBeGrabbed = true;
    [SerializeField] protected bool canBePinched = false;
    [SerializeField] protected bool useHighlighting = true;
    [SerializeField] protected Color highlightColor = new Color(1f, 0.6f, 0.0f, 0.5f);
    
    [Header("Transform Tracking")]
    [SerializeField] protected bool returnToOriginalPosition = false;
    
    // 原始变换
    protected Vector3 _originalPosition;
    protected Quaternion _originalRotation;
    protected Vector3 _originalScale;
    
    // 当前交互状态
    protected bool _isHovered = false;
    protected bool _isGrabbed = false;
    protected bool _isPinched = false;
    protected VRInteractionManager.InteractionHand _currentHand;
    
    // 渲染器引用
    protected Renderer _renderer;
    protected Material[] _originalMaterials;
    protected Material[] _highlightMaterials;
    
    // 刚体引用
    protected Rigidbody _rigidbody;
    
    protected virtual void Awake()
    {
        // 保存原始变换
        _originalPosition = transform.position;
        _originalRotation = transform.rotation;
        _originalScale = transform.localScale;
        
        // 获取渲染器
        _renderer = GetComponent<Renderer>();
        if (_renderer != null && useHighlighting)
        {
            // 创建高亮材质
            _originalMaterials = _renderer.materials;
            _highlightMaterials = new Material[_originalMaterials.Length];
            
            for (int i = 0; i < _originalMaterials.Length; i++)
            {
                _highlightMaterials[i] = new Material(_originalMaterials[i]);
                _highlightMaterials[i].color = highlightColor;
            }
        }
        
        // 获取刚体
        _rigidbody = GetComponent<Rigidbody>();
    }
    
    public virtual void OnHover(VRInteractionManager.InteractionHand hand)
    {
        if (!_isHovered)
        {
            _isHovered = true;
            SetHighlight(true);
        }
    }
    
    public virtual void OnHoverExit(VRInteractionManager.InteractionHand hand)
    {
        if (_isHovered && !_isGrabbed && !_isPinched)
        {
            _isHovered = false;
            SetHighlight(false);
        }
    }
    
    public virtual void OnActivate(VRInteractionManager.InteractionHand hand)
    {
        // 默认激活行为
        Debug.Log($"Object {gameObject.name} activated by {hand} hand");
    }
    
    public virtual void OnGrab(VRInteractionManager.InteractionHand hand)
    {
        if (canBeGrabbed && !_isGrabbed)
        {
            _isGrabbed = true;
            _currentHand = hand;
            
            // 如果有刚体,禁用物理并记录状态
            if (_rigidbody != null)
            {
                _rigidbody.isKinematic = true;
            }
            
            Debug.Log($"Object {gameObject.name} grabbed by {hand} hand");
        }
    }
    
    public virtual void OnPinch(VRInteractionManager.InteractionHand hand)
    {
        if (canBePinched && !_isPinched)
        {
            _isPinched = true;
            _currentHand = hand;
            
            // 如果有刚体,禁用物理并记录状态
            if (_rigidbody != null)
            {
                _rigidbody.isKinematic = true;
            }
            
            Debug.Log($"Object {gameObject.name} pinched by {hand} hand");
        }
    }
    
    public virtual void OnRelease(VRInteractionManager.InteractionHand hand)
    {
        if ((_isGrabbed || _isPinched) && _currentHand == hand)
        {
            _isGrabbed = false;
            _isPinched = false;
            
            // 如果需要返回原位
            if (returnToOriginalPosition)
            {
                transform.position = _originalPosition;
                transform.rotation = _originalRotation;
                transform.localScale = _originalScale;
            }
            
            // 如果有刚体,恢复物理
            if (_rigidbody != null)
            {
                _rigidbody.isKinematic = false;
            }
            
            // 如果仍然在悬停,保持高亮状态
            if (_isHovered)
            {
                SetHighlight(true);
            }
            else
            {
                SetHighlight(false);
            }
            
            Debug.Log($"Object {gameObject.name} released by {hand} hand");
        }
    }
    
    public virtual void OnButtonPress(VRInteractionManager.InteractionHand hand, string buttonName)
    {
        Debug.Log($"Button {buttonName} pressed on object {gameObject.name} by {hand} hand");
    }
    
    public virtual bool CanGrab(VRInteractionManager.InteractionHand hand)
    {
        return canBeGrabbed && !_isGrabbed && !_isPinched;
    }
    
    public virtual bool CanPinch(VRInteractionManager.InteractionHand hand)
    {
        return canBePinched && !_isPinched && !_isGrabbed;
    }
    
    protected virtual void SetHighlight(bool highlight)
    {
        if (_renderer != null && useHighlighting)
        {
            _renderer.materials = highlight ? _highlightMaterials : _originalMaterials;
        }
    }
    
    protected virtual void Update()
    {
        // 跟随手部移动
        if (_isGrabbed || _isPinched)
        {
            UpdateObjectPosition();
        }
    }
    
    protected virtual void UpdateObjectPosition()
    {
        // 具体的位置更新逻辑会在子类中实现
    }
}

// 可抓取物体
public class GrabbableObject : BaseVRInteractable
{
    [Header("Grabbable Settings")]
    [SerializeField] private Transform attachPoint;
    [SerializeField] private float followSpeed = 10f;
    [SerializeField] private float rotationSpeed = 10f;
    
    // 手部引用
    private Transform _handTransform;
    
    public override void OnGrab(VRInteractionManager.InteractionHand hand)
    {
        base.OnGrab(hand);
        
        // 获取手部变换
        if (hand == VRInteractionManager.InteractionHand.Left)
        {
            _handTransform = GameObject.FindGameObjectWithTag("LeftHand").transform;
        }
        else
        {
            _handTransform = GameObject.FindGameObjectWithTag("RightHand").transform;
        }
    }
    
    protected override void UpdateObjectPosition()
    {
        if (_handTransform != null)
        {
            // 计算目标位置和旋转
            Vector3 targetPosition = attachPoint != null ? 
                _handTransform.TransformPoint(attachPoint.localPosition) : 
                _handTransform.position;
                
            Quaternion targetRotation = attachPoint != null ? 
                _handTransform.rotation * attachPoint.localRotation : 
                _handTransform.rotation;
                
            // 平滑跟随手部
            transform.position = Vector3.Lerp(transform.position, targetPosition, followSpeed * Time.deltaTime);
            transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);
        }
    }
}

// 可缩放物体
public class ScalableObject : BaseVRInteractable
{
    [Header("Scalable Settings")]
    [SerializeField] private float minScale = 0.1f;
    [SerializeField] private float maxScale = 5.0f;
    [SerializeField] private float scaleSpeed = 1.0f;
    
    // 初始捏取距离
    private float _initialPinchDistance;
    private float _initialScale;
    
    // 手指变换
    private Transform _thumbTip;
    private Transform _indexTip;
    
    public override void OnPinch(VRInteractionManager.InteractionHand hand)
    {
        base.OnPinch(hand);
        
        // 获取手指变换
        GameObject handObj = (hand == VRInteractionManager.InteractionHand.Left) ? 
            GameObject.FindGameObjectWithTag("LeftHand") : 
            GameObject.FindGameObjectWithTag("RightHand");
            
        if (handObj != null)
        {
            _thumbTip = FindChildRecursive(handObj.transform, "Thumb_Tip");
            _indexTip = FindChildRecursive(handObj.transform, "Index_Tip");
            
            if (_thumbTip != null && _indexTip != null)
            {
                _initialPinchDistance = Vector3.Distance(_thumbTip.position, _indexTip.position);
                _initialScale = transform.localScale.x;
            }
        }
    }
    
    protected override void UpdateObjectPosition()
    {
        if (_thumbTip != null && _indexTip != null)
        {
            // 计算当前捏取距离
            float currentPinchDistance = Vector3.Distance(_thumbTip.position, _indexTip.position);
            
            // 计算比例因子
            float scaleFactor = currentPinchDistance / _initialPinchDistance;
            
            // 计算新的缩放值
            float newScale = Mathf.Clamp(_initialScale * scaleFactor, minScale, maxScale);
            
            // 应用缩放
            transform.localScale = Vector3.one * newScale;
            
            // 如果物体需要跟随手部,计算中心点位置
            Vector3 pinchCenter = (_thumbTip.position + _indexTip.position) / 2f;
            transform.position = Vector3.Lerp(transform.position, pinchCenter, scaleSpeed * Time.deltaTime);
        }
    }
    
    private Transform FindChildRecursive(Transform parent, string name)
    {
        if (parent == null)
            return null;
            
        for (int i = 0; i < parent.childCount; i++)
        {
            Transform child = parent.GetChild(i);
            if (child.name.Contains(name))
                return child;
                
            Transform found = FindChildRecursive(child, name);
            if (found != null)
                return found;
        }
        
        return null;
    }
}

// UI交互器
public class VRUIInteractor : BaseVRInteractable
{
    [Header("UI Settings")]
    [SerializeField] private bool isDraggable = true;
    [SerializeField] private bool isScrollable = true;
    [SerializeField] private float scrollSpeed = 0.1f;
    [SerializeField] private float dragSpeed = 5.0f;
    
    // UI 组件引用
    private RectTransform _rectTransform;
    private ScrollRect _scrollRect;
    private Slider _slider;
    private Button _button;
    
    // 交互状态
    private Vector3 _dragStartPosition;
    private Vector2 _initialScrollPosition;
    private Vector2 _initialTouchPosition;
    
    protected override void Awake()
    {
        base.Awake();
        
        // 获取UI组件
        _rectTransform = GetComponent<RectTransform>();
        _scrollRect = GetComponent<ScrollRect>();
        _slider = GetComponent<Slider>();
        _button = GetComponent<Button>();
    }
    
    public override void OnActivate(VRInteractionManager.InteractionHand hand)
    {
        base.OnActivate(hand);
        
        // 按钮激活
        if (_button != null)
        {
            _button.onClick.Invoke();
        }
    }
    
    public override void OnGrab(VRInteractionManager.InteractionHand hand)
    {
        if (!isDraggable)
            return;
            
        base.OnGrab(hand);
        
        // 记录拖拽开始位置
        _dragStartPosition = transform.position;
    }
    
    public override void OnPinch(VRInteractionManager.InteractionHand hand)
    {
        base.OnPinch(hand);
        
        // 初始化滚动或滑块位置
        if (_scrollRect != null && isScrollable)
        {
            _initialScrollPosition = _scrollRect.normalizedPosition;
        }
        
        if (_slider != null)
        {
            _initialTouchPosition = new Vector2(transform.position.x, transform.position.y);
        }
    }
    
    protected override void UpdateObjectPosition()
    {
        if (_isGrabbed && isDraggable && _rectTransform != null)
        {
            // 拖动UI元素
            if (_handTransform != null)
            {
                Vector3 targetPosition = new Vector3(
                    _handTransform.position.x,
                    _handTransform.position.y,
                    _rectTransform.position.z
                );
                
                _rectTransform.position = Vector3.Lerp(_rectTransform.position, targetPosition, dragSpeed * Time.deltaTime);
            }
        }
        else if (_isPinched)
        {
            // 滚动或调整滑块
            if (_scrollRect != null && isScrollable && _thumbTip != null && _indexTip != null)
            {
                float pinchDelta = Vector3.Distance(_thumbTip.position, _indexTip.position) - _initialPinchDistance;
                
                Vector2 scrollDelta = new Vector2(0, pinchDelta * scrollSpeed);
                _scrollRect.normalizedPosition = _initialScrollPosition + scrollDelta;
            }
            
            if (_slider != null && _handTransform != null)
            {
                float handDelta = _handTransform.position.x - _initialTouchPosition.x;
                _slider.value = Mathf.Clamp01(_slider.value + handDelta * 0.01f);
            }
        }
    }
}

25.2 空间UI系统

csharp

// 空间UI系统
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using TMPro;

// 空间UI管理器
public class SpatialUIManager : MonoBehaviour
{
    [Header("UI Canvas Settings")]
    [SerializeField] private Canvas worldSpaceCanvas;
    [SerializeField] private float defaultDistance = 1.0f;
    [SerializeField] private float defaultScale = 0.001f;
    [SerializeField] private float followSpeed = 5.0f;
    [SerializeField] private float minDistanceFromUser = 0.5f;
    [SerializeField] private LayerMask uiLayerMask;
    
    [Header("Input Settings")]
    [SerializeField] private float gazeTimeThreshold = 2.0f;
    [SerializeField] private bool useGazeInput = true;
    [SerializeField] private bool useControllerInput = true;
    [SerializeField] private bool useHandTracking = true;
    
    [Header("UI References")]
    [SerializeField] private GameObject gazeCursor;
    [SerializeField] private Image gazeProgressIndicator;
    
    // UI状态
    private bool _isCanvasVisible = true;
    private bool _isCanvasLocked = false;
    private Vector3 _lockedPosition;
    private Quaternion _lockedRotation;
    
    // 输入状态
    private bool _isGazing = false;
    private float _gazeTimer = 0.0f;
    private GameObject _currentGazedObject = null;
    
    // 相机引用
    private Camera _mainCamera;
    
    // UI元素注册表
    private Dictionary<string, SpatialUIElement> _uiElements = new Dictionary<string, SpatialUIElement>();
    
    private void Start()
    {
        _mainCamera = Camera.main;
        
        // 初始化世界空间Canvas
        if (worldSpaceCanvas != null)
        {
            worldSpaceCanvas.renderMode = RenderMode.WorldSpace;
            worldSpaceCanvas.transform.localScale = Vector3.one * defaultScale;
            PositionCanvasInFrontOfUser();
        }
        
        // 初始化注视光标
        if (gazeCursor != null)
        {
            gazeCursor.SetActive(useGazeInput);
        }
        
        if (gazeProgressIndicator != null)
        {
            gazeProgressIndicator.fillAmount = 0;
        }
    }
    
    private void Update()
    {
        if (worldSpaceCanvas == null)
            return;
            
        // 更新Canvas位置
        if (_isCanvasVisible && !_isCanvasLocked)
        {
            PositionCanvasInFrontOfUser();
        }
        
        // 处理注视输入
        if (useGazeInput)
        {
            ProcessGazeInput();
        }
        
        // 处理控制器输入
        if (useControllerInput)
        {
            ProcessControllerInput();
        }
        
        // 处理手势输入
        if (useHandTracking)
        {
            ProcessHandInput();
        }
    }
    
    // 定位Canvas在用户面前
    private void PositionCanvasInFrontOfUser()
    {
        if (_mainCamera == null)
            return;
            
        // 计算目标位置和旋转
        Vector3 targetPosition = _mainCamera.transform.position + _mainCamera.transform.forward * defaultDistance;
        Quaternion targetRotation = Quaternion.LookRotation(targetPosition - _mainCamera.transform.position);
        
        // 平滑移动Canvas
        worldSpaceCanvas.transform.position = Vector3.Lerp(worldSpaceCanvas.transform.position, targetPosition, followSpeed * Time.deltaTime);
        worldSpaceCanvas.transform.rotation = Quaternion.Slerp(worldSpaceCanvas.transform.rotation, targetRotation, followSpeed * Time.deltaTime);
    }
    
    // 处理注视输入
    private void ProcessGazeInput()
    {
        if (_mainCamera == null)
            return;
            
        // 发射注视射线
        Ray gazeRay = new Ray(_mainCamera.transform.position, _mainCamera.transform.forward);
        RaycastHit hit;
        
        // 更新注视光标位置
        if (gazeCursor != null)
        {
            if (Physics.Raycast(gazeRay, out hit, 100f, uiLayerMask))
            {
                gazeCursor.transform.position = hit.point;
                gazeCursor.transform.rotation = Quaternion.LookRotation(-hit.normal);
                gazeCursor.SetActive(true);
            }
            else
            {
                gazeCursor.SetActive(false);
            }
        }
        
        // 检查注视的UI元素
        if (Physics.Raycast(gazeRay, out hit, 100f, uiLayerMask))
        {
            GameObject hitObject = hit.collider.gameObject;
            
            // 检查是否是UI元素
            SpatialUIElement uiElement = hitObject.GetComponent<SpatialUIElement>();
            
            if (uiElement != null)
            {
                // 如果注视新对象
                if (_currentGazedObject != hitObject)
                {
                    // 退出前一个注视对象
                    if (_currentGazedObject != null)
                    {
                        ExecuteEvents.Execute<IPointerExitHandler>(_currentGazedObject, new PointerEventData(EventSystem.current), ExecuteEvents.pointerExitHandler);
                        _isGazing = false;
                        _gazeTimer = 0f;
                    }
                    
                    // 进入新注视对象
                    _currentGazedObject = hitObject;
                    ExecuteEvents.Execute<IPointerEnterHandler>(_currentGazedObject, new PointerEventData(EventSystem.current), ExecuteEvents.pointerEnterHandler);
                    _isGazing = true;
                    _gazeTimer = 0f;
                }
                
                // 更新注视计时器
                if (_isGazing)
                {
                    _gazeTimer += Time.deltaTime;
                    
                    // 更新进度指示器
                    if (gazeProgressIndicator != null)
                    {
                        gazeProgressIndicator.fillAmount = _gazeTimer / gazeTimeThreshold;
                    }
                    
                    // 如果超过阈值,触发点击
                    if (_gazeTimer >= gazeTimeThreshold)
                    {
                        ExecuteEvents.Execute<IPointerClickHandler>(_currentGazedObject, new PointerEventData(EventSystem.current), ExecuteEvents.pointerClickHandler);
                        _gazeTimer = 0f;
                        
                        // 如果是按钮,触发点击事件
                        Button button = _currentGazedObject.GetComponent<Button>();
                        if (button != null)
                        {
                            button.onClick.Invoke();
                        }
                    }
                }
            }
            else
            {
                // 如果不是UI元素,退出当前注视
                if (_currentGazedObject != null)
                {
                    ExecuteEvents.Execute<IPointerExitHandler>(_currentGazedObject, new PointerEventData(EventSystem.current), ExecuteEvents.pointerExitHandler);
                    _currentGazedObject = null;
                    _isGazing = false;
                    _gazeTimer = 0f;
                    
                    if (gazeProgressIndicator != null)
                    {
                        gazeProgressIndicator.fillAmount = 0f;
                    }
                }
            }
        }
        else
        {
            // 如果没有命中任何物体,退出当前注视
            if (_currentGazedObject != null)
            {
                ExecuteEvents.Execute<IPointerExitHandler>(_currentGazedObject, new PointerEventData(EventSystem.current), ExecuteEvents.pointerExitHandler);
                _currentGazedObject = null;
                _isGazing = false;
                _gazeTimer = 0f;
                
                if (gazeProgressIndicator != null)
                {
                    gazeProgressIndicator.fillAmount = 0f;
                }
            }
        }
    }
    
    // 处理控制器输入
    private void ProcessControllerInput()
    {
        // 由于XR控制器的具体实现依赖于特定的XR框架,这里提供一个简化的示例
        // 在实际项目中,应该根据使用的XR框架(如OpenXR, SteamVR等)进行相应的实现
        
        // 示例:基于射线的控制器指向
        Ray controllerRay = new Ray(transform.position, transform.forward);
        RaycastHit hit;
        
        if (Physics.Raycast(controllerRay, out hit, 100f, uiLayerMask))
        {
            GameObject hitObject = hit.collider.gameObject;
            
            // 检查是否是UI元素
            SpatialUIElement uiElement = hitObject.GetComponent<SpatialUIElement>();
            
            if (uiElement != null)
            {
                // 在实际项目中,这里应检查控制器的触发按钮输入
                if (Input.GetButtonDown("Fire1")) // 替换为实际的控制器输入
                {
                    // 触发UI元素点击
                    ExecuteEvents.Execute<IPointerClickHandler>(hitObject, new PointerEventData(EventSystem.current), ExecuteEvents.pointerClickHandler);
                    
                    // 如果是按钮,触发点击事件
                    Button button = hitObject.GetComponent<Button>();
                    if (button != null)
                    {
                        button.onClick.Invoke();
                    }
                }
            }
        }
    }
    
    // 处理手势输入
    private void ProcessHandInput()
    {
        // 手势处理同样依赖于特定的手势跟踪系统实现
        // 在实际项目中,应该根据使用的手势跟踪系统进行相应的实现
        
        // 示例:简单的手指指向检测
        // 假定有一个API可以获取食指尖端位置和方向
        Vector3 fingerPosition = Vector3.zero; // 替换为实际的手指位置
        Vector3 fingerDirection = Vector3.forward; // 替换为实际的手指方向
        
        Ray fingerRay = new Ray(fingerPosition, fingerDirection);
        RaycastHit hit;
        
        if (Physics.Raycast(fingerRay, out hit, 100f, uiLayerMask))
        {
            GameObject hitObject = hit.collider.gameObject;
            
            // 检查是否是UI元素
            SpatialUIElement uiElement = hitObject.GetComponent<SpatialUIElement>();
            
            if (uiElement != null)
            {
                // 检测捏合手势
                bool isPinching = false; // 替换为实际的捏合检测
                
                if (isPinching)
                {
                    // 触发UI元素点击
                    ExecuteEvents.Execute<IPointerClickHandler>(hitObject, new PointerEventData(EventSystem.current), ExecuteEvents.pointerClickHandler);
                    
                    // 如果是按钮,触发点击事件
                    Button button = hitObject.GetComponent<Button>();
                    if (button != null)
                    {
                        button.onClick.Invoke();
                    }
                }
            }
        }
    }
    
    // 注册UI元素
    public void RegisterUIElement(SpatialUIElement element)
    {
        if (element != null && !string.IsNullOrEmpty(element.ElementID))
        {
            _uiElements[element.ElementID] = element;
        }
    }
    
    // 取消注册UI元素
    public void UnregisterUIElement(string elementID)
    {
        if (_uiElements.ContainsKey(elementID))
        {
            _uiElements.Remove(elementID);
        }
    }
    
    // 获取UI元素
    public SpatialUIElement GetUIElement(string elementID)
    {
        if (_uiElements.ContainsKey(elementID))
        {
            return _uiElements[elementID];
        }
        return null;
    }
    
    // 显示Canvas
    public void ShowCanvas()
    {
        if (worldSpaceCanvas != null)
        {
            worldSpaceCanvas.gameObject.SetActive(true);
            _isCanvasVisible = true;
        }
    }
    
    // 隐藏Canvas
    public void HideCanvas()
    {
        if (worldSpaceCanvas != null)
        {
            worldSpaceCanvas.gameObject.SetActive(false);
            _isCanvasVisible = false;
        }
    }
    
    // 锁定/解锁Canvas位置
    public void ToggleCanvasLock()
    {
        _isCanvasLocked = !_isCanvasLocked;
        
        if (_isCanvasLocked)
        {
            _lockedPosition = worldSpaceCanvas.transform.position;
            _lockedRotation = worldSpaceCanvas.transform.rotation;
        }
    }
    
    // 设置Canvas距离
    public void SetCanvasDistance(float distance)
    {
        if (distance < minDistanceFromUser)
        {
            distance = minDistanceFromUser;
        }
        
        defaultDistance = distance;
        
        if (!_isCanvasLocked)
        {
            PositionCanvasInFrontOfUser();
        }
    }
}

// 空间UI元素组件
public class SpatialUIElement : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerClickHandler
{
    [Header("Element Settings")]
    [SerializeField] private string elementID;
    [SerializeField] private bool isInteractable = true;
    [SerializeField] private float hoverScaleMultiplier = 1.1f;
    [SerializeField] private Color normalColor = Color.white;
    [SerializeField] private Color hoverColor = Color.cyan;
    [SerializeField] private Color disabledColor = Color.gray;
    [SerializeField] private AudioClip hoverSound;
    [SerializeField] private AudioClip clickSound;
    
    // 元素状态
    private bool _isHovering = false;
    private Vector3 _originalScale;
    private Image _image;
    private TextMeshProUGUI _text;
    private AudioSource _audioSource;
    
    // 事件
    public event Action<SpatialUIElement> OnElementHoverEnter;
    public event Action<SpatialUIElement> OnElementHoverExit;
    public event Action<SpatialUIElement> OnElementClick;
    
    // 属性
    public string ElementID => elementID;
    public bool IsInteractable
    {
        get { return isInteractable; }
        set { SetInteractable(value); }
    }
    
    private void Awake()
    {
        _originalScale = transform.localScale;
        _image = GetComponent<Image>();
        _text = GetComponent<TextMeshProUGUI>();
        _audioSource = GetComponent<AudioSource>();
        
        if (_audioSource == null && (hoverSound != null || clickSound != null))
        {
            _audioSource = gameObject.AddComponent<AudioSource>();
            _audioSource.spatialBlend = 1.0f; // 完全3D音效
            _audioSource.minDistance = 0.1f;
            _audioSource.maxDistance = 10f;
        }
    }
    
    private void Start()
    {
        // 注册到空间UI管理器
        SpatialUIManager manager = FindObjectOfType<SpatialUIManager>();
        if (manager != null)
        {
            manager.RegisterUIElement(this);
        }
        
        UpdateVisuals();
    }
    
    private void OnDestroy()
    {
        // 从空间UI管理器取消注册
        SpatialUIManager manager = FindObjectOfType<SpatialUIManager>();
        if (manager != null)
        {
            manager.UnregisterUIElement(elementID);
        }
    }
    
    // 设置交互状态
    public void SetInteractable(bool interactable)
    {
        isInteractable = interactable;
        UpdateVisuals();
    }
    
    // 更新视觉效果
    private void UpdateVisuals()
    {
        if (_image != null)
        {
            if (!isInteractable)
            {
                _image.color = disabledColor;
            }
            else if (_isHovering)
            {
                _image.color = hoverColor;
            }
            else
            {
                _image.color = normalColor;
            }
        }
        
        if (_text != null)
        {
            _text.color = isInteractable ? normalColor : disabledColor;
        }
    }
    
    // 实现接口方法
    public void OnPointerEnter(PointerEventData eventData)
    {
        if (!isInteractable)
            return;
            
        _isHovering = true;
        transform.localScale = _originalScale * hoverScaleMultiplier;
        
        if (_audioSource != null && hoverSound != null)
        {
            _audioSource.PlayOneShot(hoverSound);
        }
        
        UpdateVisuals();
        
        // 触发事件
        OnElementHoverEnter?.Invoke(this);
    }
    
    public void OnPointerExit(PointerEventData eventData)
    {
        if (!isInteractable)
            return;
            
        _isHovering = false;
        transform.localScale = _originalScale;
        
        UpdateVisuals();
        
        // 触发事件
        OnElementHoverExit?.Invoke(this);
    }
    
    public void OnPointerClick(PointerEventData eventData)
    {
        if (!isInteractable)
            return;
            
        if (_audioSource != null && clickSound != null)
        {
            _audioSource.PlayOneShot(clickSound);
        }
        
        // 触发事件
        OnElementClick?.Invoke(this);
    }
}

// 空间UI面板
public class SpatialUIPanel : MonoBehaviour
{
    [Header("Panel Settings")]
    [SerializeField] private string panelID;
    [SerializeField] private bool startVisible = true;
    [SerializeField] private bool useAnimation = true;
    [SerializeField] private float animationDuration = 0.5f;
    [SerializeField] private AnimationCurve animationCurve = AnimationCurve.EaseInOut(0, 0, 1, 1);
    
    [Header("Layout")]
    [SerializeField] private float width = 1.0f;
    [SerializeField] private float height = 0.6f;
    [SerializeField] private float curvature = 0.0f; // 0为平面,正值为向内弯曲
    [SerializeField] private int gridColumns = 3;
    [SerializeField] private int gridRows = 2;
    [SerializeField] private Vector2 spacing = new Vector2(0.1f, 0.1f);
    
    [Header("Appearance")]
    [SerializeField] private Material panelMaterial;
    [SerializeField] private Color backgroundColor = new Color(0.2f, 0.2f, 0.2f, 0.8f);
    [SerializeField] private float cornerRadius = 0.05f;
    [SerializeField] private float borderWidth = 0.01f;
    [SerializeField] private Color borderColor = Color.white;
    
    // 面板状态
    private bool _isVisible = false;
    private RectTransform _rectTransform;
    private CanvasGroup _canvasGroup;
    private List<SpatialUIElement> _childElements = new List<SpatialUIElement>();
    
    // 动画状态
    private Coroutine _animationCoroutine;
    
    private void Awake()
    {
        _rectTransform = GetComponent<RectTransform>();
        _canvasGroup = GetComponent<CanvasGroup>();
        
        if (_canvasGroup == null)
        {
            _canvasGroup = gameObject.AddComponent<CanvasGroup>();
        }
        
        // 初始化面板尺寸
        if (_rectTransform != null)
        {
            _rectTransform.sizeDelta = new Vector2(width, height);
        }
        
        // 收集子UI元素
        SpatialUIElement[] elements = GetComponentsInChildren<SpatialUIElement>(true);
        _childElements.AddRange(elements);
        
        // 初始可见性
        _isVisible = startVisible;
        _canvasGroup.alpha = startVisible ? 1.0f : 0.0f;
        _canvasGroup.blocksRaycasts = startVisible;
        _canvasGroup.interactable = startVisible;
    }
    
    private void Start()
    {
        // 应用材质和外观
        ApplyAppearance();
        
        // 如果使用网格布局,排列子元素
        if (gridColumns > 0 && gridRows > 0)
        {
            ArrangeElementsInGrid();
        }
        
        // 根据面板曲率调整元素位置
        if (curvature != 0)
        {
            ApplyCurvature();
        }
    }
    
    // 应用面板外观
    private void ApplyAppearance()
    {
        // 设置背景
        Image backgroundImage = GetComponent<Image>();
        if (backgroundImage == null)
        {
            backgroundImage = gameObject.AddComponent<Image>();
        }
        
        backgroundImage.color = backgroundColor;
        
        if (panelMaterial != null)
        {
            backgroundImage.material = new Material(panelMaterial);
            
            // 如果材质支持圆角和边框属性
            if (backgroundImage.material.HasProperty("_CornerRadius"))
            {
                backgroundImage.material.SetFloat("_CornerRadius", cornerRadius);
            }
            
            if (backgroundImage.material.HasProperty("_BorderWidth"))
            {
                backgroundImage.material.SetFloat("_BorderWidth", borderWidth);
            }
            
            if (backgroundImage.material.HasProperty("_BorderColor"))
            {
                backgroundImage.material.SetColor("_BorderColor", borderColor);
            }
        }
    }
    
    // 将元素排列成网格
    private void ArrangeElementsInGrid()
    {
        if (_childElements.Count == 0)
            return;
            
        // 计算单元格大小
        float cellWidth = (width - spacing.x * (gridColumns - 1)) / gridColumns;
        float cellHeight = (height - spacing.y * (gridRows - 1)) / gridRows;
        
        // 计算起始位置(左上角)
        float startX = -width / 2 + cellWidth / 2;
        float startY = height / 2 - cellHeight / 2;
        
        int elementIndex = 0;
        
        for (int row = 0; row < gridRows; row++)
        {
            for (int col = 0; col < gridColumns; col++)
            {
                if (elementIndex >= _childElements.Count)
                    break;
                    
                RectTransform elementRect = _childElements[elementIndex].GetComponent<RectTransform>();
                if (elementRect != null)
                {
                    // 计算位置
                    float x = startX + col * (cellWidth + spacing.x);
                    float y = startY - row * (cellHeight + spacing.y);
                    
                    // 设置位置和大小
                    elementRect.anchoredPosition = new Vector2(x, y);
                    elementRect.sizeDelta = new Vector2(cellWidth, cellHeight);
                }
                
                elementIndex++;
            }
        }
    }
    
    // 应用曲率
    private void ApplyCurvature()
    {
        if (_childElements.Count == 0 || curvature == 0)
            return;
            
        foreach (var element in _childElements)
        {
            RectTransform elementRect = element.GetComponent<RectTransform>();
            if (elementRect != null)
            {
                // 获取当前位置
                Vector2 position = elementRect.anchoredPosition;
                
                // 计算元素应该向内/外弯曲的距离
                float distanceFromCenter = Mathf.Abs(position.x);
                float zOffset = curvature * distanceFromCenter * distanceFromCenter;
                
                // 应用Z轴偏移
                elementRect.position = new Vector3(
                    elementRect.position.x,
                    elementRect.position.y,
                    elementRect.position.z - zOffset
                );
                
                // 调整朝向以面向中心
                if (curvature > 0)
                {
                    float angle = Mathf.Atan2(position.x, 1.0f / curvature) * Mathf.Rad2Deg;
                    elementRect.localRotation = Quaternion.Euler(0, angle, 0);
                }
            }
        }
    }
    
    // 显示面板
    public void Show()
    {
        if (_isVisible)
            return;
            
        _isVisible = true;
        
        if (useAnimation)
        {
            if (_animationCoroutine != null)
            {
                StopCoroutine(_animationCoroutine);
            }
            
            _animationCoroutine = StartCoroutine(AnimatePanel(0, 1, animationDuration));
        }
        else
        {
            _canvasGroup.alpha = 1.0f;
            _canvasGroup.blocksRaycasts = true;
            _canvasGroup.interactable = true;
        }
    }
    
    // 隐藏面板
    public void Hide()
    {
        if (!_isVisible)
            return;
            
        _isVisible = false;
        
        if (useAnimation)
        {
            if (_animationCoroutine != null)
            {
                StopCoroutine(_animationCoroutine);
            }
            
            _animationCoroutine = StartCoroutine(AnimatePanel(1, 0, animationDuration));
        }
        else
        {
            _canvasGroup.alpha = 0.0f;
            _canvasGroup.blocksRaycasts = false;
            _canvasGroup.interactable = false;
        }
    }
    
    // 面板动画协程
    private IEnumerator AnimatePanel(float startAlpha, float endAlpha, float duration)
    {
        float startTime = Time.time;
        float elapsedTime = 0f;
        
        _canvasGroup.blocksRaycasts = endAlpha > 0;
        _canvasGroup.interactable = endAlpha > 0;
        
        while (elapsedTime < duration)
        {
            elapsedTime = Time.time - startTime;
            float normalizedTime = Mathf.Clamp01(elapsedTime / duration);
            float curveValue = animationCurve.Evaluate(normalizedTime);
            
            _canvasGroup.alpha = Mathf.Lerp(startAlpha, endAlpha, curveValue);
            
            yield return null;
        }
        
        _canvasGroup.alpha = endAlpha;
    }
    
    // 切换可见性
    public void Toggle()
    {
        if (_isVisible)
        {
            Hide();
        }
        else
        {
            Show();
        }
    }
    
    // 获取子元素
    public SpatialUIElement GetElement(string elementID)
    {
        return _childElements.Find(e => e.ElementID == elementID);
    }
}

// 空间UI上下文菜单
public class SpatialContextMenu : MonoBehaviour
{
    [Header("Menu Settings")]
    [SerializeField] private float radius = 0.2f;
    [SerializeField] private int maxItems = 6;
    [SerializeField] private float itemSize = 0.05f;
    [SerializeField] private float openAnimationDuration = 0.3f;
    [SerializeField] private AnimationCurve openCurve = AnimationCurve.EaseInOut(0, 0, 1, 1);
    
    [Header("Appearance")]
    [SerializeField] private Sprite backgroundSprite;
    [SerializeField] private Color backgroundColor = new Color(0.2f, 0.2f, 0.2f, 0.8f);
    [SerializeField] private Sprite itemBackgroundSprite;
    [SerializeField] private Color itemBackgroundColor = new Color(0.3f, 0.3f, 0.3f, 1.0f);
    [SerializeField] private Color itemHoverColor = new Color(0.5f, 0.5f, 0.5f, 1.0f);
    
    // 菜单项
    [System.Serializable]
    public class MenuItem
    {
        public string id;
        public string label;
        public Sprite icon;
        public UnityEngine.Events.UnityEvent onClick;
    }
    
    [Header("Menu Items")]
    [SerializeField] private List<MenuItem> menuItems = new List<MenuItem>();
    
    // 内部状态
    private bool _isOpen = false;
    private List<GameObject> _itemGameObjects = new List<GameObject>();
    private GameObject _background;
    private Coroutine _animationCoroutine;
    
    // 打开菜单的位置和朝向
    private Vector3 _openPosition;
    private Quaternion _openRotation;
    
    private void Awake()
    {
        // 创建背景
        _background = new GameObject("ContextMenuBackground");
        _background.transform.SetParent(transform);
        
        Image bgImage = _background.AddComponent<Image>();
        bgImage.sprite = backgroundSprite;
        bgImage.color = backgroundColor;
        
        RectTransform bgRect = _background.GetComponent<RectTransform>();
        bgRect.sizeDelta = Vector2.one * radius * 2;
        
        // 初始化为关闭状态
        gameObject.SetActive(false);
    }
    
    // 打开上下文菜单
    public void Open(Vector3 position, Quaternion rotation)
    {
        if (_isOpen)
            return;
            
        _openPosition = position;
        _openRotation = rotation;
        
        transform.position = position;
        transform.rotation = rotation;
        
        gameObject.SetActive(true);
        _isOpen = true;
        
        // 创建菜单项
        CreateMenuItems();
        
        // 动画打开
        if (_animationCoroutine != null)
        {
            StopCoroutine(_animationCoroutine);
        }
        
        _animationCoroutine = StartCoroutine(AnimateOpen());
    }
    
    // 关闭上下文菜单
    public void Close()
    {
        if (!_isOpen)
            return;
            
        _isOpen = false;
        
        // 清理菜单项
        foreach (var item in _itemGameObjects)
        {
            Destroy(item);
        }
        _itemGameObjects.Clear();
        
        gameObject.SetActive(false);
    }
    
    // 创建菜单项
    private void CreateMenuItems()
    {
        // 清理现有菜单项
        foreach (var item in _itemGameObjects)
        {
            Destroy(item);
        }
        _itemGameObjects.Clear();
        
        // 限制菜单项数量
        int itemCount = Mathf.Min(menuItems.Count, maxItems);
        
        for (int i = 0; i < itemCount; i++)
        {
            MenuItem menuItem = menuItems[i];
            
            // 创建菜单项GameObject
            GameObject itemGO = new GameObject(menuItem.id);
            itemGO.transform.SetParent(transform);
            
            // 添加UI组件
            Image itemImage = itemGO.AddComponent<Image>();
            itemImage.sprite = itemBackgroundSprite;
            itemImage.color = itemBackgroundColor;
            
            RectTransform itemRect = itemGO.GetComponent<RectTransform>();
            itemRect.sizeDelta = Vector2.one * itemSize;
            
            // 如果有图标,添加图标
            if (menuItem.icon != null)
            {
                GameObject iconGO = new GameObject("Icon");
                iconGO.transform.SetParent(itemGO.transform);
                
                Image iconImage = iconGO.AddComponent<Image>();
                iconImage.sprite = menuItem.icon;
                
                RectTransform iconRect = iconGO.GetComponent<RectTransform>();
                iconRect.anchorMin = Vector2.zero;
                iconRect.anchorMax = Vector2.one;
                iconRect.offsetMin = Vector2.one * (itemSize * 0.2f);
                iconRect.offsetMax = -Vector2.one * (itemSize * 0.2f);
            }
            
            // 如果有标签,添加文本
            if (!string.IsNullOrEmpty(menuItem.label))
            {
                GameObject labelGO = new GameObject("Label");
                labelGO.transform.SetParent(itemGO.transform);
                
                TextMeshProUGUI labelText = labelGO.AddComponent<TextMeshProUGUI>();
                labelText.text = menuItem.label;
                labelText.alignment = TextAlignmentOptions.Center;
                labelText.fontSize = itemSize * 0.3f;
                
                RectTransform labelRect = labelGO.GetComponent<RectTransform>();
                labelRect.anchorMin = new Vector2(0, 0);
                labelRect.anchorMax = new Vector2(1, 0.3f);
                labelRect.offsetMin = Vector2.zero;
                labelRect.offsetMax = Vector2.zero;
            }
            
            // 添加按钮组件
            Button itemButton = itemGO.AddComponent<Button>();
            itemButton.transition = Selectable.Transition.ColorTint;
            
            ColorBlock colors = itemButton.colors;
            colors.normalColor = itemBackgroundColor;
            colors.highlightedColor = itemHoverColor;
            colors.pressedColor = itemHoverColor * 0.8f;
            itemButton.colors = colors;
            
            // 添加点击事件
            int index = i; // 捕获循环变量
            itemButton.onClick.AddListener(() => {
                menuItems[index].onClick?.Invoke();
                Close();
            });
            
            // 初始位置 (都在中心,然后通过动画展开)
            itemRect.anchoredPosition = Vector2.zero;
            
            // 添加到列表
            _itemGameObjects.Add(itemGO);
        }
    }
    
    // 打开动画
    private IEnumerator AnimateOpen()
    {
        float startTime = Time.time;
        float elapsedTime = 0f;
        
        // 计算每个项目的最终位置 (围绕一个圆)
        Vector2[] finalPositions = new Vector2[_itemGameObjects.Count];
        
        for (int i = 0; i < _itemGameObjects.Count; i++)
        {
            float angle = 2 * Mathf.PI * i / _itemGameObjects.Count;
            finalPositions[i] = new Vector2(
                Mathf.Cos(angle) * radius,
                Mathf.Sin(angle) * radius
            );
        }
        
        // 初始缩放为0
        _background.transform.localScale = Vector3.zero;
        
        foreach (var item in _itemGameObjects)
        {
            item.transform.localScale = Vector3.zero;
        }
        
        // 动画
        while (elapsedTime < openAnimationDuration)
        {
            elapsedTime = Time.time - startTime;
            float t = Mathf.Clamp01(elapsedTime / openAnimationDuration);
            float curveValue = openCurve.Evaluate(t);
            
            // 缩放背景
            _background.transform.localScale = Vector3.one * curveValue;
            
            // 移动和缩放菜单项
            for (int i = 0; i < _itemGameObjects.Count; i++)
            {
                RectTransform itemRect = _itemGameObjects[i].GetComponent<RectTransform>();
                
                // 位置
                itemRect.anchoredPosition = finalPositions[i] * curveValue;
                
                // 缩放 (延迟一点点打开,让背景先出现)
                float itemDelay = 0.2f;
                float itemT = Mathf.Clamp01((t - itemDelay) / (1 - itemDelay));
                _itemGameObjects[i].transform.localScale = Vector3.one * itemT;
            }
            
            yield return null;
        }
        
        // 确保最终状态正确
        _background.transform.localScale = Vector3.one;
        
        for (int i = 0; i < _itemGameObjects.Count; i++)
        {
            RectTransform itemRect = _itemGameObjects[i].GetComponent<RectTransform>();
            itemRect.anchoredPosition = finalPositions[i];
            _itemGameObjects[i].transform.localScale = Vector3.one;
        }
    }
    
    // 添加菜单项
    public void AddMenuItem(string id, string label, Sprite icon, UnityEngine.Events.UnityAction action)
    {
        MenuItem item = new MenuItem
        {
            id = id,
            label = label,
            icon = icon,
            onClick = new UnityEngine.Events.UnityEvent()
        };
        
        if (action != null)
        {
            item.onClick.AddListener(action);
        }
        
        menuItems.Add(item);
    }
    
    // 移除菜单项
    public void RemoveMenuItem(string id)
    {
        menuItems.RemoveAll(item => item.id == id);
    }
}

25.3 自适应UI系统

csharp

// 自适应UI系统
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using TMPro;

// 自适应UI管理器
public class AdaptiveUIManager : MonoBehaviour
{
    [Header("Device Detection")]
    [SerializeField] private bool autoDetectDevice = true;
    [SerializeField] private DeviceType manualDeviceType = DeviceType.Desktop;
    [SerializeField] private OrientationType manualOrientation = OrientationType.Landscape;
    
    [Header("Layout Settings")]
    [SerializeField] private float desktopScaleFactor = 1.0f;
    [SerializeField] private float tabletScaleFactor = 1.2f;
    [SerializeField] private float mobileScaleFactor = 1.5f;
    [SerializeField] private float vrScaleFactor = 2.0f;
    
    [Header("Performance")]
    [SerializeField] private bool dynamicResolutionScaling = true;
    [SerializeField] private float targetFrameRate = 60f;
    [SerializeField] private float resolutionScaleMin = 0.5f;
    [SerializeField] private float resolutionScaleMax = 1.0f;
    
    [Header("Accessibility")]
    [SerializeField] private bool enableAccessibilityFeatures = true;
    [SerializeField] private float textScaleFactor = 1.0f;
    [SerializeField] private bool highContrastMode = false;
    [SerializeField] private bool reduceMotion = false;
    
    // 设备和方向类型枚举
    public enum DeviceType
    {
        Desktop,
        Tablet,
        Mobile,
        VR
    }
    
    public enum OrientationType
    {
        Portrait,
        Landscape
    }
    
    // 当前设备信息
    private DeviceType _currentDeviceType;
    private OrientationType _currentOrientation;
    private Vector2 _screenSize;
    private float _currentDPI;
    private float _currentScaleFactor;
    
    // 注册的自适应UI元素
    private List<IAdaptiveUIElement> _adaptiveElements = new List<IAdaptiveUIElement>();
    
    // 性能监控
    private float _frameTimeAverage;
    private Queue<float> _frameTimeHistory = new Queue<float>();
    private int _frameHistorySize = 20;
    private float _currentResolutionScale = 1.0f;
    
    // 事件
    public event Action<DeviceType> OnDeviceTypeChanged;
    public event Action<OrientationType> OnOrientationChanged;
    public event Action<float> OnScaleFactorChanged;
    
    // 单例实例
    private static AdaptiveUIManager _instance;
    public static AdaptiveUIManager Instance => _instance;
    
    // 属性
    public DeviceType CurrentDeviceType => _currentDeviceType;
    public OrientationType CurrentOrientation => _currentOrientation;
    public Vector2 ScreenSize => _screenSize;
    public float CurrentDPI => _currentDPI;
    public float CurrentScaleFactor => _currentScaleFactor;
    public bool HighContrastMode => highContrastMode;
    public bool ReduceMotion => reduceMotion;
    public float TextScaleFactor => textScaleFactor;
    
    private void Awake()
    {
        // 设置单例
        if (_instance == null)
        {
            _instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
            return;
        }
        
        // 初始化
        _screenSize = new Vector2(Screen.width, Screen.height);
        _currentD
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小宝哥Code

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值