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.xlsxpublic 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}");}// 调用回调,返回加载完成的 RewardInfocallback?.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 cardfloat 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 rotationQuaternion initialRotation = card.transform.rotation;// Create rotate animationvar sequence = DOTween.Sequence();sequence.AppendInterval(delay);// Move card to target positionsequence.Append(card.transform.DOMove(targetPos, 0.1f));// Rotate card to half way over dealDuration / 2sequence.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 facesequence.AppendCallback(() => HalfWayThere(card, rewardable));// Rotate card to fully turned over dealDuration / 2sequence.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.rhkb.cn/news/418911.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DevC++编译及使用Opencv

1.依赖 需要如下依赖&#xff1a; DevC11Opencv4.10.0CMake.exe 整个安装过程参考下面的文章&#xff1a;https://blog.csdn.net/weixin_41673576/article/details/108519841 这里总结一下遇到的问题。 2.问题 2.1 DevC安装路径 一定不要有空格&#xff01;&#xff01;否则…

【自动驾驶】控制算法(八)横向控制Ⅲ | 代码与模型

写在前面&#xff1a; &#x1f31f; 欢迎光临 清流君 的博客小天地&#xff0c;这里是我分享技术与心得的温馨角落。&#x1f4dd; 个人主页&#xff1a;清流君_CSDN博客&#xff0c;期待与您一同探索 移动机器人 领域的无限可能。 &#x1f50d; 本文系 清流君 原创之作&…

Java | Leetcode Java题解之第393题UTF-8编码验证

题目&#xff1a; 题解&#xff1a; class Solution {static final int MASK1 1 << 7;static final int MASK2 (1 << 7) (1 << 6);public boolean validUtf8(int[] data) {int m data.length;int index 0;while (index < m) {int num data[index];…

从零开始学习JVM(七)- StringTable字符串常量池

1 概述 String应该是Java使用最多的类吧&#xff0c;很少有Java程序没有使用到String的。在Java中创建对象是一件挺耗费性能的事&#xff0c;而且我们又经常使用相同的String对象&#xff0c;那么创建这些相同的对象不是白白浪费性能吗。所以就有了StringTable这一特殊的存在&…

Python爬虫:通过js逆向获取某瓜视频的下载链接

爬虫:通过js逆向获取某瓜视频的下载链接 1. 前言2. 获取script标签下的视频加密数据3. 第一步:获取解密后的视频下载链接4. 第二步:模拟生成加密的webid值 1. 前言 就小编了解&#xff0c;某瓜视频这个网站对应视频下载链接加密处理至少经过三个版本。之前在CSDN发布了一篇关于…

华为 HCIP-Datacom H12-821 题库 (5)

有需要题库的可以看主页置顶 需要题库的加Q裙 V群仅进行学习交流 1.以下关于堆叠 MAD 检测说法错误的是&#xff1f; A、堆系统互为代理进行 MAD 检测时&#xff0c;两个堆系统可以使用相同的D omain ID B、MAD 检测的方式分为直连检测、代理检测 C、MAD 代理检测要求所有堆叠…

Vim笔记

【指尖飞舞&#xff1a;vscode vim 高效开发&#xff08;系列视频&#xff09;】https://www.bilibili.com/video/BV1z541177Jyp16&vd_source23e4761174881d73295e362ffd706749 Vscode vim插件配置-CSDN博客 g_跳到行尾最后一个非空字符 gd :go to definition ctrl (o): …

【基础】Three.js 自定义几何体和复制几何体

通过自定义顶点数据&#xff0c;可以创建任意的几何体。像threejs的长方体BoxGeometry、球体SphereGeometry等几何体都是基于BufferGeometry类构建的&#xff0c;它表示一个没有任何形状的空几何体。 1. 自定义点模型 通过javascript 类型化数组 Float32Array创建一组xyz坐标…

比特币客户端和API

1. 比特比客户端的安装 Bitcoin Core 客户端适用于从 x86 Windows 到 ARM Linux 的不同架构和平台&#xff0c;如下图所示&#xff1a; 2. Bitcoin Core客户端的类型 2.1 Bitcoind Bitcoind 末尾的字母 d 表示 daemon (守护程序&#xff09;。所谓守护程序&#xff0c;就是指常…

基于深度学习 卷积神经网络resnext50的中医舌苔分类系统

项目概述 本项目旨在通过深度学习技术&#xff0c;特别是利用卷积神经网络&#xff08;Convolutional Neural Networks, CNNs&#xff09;中的ResNeXt50架构&#xff0c;实现对中医舌象图像的自动分类。该系统不仅能够识别不同的舌苔类型&#xff0c;还能够在PyQt5框架下提供一…

简单实用的php全新实物商城系统

免费开源电商系统,提供灵活的扩展特性、高度自动化与智能化、创新的管理模式和强大的自定义模块,让电商用户零成本拥有安全、高效、专业的移动商城。 代码是全新实物商城系统源码版。 代码下载

ngrok | 内网穿透,支持 HTTPS、国内访问、静态域名

前言 当我们需要把本地开发的应用展示给外部用户时&#xff0c;常常会因为无法直接访问而陷入困境。 就为了展示一下&#xff0c;买服务、域名&#xff0c;搭环境&#xff0c;费钱又费事。 那有没有办法&#xff0c;让客户直接访问自己本机开发的应用呢&#xff1f; 这种需…

Vue 使用接口返回的背景图片和拼图图片进行滑动拼图验证

一、背景 前两天发了一篇 vue-monoplasty-slide-verify 滑动验证码插件使用及踩坑_vue-monoplasty-slide-verify 引用后不显示-CSDN博客 这两天项目又需要通过接口校验&#xff0c;接口返回了背景图片和拼图图片&#xff0c;于是在网上找了一篇帖子&#xff0c;vue 图片滑动…

安卓玩机工具------小米工具箱扩展工具 小米机型功能拓展

小米工具箱扩展版 小米工具箱扩展版 iO_Box_Mi_Ext是由晨钟酱开发的一款适用于小米&#xff08;MIUI&#xff09;、多亲&#xff08;2、2Pro&#xff09;、多看&#xff08;多看电纸书&#xff09;的多功能工具箱。该工具所有功能均可以免root实现&#xff0c;使用前&…

2024/9/6黑马头条跟学笔记(三)

D3 内容介绍 jdk8新特性&#xff0c;stream流&#xff0c;lambda表达式 ​ 自媒体前后端搭建 步骤 sql—— 实体—— 微服务拷贝&#xff0c;配置nacos—— spring:datasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://192.168.233.136:3306/leadnews_…

基于Spring Boot的火车订票管理系统

你好呀&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;JAVA语言 Spring Boot框架 工具&#xff1a;IDEA/Eclipse、Navicat、Tomcat 系统展示 首页 管理…

Android Jetpact Lifecycle 解析

认识 Lifecycle Lifecycle 是什么 Lifecycle 是 Jetpack 组件库中的一个生命周期感知型组件。在 Lifecycle 出现之前&#xff0c;需要手动从外部宿主&#xff08;如 Activity、Fragment 或自定义宿主&#xff09;中将生命周期事件分发到功能组件内部&#xff0c;这势必会造成…

SAM 2:分割图像和视频中的任何内容

文章目录 摘要1 引言2 相关工作3 任务&#xff1a;可提示视觉分割4 模型5 数据5.1 数据引擎5.2 SA-V数据集 6 零样本实验6.1 视频任务6.1.1 提示视频分割6.1.2 半监督视频对象分割6.1.3 公平性评估 6.2 图像任务 7 与半监督VOS的最新技术的比较8 数据和模型消融8.1 数据消融8.2…

RT-Thread(Nano版本)的快速移植(基于NUCLEO-F446RE)

目录 概述 1 RT-Thread 1.1 RT-Thread的版本 1.2 认识Nano版本 2 STM32F446U上移植RT-Thread 2.1 STM32Cube创建工程 2.2 移植RT-Thread 2.2.1 安装RT-Thread Packet 2.2.2 加载RT-Thread 2.2.3 匹配相关接口 2.2.3.1 初次编译代码 2.2.3.2 匹配端口 2.2.4 移植FinSH…

时间同步服务

多主机协作工作时&#xff0c;各个主机的时间同步很重要&#xff0c;时间不一致会造成很多重要应用的故障&#xff0c;如&#xff1a;加密协 议&#xff0c;日志&#xff0c;集群等。 利用NTP&#xff08;Network Time Protocol&#xff09; 协议使网络中的各个计算机时间达到…