当前位置: 首页 > article >正文

unity 实现吸血鬼幸存者的随机奖励

设置奖励的数据类型

//
// Auto Generated Code By excel2json
// https://neil3d.gitee.io/coding/excel2json.html
// 1. 每个 Sheet 形成一个 Struct 定义, Sheet 的名称作为 Struct 的名称
// 2. 表格约定:第一行是变量名称,第二行是变量类型

// Generate From C:\Users\wasi\Desktop\Reward.xlsx.xlsx

public class Reward
{
	public int  RewardID; // id值
	public string  RewardName; // 名字
	public string  RewardType; // 类型
	public int RewardValue; // 值
	public string  Descript; // 描述
	public string BG; // 背景图
	public string Icon; // 图标
	public string AddObjcetName; // 增加物体

    public int MaxCount; // 最多出现次数
    public float CumulativeProbability; // 出现概率
    public string Level; // 奖励品质
}


// End of Auto Generated Code

奖励接口

// 定义奖励接口
using UnityEngine;
using System;

public interface IRewardable
{
    string Name { get; }
    Reward Reward { get; set; }
    /// <summary>
    /// 异步返回奖励信息的方法
    /// </summary>
    /// <param name="callback">加载完成后的回调,返回加载的奖励信息</param>
    void ReturnRewardInfo(Action<RewardInfo> callback);

    /// <summary>
    /// 授予奖励的方法
    /// </summary>
    void GetReward();
}
public class RewardInfo
{
    public string name;       // 奖励名称
    public Sprite bgSprite;   // 背景图片
    public Sprite headSprite; // 头像图片
    public string description; // 描述

    public int currentConut;
    public int maxCount;
}

奖励父类

using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using System;

public class Rewardable : IRewardable
{
    public Reward Reward { get; set; }

    public string Name => GetType().Name;
    public RewardInfo info;

    public Rewardable(Reward reward)
    {
        Debug.Log("初始化数据"+Name);

        Reward = reward;
        info = new RewardInfo();
        info.name = Reward.RewardName;
        info.description = Reward.Descript;
        info.maxCount = Reward.MaxCount;
        info.currentConut=0;
    }

    public void ReturnRewardInfo(Action<RewardInfo> callback)
    {
        // 异步加载背景图
        AsyncOperationHandle<Sprite> bgHandle = Addressables.LoadAssetAsync<Sprite>(Reward.BG);
        bgHandle.Completed += (op) =>
        {
            if (op.Status == AsyncOperationStatus.Succeeded)
            {
                info.bgSprite = op.Result;
            }
            else
            {
                Debug.LogError($"Failed to load sprite with key {Reward.BG}");
            }

            // 异步加载图标
            AsyncOperationHandle<Sprite> iconHandle = Addressables.LoadAssetAsync<Sprite>(Reward.Icon);
            iconHandle.Completed += (opIcon) =>
            {
                if (opIcon.Status == AsyncOperationStatus.Succeeded)
                {
                    info.headSprite = opIcon.Result;
                }
                else
                {
                    Debug.LogError($"Failed to load sprite with key {Reward.Icon}");
                }

                // 调用回调,返回加载完成的 RewardInfo
                callback?.Invoke(info);
            };
        };
    }

    public virtual void GetReward()
    {
        // 实现领取奖励的逻辑
    }
    public bool CanDraw()//是否能抽取
    {
        return info.currentConut < info.maxCount; // 检查是否可以抽取
    }
}

奖励系统制作成持久性单列

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

public class PersistentSingleton<T> : MonoBehaviour where T : Component
{
    public static T instance { get; private set; }
    protected virtual void Awake()
    {
        if (instance == null)
        {
            instance=this as T;
            DontDestroyOnLoad(gameObject);
        }
        else if (instance != this)
        {
            Destroy(gameObject);
        }

    }
}

奖励管理器和奖励工厂 用Newtonsoft来解析数据

using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
public class RewardManager :PersistentSingleton<RewardManager>
{
    //全部的奖励
    private List<Reward> rewardDataList = new List<Reward>();
    private List<Rewardable> rewardList = new List<Rewardable>();

    //拥有的奖励
    private List<Rewardable> owerRawardList = new List<Rewardable>();

    void Start()
    {
        LoadJson();
        foreach (string name in RewardFactory.GetRewardNames())
        {
           // Debug.Log("奖励名字"+   name);
        }
    }
    private void LoadJson()
    {
        // 使用 Addressables 异步加载 JSON 文件
        Addressables.LoadAssetAsync<TextAsset>("Data/Reward.json").Completed += OnJsonLoaded;
    }
    private void OnJsonLoaded(AsyncOperationHandle<TextAsset> handle)
    {
        if (handle.Status == AsyncOperationStatus.Succeeded)
        {
            // JSON 文件加载成功
            TextAsset jsonAsset = handle.Result;
            string json = jsonAsset.text;
            rewardDataList = JsonConvert.DeserializeObject<List<Reward>>(json);
            foreach (var reward in rewardDataList)
            {
                GrantReward(reward.RewardID);
            }
            // 在这里处理 JSON 数据
            //暂时获得全部奖励 
            owerRawardList=rewardList;
            //每次被重新生成了
            Debug.Log("重新刷新奖励-------------------------");

        }
        else
        {
            Debug.LogError("Failed to load JSON: " + handle);
        }
    }

    private void GrantReward(int rewardID)
    {
        var data = rewardDataList.Find(r => r.RewardID == rewardID);
        Rewardable rewardable = RewardFactory.GetReward(data.RewardType, data);
        if (!rewardList.Contains(rewardable))
        {
            rewardList.Add(rewardable);
        }
    }

    public Rewardable[] GetOwerRewardable(int number)
    {
        Rewardable[] newRewards=new Rewardable[number];
        HashSet<int> rewardIdList = new HashSet<int>();//记录已经抽过的奖励
        int i = 0;
        while (i<number)
        {
            float randomValue =UnityEngine.Random.Range(0f, 1f);
            Rewardable reward = owerRawardList[UnityEngine.Random.Range(0, owerRawardList.Count)];
     
            if (reward.Reward.CumulativeProbability>randomValue&&reward.CanDraw())
            {
                if (!rewardIdList.Contains(reward.Reward.RewardID))
                {
                    rewardIdList.Add(reward.Reward.RewardID);
                    newRewards[i] = reward;
                    i++;
                }

            }
        }
        return newRewards;
    }

}



public static class RewardFactory
{
    private static Dictionary<string, Type> rewardByName;
    private static bool isInit => rewardByName != null;
    private static void Init()
    {
        if (isInit) return;
        // Debug.Log("初始化奖励脚本");
        //获得脚本中所有的 IRewardable 类 同时 要是类 和不是接口 而且要是 Rewardable 子类
        var rewardTypes = Assembly.GetAssembly(typeof(IRewardable)).GetTypes()
            .Where(myType => myType.IsClass && !myType.IsInterface && myType.IsSubclassOf(typeof(Rewardable)));

        rewardByName = new Dictionary<string, Type>();
        foreach (var rewardType in rewardTypes)
        {
            //运用反射创建类 添加到字典里
            var tempEffect = Activator.CreateInstance(rewardType, new Reward()) as IRewardable;
            rewardByName.Add(tempEffect.Name, rewardType);
        }
    }
    public static Rewardable GetReward(string rewardType, Reward reward)
    {
        Init();
        if (rewardByName.ContainsKey(rewardType))
        {
            Type type = rewardByName[rewardType];
            try
            {
                //反射创建实例
                var rewardInstance = Activator.CreateInstance(type, reward) as Rewardable;
                return rewardInstance;
            }
            catch (Exception ex)
            {
                Debug.LogError($"无法创建奖励实例 {rewardType}: {ex.Message}");
            }
        }
        else
        {
            Debug.LogWarning($"未找到奖励类型 {rewardType}");
        }
        return null;
    }
    public static IEnumerable<string> GetRewardNames()
    {
       // Debug.Log("获取所有奖励名称");
        Init();
        return rewardByName.Keys;
    }
}

选取奖励制作成按钮

using UnityEngine;
using UnityEngine.UI;
using System;
using System.Collections;

public class RewardButton : MonoBehaviour
{
    [SerializeField] private Image BG;
    [SerializeField] private Image headImage;
    [SerializeField] private Text nameText;
    [SerializeField] private Text descriptText;

    [SerializeField] private GameObject BackGround;

    private Button button;

    private bool isOnclik;

    private Action action;
    private void Awake()
    {
        button = GetComponent<Button>();
    }

    private void Start()
    {
        button.onClick.AddListener(() =>
        {
            OnButtonOnClick();
        });
    }

    public void Init(IRewardable rewardable)
    {
     
        // 异步加载并显示奖励信息
        rewardable.ReturnRewardInfo((info) =>
        {
            if (info != null)
            {
                BackGround.SetActive(false);

                BG.sprite = info.bgSprite;
                headImage.sprite = info.headSprite;
                nameText.text = info.name;
                descriptText.text = info.description;
                // 添加按钮点击事件
                action+=()=>rewardable.GetReward();
            }
            else
            {
                Debug.LogError("Failed to load reward info");
            }
        });
    }

    public void ButtonAddAction(Action action)
    {
        this.action += action;
    }

    void OnButtonOnClick()
    {

        if (isOnclik)
        {
            action?.Invoke();
        }

        StartCoroutine(DoubleOnClikCoroutine());
    }

    IEnumerator DoubleOnClikCoroutine()
    {
        isOnclik=true;
        yield return new WaitForSeconds(0.5f);
        isOnclik = false;
    }
}

奖励界面

using DG.Tweening;
using System;
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

public class RewardUI : MonoBehaviour
{
    [SerializeField] Canvas canvas;
    [SerializeField] RewardButton rewardButton;

    public Transform cardParent;
    public Transform cardStartPosT;
    public int cardCount = 10;
    public float cardWidth = 1f;

    public float dealDuration = 1f;
    public float delayBetweenCards = 0.2f;

    private void OnEnable()
    {
        WaveUI.OnRewardEvent+=onRewardEvent;
    }
    private void OnDisable()
    {
        WaveUI.OnRewardEvent-=onRewardEvent;
    }

    private void onRewardEvent()
    {
        Debug.Log("调用奖励");
        CreateCard();
    }
    void CreateCard()
    {
        canvas.enabled=true;

        foreach (Transform item in cardParent)
        {
            Destroy(item.gameObject);
        }

        IRewardable[] rewardables = RewardManager.instance.GetOwerRewardable(cardCount);

        int cardNumber =cardCount;

        float totalWidth = cardNumber * cardWidth;
        float startingX = cardParent.position.x - totalWidth / 2 + cardWidth / 2;
        for (int i = 0; i < cardNumber; i++)
        {
            var card = Instantiate(rewardButton);

            // Position the card
            float cardX = startingX + i * cardWidth;
            card.transform.position = cardStartPosT.position;

            card.transform.SetParent(cardParent);
            card.transform.localScale = Vector3.one;


            DealCard(card.gameObject, i * delayBetweenCards, new Vector3(cardX, cardParent.position.y, cardParent.position.z), rewardables[i]);
        }

    }
    private void DealCard(GameObject card, float delay, Vector3 targetPos, IRewardable rewardable)
    {
        // Store the initial rotation
        Quaternion initialRotation = card.transform.rotation;

        // Create rotate animation
        var sequence = DOTween.Sequence();

        sequence.AppendInterval(delay);

        // Move card to target position
        sequence.Append(card.transform.DOMove(targetPos, 0.1f));

        // Rotate card to half way over dealDuration / 2
        sequence.Append(card.transform.DORotate(new Vector3(0, 90, 0), dealDuration / 2));

        // Add a function callback here to do something when the card is half way turned
        // For example, change the card's sprite to show its face
        sequence.AppendCallback(() => HalfWayThere(card, rewardable));

        // Rotate card to fully turned over dealDuration / 2
        sequence.Append(card.transform.DORotate(initialRotation.eulerAngles, dealDuration / 2));

        // Add a callback for completion after the animation finishes
        //  sequence.OnComplete(() => ResetReawardPlane());

    }

    private void HalfWayThere(GameObject card, IRewardable rewardable)
    {
        card.GetComponent<RewardButton>().Init(rewardable);
        card.GetComponent<RewardButton>().ButtonAddAction(
            () =>
            {
                canvas.enabled=false;
                GameManager.GameState=GameState.UI;
            }
        );

    }

    //private void Update()
    //{
    //    if (Input.GetKeyDown(KeyCode.Escape))
    //    {
    //        Debug.Log("生成奖励");
    //        //  CreateReward();
    //        CreateCard();
    //    }
    //}
}

具体的奖励类

比如我增加枪支

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

public class AddWeaponReward : Rewardable
{
    public AddWeaponReward(Reward reward) : base(reward)
    {
    }
    public override void GetReward()
    {
        info.currentConut++;//计入使用次数

        AsyncOperationHandle<GameObject> bgHandle = Addressables.LoadAssetAsync<GameObject>(Reward.AddObjcetName);
        bgHandle.Completed += (op) =>
        {
            if (op.Status == AsyncOperationStatus.Succeeded)
            {
                GameObject weapon=op.Result;
                GameObject.FindAnyObjectByType<PlayerWeapon>().AddGun(weapon);
            }
            else
            {
                Debug.LogError($"Failed to load sprite with key {Reward.BG}");
            }
        };
        Debug.Log("增加武器");
    }
}

我的excel配置表,我用excel2json 转换为json数据

保存在 data下面,这里用Addressable标记


http://www.kler.cn/a/295157.html

相关文章:

  • MYSQL 库,表 基本操作
  • k8s集群安装(kubeadm)
  • C# 委托与匿名方法
  • 若依笔记(八):Docker容器化并部署到公网
  • [CKS] K8S ServiceAccount Set Up
  • 在C++上实现反射用法
  • 基于stm32的河流检测系统-单片机毕业设计
  • u盘显示需要格式化才能用预警下的数据拯救恢复指南
  • CNC数控加工如何开启个性化制造新时代?
  • C++数据结构重要知识点(5)(哈希表、unordered_map和unordered_set封装)
  • 封装触底加载组件
  • ✨机器学习笔记(一)—— 监督学习和无监督学习
  • 包机制,javadoc生成文档,用户交互scanner
  • 怎样通过STM32实现环境监测设计
  • 【大数据分析与挖掘算法】matlab实现——Apriori关联规则算法
  • 一篇文章告诉你小程序为什么最近这么火?
  • mysql创建新表,同步数据
  • 简单实用的php全新实物商城系统
  • 2024国赛数学建模B题完整分析参考论文38页(含模型和可运行代码)
  • 深度学习速通系列:如何生成句向量?
  • 9.8通宵速通javascript
  • [论文笔记]QLoRA: Efficient Finetuning of Quantized LLMs
  • 系统架构师考试学习笔记第三篇——架构设计高级知识(19)嵌入式系统架构设计理论与实践
  • 3177. 求出最长好子序列 II / 3176. 求出最长好子序列 I(24.9.7 / 24.9.8)
  • pdf转word格式乱了怎么调整?2024帮助你快速进行pdf格式调整的软件
  • [论文笔记]Circle Loss: A Unified Perspective of Pair Similarity Optimization