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

Unity点击游戏Steam定时物品掉落系统开发技术求助

1. Steamworks ItemDefinitions.json 结构

以下是符合Steam Inventory Schema规范的物品定义文件结构,适配你的普通/稀有掉落池需求:

{
  "schema_version": "1.0",
  "itemdefcount": 4,
  "itemdefs": [
    {
      "defid": 1001,
      "name": "普通道具A",
      "description": "2小时定时掉落的普通物品",
      "type": "item",
      "icon_url": "icons/common_a.png",
      "background_color": "#FFFFFF",
      "tradable": false,
      "marketable": false
    },
    {
      "defid": 1002,
      "name": "普通道具B",
      "description": "2小时定时掉落的普通物品",
      "type": "item",
      "icon_url": "icons/common_b.png",
      "background_color": "#FFFFFF",
      "tradable": false,
      "marketable": false
    },
    {
      "defid": 2001,
      "name": "稀有道具X",
      "description": "10小时定时掉落的稀有物品",
      "type": "item",
      "icon_url": "icons/rare_x.png",
      "background_color": "#FFD700",
      "tradable": false,
      "marketable": false
    },
    {
      "defid": 2002,
      "name": "稀有道具Y",
      "description": "10小时定时掉落的稀有物品",
      "type": "item",
      "icon_url": "icons/rare_y.png",
      "background_color": "#FFD700",
      "tradable": false,
      "marketable": false
    }
  ]
}

关键注意点:

  • defid:需与后续脚本中物品池的ID完全对应
  • icon_url:填写你上传至Steam后台的图标文件路径
  • tradable/marketable:点击游戏建议设为false,避免物品交易
2. 适配定时掉落逻辑的Unity脚本

该脚本实现了2小时普通掉落、10小时稀有掉落,且强制要求时段内至少点击一次才触发掉落,同时修复了原脚本中Steam回调处理的错误:

using UnityEngine;
using Steamworks;
using System.Collections.Generic;

public class ItemDropManager : MonoBehaviour
{
    // 时间间隔常量(秒)
    private const int NormalDropInterval = 7200; // 2小时
    private const int RareDropInterval = 36000; // 10小时

    // 物品池:对应ItemDefinitions.json中的defid
    private List<int> normalLootPool = new List<int> { 1001, 1002 };
    private List<int> rareLootPool = new List<int> { 2001, 2002 };

    // 状态记录
    private bool hasClickedInCurrentSession = false;
    private const string LastNormalDropKey = "LastNormalDropTime";
    private const string LastRareDropKey = "LastRareDropTime";
    private const string LastClickTimeKey = "LastPlayerClickTime";

    private Callback<SteamInventoryResultReady_t> _inventoryCallback;

    private void Awake()
    {
        // 注册Steam库存回调
        _inventoryCallback = Callback<SteamInventoryResultReady_t>.Create(OnInventoryResultReady);
    }

    private void Start()
    {
        // 每3分钟检查一次掉落条件
        InvokeRepeating(nameof(CheckDropConditions), 0f, 180f);
        // 初始化点击状态,处理玩家重启游戏的情况
        CheckInitialClickState();
    }

    // 供点击图片脚本调用:玩家点击时触发
    public void OnPlayerClicked()
    {
        hasClickedInCurrentSession = true;
        long currentTime = GetCurrentUnixTime();
        PlayerPrefs.SetInt(LastClickTimeKey, (int)currentTime);
        PlayerPrefs.Save();
    }

    private void CheckDropConditions()
    {
        long currentTime = GetCurrentUnixTime();
        long lastNormalDrop = PlayerPrefs.GetInt(LastNormalDropKey, 0);
        long lastRareDrop = PlayerPrefs.GetInt(LastRareDropKey, 0);

        // 检查普通掉落:时间达标 + 时段内有点击
        if (currentTime - lastNormalDrop >= NormalDropInterval && HasValidClick(lastNormalDrop, currentTime))
        {
            GrantRandomItem(normalLootPool);
            PlayerPrefs.SetInt(LastNormalDropKey, (int)currentTime);
            PlayerPrefs.Save();
            hasClickedInCurrentSession = false;
        }

        // 检查稀有掉落:时间达标 + 时段内有点击
        if (currentTime - lastRareDrop >= RareDropInterval && HasValidClick(lastRareDrop, currentTime))
        {
            GrantRandomItem(rareLootPool);
            PlayerPrefs.SetInt(LastRareDropKey, (int)currentTime);
            PlayerPrefs.Save();
            hasClickedInCurrentSession = false;
        }
    }

    // 验证是否在指定时段内有有效点击
    private bool HasValidClick(long intervalStart, long currentTime)
    {
        long lastClick = PlayerPrefs.GetInt(LastClickTimeKey, 0);
        // 两种情况满足:当前会话内点击过,或上次点击在当前掉落时段内
        return hasClickedInCurrentSession || (lastClick >= intervalStart && lastClick <= currentTime);
    }

    // 从物品池随机选一个,通过Steam发放
    private void GrantRandomItem(List<int> pool)
    {
        if (pool.Count == 0)
        {
            Debug.LogError("Loot pool is empty!");
            return;
        }

        int randomIndex = Random.Range(0, pool.Count);
        SteamItemDef_t itemDef = new SteamItemDef_t((uint)pool[randomIndex]);

        SteamInventoryResult_t resultHandle;
        bool success = SteamInventory.AddPromoItem(out resultHandle, itemDef);
        if (!success) Debug.LogError("Failed to request Steam item drop.");
    }

    // Steam库存操作结果回调
    private void OnInventoryResultReady(SteamInventoryResultReady_t callback)
    {
        if (callback.m_result == EResult.k_EResultOK)
        {
            Debug.Log("Item granted successfully.");
            // 这里可以添加掉落提示、UI更新逻辑
        }
        else
        {
            Debug.LogError($"Item grant failed: {callback.m_result}");
        }
        // 必须释放结果句柄,避免内存泄漏
        SteamInventory.DestroyResult(callback.m_handle);
    }

    // 初始化点击状态,处理玩家重启游戏的场景
    private void CheckInitialClickState()
    {
        long currentTime = GetCurrentUnixTime();
        long lastNormalDrop = PlayerPrefs.GetInt(LastNormalDropKey, 0);
        long lastRareDrop = PlayerPrefs.GetInt(LastRareDropKey, 0);
        long lastClick = PlayerPrefs.GetInt(LastClickTimeKey, 0);

        if (currentTime - lastNormalDrop >= NormalDropInterval && lastClick >= lastNormalDrop)
        {
            hasClickedInCurrentSession = true;
        }
        else if (currentTime - lastRareDrop >= RareDropInterval && lastClick >= lastRareDrop)
        {
            hasClickedInCurrentSession = true;
        }
    }

    // 获取当前UTC Unix时间戳(秒)
    private long GetCurrentUnixTime()
    {
        return (long)(System.DateTime.UtcNow - new System.DateTime(1970, 1, 1)).TotalSeconds;
    }

    private void OnDestroy()
    {
        _inventoryCallback?.Unregister();
    }
}

使用说明:

  1. 将脚本挂载到场景中的持久化GameObject(如GameManager)上
  2. 在你的点击图片脚本中,调用ItemDropManager.Instance.OnPlayerClicked()(需实现单例或直接引用)
  3. 替换物品池中的ID为你ItemDefinitions.json里的实际defid
  4. 确保Steam后台已开启Inventory功能,测试时需用Steam客户端登录测试账号

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 19:10:54