unity 技能系统 学习 个人部分笔记

B站视频学习 祁老师【第三部分:Unity技能系统】

博客-小紫苏

三.技能系统 [Unity_Learn_RPG_1] CSDN:cyx1144

主要是跟着视频学的思路,还有阅读小紫苏项目源码,补充个人学习中遇到的一些问题和部分笔记内容。 个人之前的项目代号“苡宁”,是M_Studio的3drpg教程项目,其中已经包括简单的对战,背包系统,任务系统,对话系统等,想要在此基础上加上技能系统。

祁老师讲的是SkillData是一个大类, 存了很多内容,

小紫苏的skill中 定义了一个 包含各种buff类型的枚举类型BuffType
包含不同受击模式的枚举类型的DamageMode 其中枚举变量包含圆形,扇形,线形
还有枚举类型的 DamageType 包含技能类型

然后还有 Skill类中的一些技能基本信息、攻击基本信息、影响效果等

技能数据类,所有可以外部导入的技能数据都放在这个类中,以便于可以外部导入数据;

Serializable

[Serializable] 是一个C#中的Attribute(属性),用于指示被修饰的类可以进行序列化,即将该类的实例转换为二进制数据,以便存储、传输或重建该类实例。在Unity中,这个属性常常用于序列化自定义数据类型,以便在Inspector面板中编辑该类型的实例。当一个类被 [Serializable] 标记时,其成员变量也需要满足可序列化的要求,例如,它们需要被标记为 [Serializable],或者是基本数据类型(如int、float、string等)。需要注意的是,一些类型,例如List、Dictionary等,已经默认实现了序列化接口,不需要标记 [Serializable]。

ScriptableObject

ScriptableObject是Unity中的一个类,继承自UnityEngine.Object,可用于创建可重复使用的数据对象。ScriptableObject可以在Unity Editor中创建、编辑和保存,与脚本代码分离,可以被多个场景、游戏对象和脚本引用,以方便共享和重用。ScriptableObject也可以通过序列化机制来实现数据持久化,从而允许将它们存储到磁盘上,并且可以在不同的场景和编辑器中重新加载和使用它们。因为ScriptableObject的实例可以重复使用,所以它们比MonoBehaviour对象更轻量,对内存的消耗更小。ScriptableObject通常用于创建一些不需要被实例化或不需要附加到游戏对象上的数据对象,例如:配置文件、资源文件、游戏物品的属性等等。

AssetBundle

AssetBundle是一种将游戏资源打包为二进制文件的方式,可以通过下载或本地加载的方式加载资源。使用AssetBundle可以实现以下功能:

减少内存占用:将游戏中的资源进行打包,可以减少游戏运行时内存的占用。

动态下载:游戏可以根据需要动态下载资源包,实现按需加载,节省玩家的网络流量。

资源共享:不同场景、游戏对象等可以共享同一个AssetBundle,避免重复加载资源。 

在什么情况下使用AssetBundle呢?一般来说,如果游戏中需要使用大量的资源,而且这些资源不能全部预加载到内存中,那么可以考虑使用AssetBundle进行资源的动态加载和卸载。比如:

大型游戏:像一些开放世界游戏、大型RPG等,需要加载大量的地图、角色、道具等资源,这些资源无法一次性预加载到内存中,使用AssetBundle可以实现按需加载。

资源更新:如果游戏需要支持在线更新,那么可以使用AssetBundle将更新后的资源打包成包,方便下载和更新。

游戏压缩:将游戏中的资源打包成AssetBundle可以减少游戏的体积,加快游戏的下载和安装速度。 

要使用AssetBundle,需要进行以下步骤:

创建AssetBundle:使用Unity的AssetBundle工具将资源打包成AssetBundle文件。

加载AssetBundle:使用AssetBundle.LoadFromFile或AssetBundle.LoadFromMemory等方法从磁盘或内存中加载AssetBundle。

加载Asset:使用AssetBundle.LoadAsset或AssetBundle.LoadAllAssets等方法从AssetBundle中加载资源。

卸载AssetBundle:使用AssetBundle.Unload或AssetBundle.UnloadAsync等方法卸载AssetBundle及其资源。 

需要注意的是,AssetBundle的使用需要谨慎,过度使用会增加开发和维护的难度。建议在游戏中仅在必要的情况下使用AssetBundle。

两种不同的单例实现方式

小紫苏项目中的

点击查看代码
using System;
using System.Reflection;
using UnityEngine;

/// <summary>
/// MonoBehaviour子类 一个抽象单列类
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class SingletonMono<T> :MonoBehaviour where T: SingletonMono<T>
{
    private static T instance = null;

    public static T I
    {
        get
        {
            if (instance == null)
            {
                instance = FindObjectOfType<T>();
                if (FindObjectsOfType<T>().Length > 1)
                {
                    Debug.Log("More than 1!");
                }

                if (instance == null)
                {
                    string instanceName = typeof(T).Name;
                    Debug.Log("Instance Name: " + instanceName); 
                    GameObject instanceGO = GameObject.Find(instanceName);
                    
                    if (instanceGO == null)
                        instanceGO = new GameObject(instanceName);
                    
                    instance = instanceGO.AddComponent<T>();
                    DontDestroyOnLoad(instanceGO);  //保证实例不会被释放
                    
                    Debug.Log("Add New Singleton " + instance.name + " in Game!");
                }
                else
                {
                    Debug.Log("Already exist: " + instance.name);
                }
            }

            return instance;
        }
    }

    protected virtual void OnDestroy()
    {
        instance = null;
    }
}

之前常用的:

点击查看代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Singleton<T> : MonoBehaviour where T:Singleton<T>
{
    private static T instance;
    public static T Instance
    {
        get { return instance; }
    }

    protected virtual void Awake()
    {
        if (instance != null)
        {
            Destroy(gameObject);
        }
        else { instance = (T)this;   }

    }

    public static bool IsInitialized
    {
        get { return instance != null; }
    }

    protected virtual void OnDestroy()
    {
        if (instance == this) 
        {
            instance = null;    
        }
    }

}


这两个单例的实现方法相似,都使用了泛型约束来确保单例只有一个实例,同时也都继承自MonoBehaviour。

然而,它们在实现上有一些差异:

第一个单例的实现方法是通过 FindObjectOfType 和 FindObjectsOfType 来查找场景中已经存在的单例实例或创建一个新的单例实例,并将其添加到场景中。同时,还在 OnDestroy 函数中将单例实例设置为 null,以便在下次需要使用单例时重新创建。

第二个单例的实现方法是在 Awake 函数中检查是否已经存在一个单例实例。如果存在,则销毁当前对象;如果不存在,则将当前对象设置为单例实例。在 OnDestroy 函数中,如果销毁的是当前单例实例,就将实例设置为 null。

因此,第一个单例实现方法允许在需要时动态创建单例实例,而第二个单例实现方法则要求单例实例在游戏启动时必须已经存在。另外,第一个单例实现方法允许单例实例在场景中有多个实例,而第二个单例实现方法则要求单例实例只能有一个实例。

选择哪种实现方法取决于具体情况和需求。如果需要在运行时创建单例实例或允许场景中存在多个实例,那么第一个实现方法可能更适合。如果希望单例实例在游戏启动时已经存在且只有一个实例,那么第二个实现方法可能更适合。

为什么给它变量名为SP

 /// <summary>技能的拥有者</summary>
  private CharacterStatus chStatus = null;

 chStatus.SP >= skillData.skill.costSP && //检查角色SP是否够使用该技能

SP 是 Skill Point 的缩写,通常指代角色或者游戏中使用技能所消耗的能量点数。在所给的代码中,chStatus 是一个代表技能持有者的对象,SP 是这个对象中的一个属性,代表角色当前的技能点数。因此,这里使用 chStatus.SP 来检查角色是否拥有足够的技能点数以使用特定的技能。

个人问题记录: 之前用的那个Character Stats 里面有刀剑攻击

把这个技能系统中的技能skillTemp中的数据拆到“苡宁”中对应的数据类中,攻击的一些可以用接口。

AssetDatabase

Unity的AssetDatabase是Unity内部用来管理各种资源(asset)的类库,包含了许多实用函数和属性。它允许在Unity编辑器中,以编程方式加载、创建、修改或删除各种类型的资源文件。比如使用AssetDatabase可以动态地加载纹理、材质球、预制件、场景等任何可计算化资源类型。

通过AssetDatabase可以:

  1. 加载和卸载资源:使用 AssetDatabase.LoadAsset 加载某个指定路径下的 asset ,将 LoadAsset 强制转换为需要的数据类型即可得到其内容。同时,也可以使用 AssetDatabase.UnloadAsset 来手动销毁已经加载到内存中的资源对象。

  2. 创建和修改资源:使用 AssetDatabase.CreateAsset 在磁盘创建一个新的 asset 文件,共有两种类型( text / binary )。然后可以使用 AssetDatabase.Refresh 立即更新项目,即可在 Unity 编辑器框架内查看 / 修改新建立的资源。

  3. 删除资源:使用 AssetDatabase.DeleteAsset() 函数,该函数接受一个字符串参数 assetPath , 指定路径下的文件都将被删除。

总之,Unity的AssetDatabase提供了一些方便开发者管理资源的方法,在Unity开发游戏过程中是一种非常有用的工具。

posted @ 2023-04-02 23:23  专心Coding的程侠  阅读(256)  评论(0编辑  收藏  举报