首页 > 其他分享 >【XYFrame unity框架使用文档】封装unity小框架工具集 —— XYFrame

【XYFrame unity框架使用文档】封装unity小框架工具集 —— XYFrame

时间:2024-10-14 20:49:06浏览次数:8  
标签:框架 AudioManager void height Instance unity width public XYFrame

文章目录

XYFrame介绍

XYFrame是个人整理的自用unity小框架,非常适合中小项目的开发。与其说是框架不如说是工具集,其实就是把一些常用的unity管理器进行封装。

写这个框架的原因就是不想一直造轮子,游戏开发过程中发现很多功能都是通用的,比如单例、对象池、音频、存档等等。

优点

  • 框架源码完全开源免费使用
  • 轻量,主要就是对一些常用功能进行封装,避免重复造轮子,基本没有特别花里胡哨的操作
  • 维护稳定,因为这是自用框架,自己平时会用,如果有任何问题会第一时间更新
  • 实战项目,后续我会在不同的项目中用它,并将实战经验分享出来
  • 代码耦合性极低,设计之初,框架每个模块之间尽量做到低关联,每个模块都可以选择单独提取使用,基本不用修改或者少修改即可使用
  • 自带中文注释,易于使用理解
  • 源码内自带非常完整常用的测试用例可以使用和演示

获取框架源码

【gitee地址】https://gitee.com/unity_data/xyframe

引入的第三方插件

  • DOTween

作者信息

姓名:向宇

博客:https://xiangyu.blog.csdn.net/

技术交流群反馈企鹅裙

826534924

画饼

  • 封装存储事件(未完成
  • 封装有限状态机(未完成
  • 用0GC更高性能的UniTask替换协程(未完成
  • BUFF系统(未完成
  • 对话系统(未完成
  • 任务系统(未完成
  • 背包系统(未完成
  • 热更(未完成
  • 本地化多语言(未完成

使用文档

原文:【XYFrame unity框架使用文档】封装unity小框架工具集 ——XYFrame

导入

你可以选择直接下载整个文件夹,用unity打开
也可以选择下载导入unity框架包

在这里插入图片描述

文件目录

在这里插入图片描述

Test目录:保存一些非常完整常用的测试用例可以使用和演示,供新手快速入门使用,当然你完全可以删除它,不会影响框架的使用。可以打开一个空场景,可以通过菜单工具按钮进行测试

在这里插入图片描述

Frame目录:框架的主体代码目录,为了方便后期框架的更新,我并不推荐你去修改它们,当然除非你知道自己在干什么。框架主体代码目录具体解释见下文

启动

启动场景在0.Init里放置一个GameApp脚本即可,运行项目会自动跳转到1.Start场景,从1.Start场景开始才是真正的游戏场景,0.Init只是进行初始化操作,不带任何的界面操作

在这里插入图片描述

GameApp游戏入口脚本,你可以像我一样一次性加载全部管理器,也可以按需加载,后续调用就使用GameApp.MonoManager.xxxx方式即可

using UnityEngine;
using XYFrame;

/// <summary>
/// 游戏入口脚本
/// </summary>
public class GameApp : SingletonMono<GameApp>
{
    //初始化管理器
    [HideInInspector] public MonoManager MonoManager = null;
    [HideInInspector] public EventManager EventManager = null;
    [HideInInspector] public ResourcesManager ResourcesManager = null;
    [HideInInspector] public ObjectPoolsManager ObjectPoolsManager = null;
    [HideInInspector] public LoadSceneManager LoadSceneManager = null;
    [HideInInspector] public UIManager UIManager = null;
    [HideInInspector] public AudioManager AudioManager = null;
    [HideInInspector] public SaveManager SaveManager = null;

    //游戏入口
    void Awake()
    {
        //全局单例赋值
        MonoManager = MonoManager.Instance;
        EventManager = EventManager.Instance;
        ResourcesManager = ResourcesManager.Instance;
        ObjectPoolsManager = ObjectPoolsManager.Instance;
        LoadSceneManager = LoadSceneManager.Instance;
        UIManager = UIManager.Instance;
        AudioManager = AudioManager.Instance;
        SaveManager = SaveManager.Instance;

        //跳转下一个场景
        LoadSceneManager.LoadNextScene();
    }
}

ps:当然我这里只是一个推荐加载方式,如果你不喜欢,也可以选择使用自己的方式,XYFrame是完全自由的。

1、单例模式

不继承MonoBehaviour的单例模式基类

public class TestModel : Singleton<TestModel>

继承MonoBehaviour的单例模式基类

public class TestUI : SingletonMono<TestUI> 

在OnDestroy方法中访问单例对象,如果直接在在OnDestroy方法中访问单例对象,每次运行结束时会报错

在OnDestroy调用时,先判断IsExisted是否为true

private void OnDestroy() {
    if(TestUI.IsExisted) TestUI.Instance.Log();
}

2、Mono管理器

在不继承MonoBehaviour情况下调用MonoBehaviour里的功能,比如协程、Update、LateUpdate、FixedUpdate

# 开启携程
coroutine = MonoManager.Instance.StartCoroutine(MyCoroutine());
# 停止协程
MonoManager.Instance.StopCoroutine(coroutine);
# 停止所有协程
MonoManager.Instance.AddLateUpdateListener(OnLateUpdate);

# 开启Update
MonoManager.Instance.AddUpdateListener(OnUpdate);
# 停止Update
MonoManager.Instance.RemoveUpdateListener(OnUpdate);
# 停止所有Update
MonoManager.Instance.RemoveAllUpdateListeners();

# 开启FixedUpdate
MonoManager.Instance.AddFixedUpdateListener(OnFixedUpdate);
# 停止FixedUpdate
MonoManager.Instance.RemoveFixedUpdateListener(OnFixedUpdate);
# 停止所有FixedUpdate
MonoManager.Instance.RemoveAllFixedUpdateListeners();

# 开启LateUpdate
MonoManager.Instance.AddLateUpdateListener(OnLateUpdate);
# 停止LateUpdate
MonoManager.Instance.RemoveLateUpdateListener(OnLateUpdate);
# 停止所有LateUpdate
MonoManager.Instance.RemoveAllLateUpdateListeners();

3、事件管理系统

这里我添加最多支持添加4个参数的事件,一般都够了,如果觉得还是不够,可以模仿我的方式继续添加即可

# 事件监听
EventManager.Instance.AddEventListener(EventNameEnum.Log, Log);
EventManager.Instance.AddEventListener<int>(EventNameEnum.AddHealth, AddHealth);

# 触发带1个参数事件
EventManager.Instance.Dispatch<int>(EventNameEnum.AddHealth, 1);

# 移除Player带1个参数事件监听
EventManager.Instance.RemoveEventListener<int>(EventNameEnum.AddHealth, go.GetComponent<Player>().AddHealth);

# 移除整个带1个参数事件
EventManager.Instance.RemoveEvent<int>(EventNameEnum.AddHealth);

4、工具类

封装unity协程工具,避免 GC(垃圾回收)

提前new好协程所需要的WaitForEndOfFrame、WaitForFixedUpdate、WaitForFrameStruct类的对象,避免GC。

# 使用
IEnumerator DelayedAction()
{
    yield return CoroutineTool.WaitForEndOfFrame(); // 等待到当前帧的结束
    yield return CoroutineTool.WaitForFixedUpdate(); // 等待到下一个固定更新
    yield return CoroutineTool.WaitForSeconds(2.0f); // 等待2秒(游戏时间)
    yield return CoroutineTool.WaitForSecondsRealtime(2.0f); // 等待2秒(现实时间,不受游戏时间缩放影响)
    yield return CoroutineTool.WaitForFrame(); // 等待一帧
    yield return CoroutineTool.WaitForFrame(3); // 等待3帧
}

封装Stopwatch工具类,计算执行一段代码所用的时间

# 测试调用,打印执行一段代码10000次需要多少秒
public class ToolsTest : MonoBehaviour {
    private void Start() {
        StopwatchUtility.PrintTime(Execute, 10000);
    }

    void Execute(){
        "测试字符".GetType();
    }
}

5、Resources资源管理器

# 异步加载资源
ResourcesManager.Instance.LoadAsync<GameObject>("Prefabs/Cube", (obj)=>{
    Instantiate(obj);
});

# 同步加载封装虽然和unity自带的方法是一样的,但是好处是自己封装可以统一管理和进行自定义注释
GameObject prefab = ResourcesManager.Instance.Load<GameObject>("Prefabs/Cube");

# 同步加载Resources文件夹中指定类型的资源。
GameObject[] gos = ResourcesManager.Instance.LoadAll<GameObject>("Prefabs");
for (int i = 0; i < gos.Length; i++)
{
    Instantiate(gos[i]);
}

# 异步卸载所有用Resources方式加载到内存中且当前没有被任何地方使用的资源。
ResourcesManager.Instance.UnloadUnusedAssets(() =>
{
    Debug.Log("异步卸载所有资源成功");
});

6、对象池管理器

# 生成游戏对象
GameObject go = ObjectPoolsManager.Instance.Spawn(prefab, transform.position, Quaternion.identity, transform);

# 5秒后回收
ObjectPoolsManager.Instance.Despawn(go, 5f);

# 生成和回收游戏对象时自动调用的方法
public class Cube : MonoBehaviour {
    //生成游戏对象时自动调用
    void OnSpawn(){
        Debug.Log("生成游戏对象");
    }

    //回收游戏对象时自动调用
    void OnDespawn(){
        Debug.Log("回收游戏对象");
        
        //重置参数
        transform.position = Vector3.zero;
        GetComponent<Rigidbody>().velocity = Vector3.zero;
    }
}

7、场景管理器

# 同步加载当前场景、下一个场景、上一个场景
LoadSceneManager.Instance.LoadActiveScene();
LoadSceneManager.Instance.LoadNextScene();
LoadSceneManager.Instance.LoadPreviousScene();

# 异步切换场景
LoadSceneManager.Instance.LoadSceneAsync(1);
LoadSceneManager.Instance.LoadSceneAsync("Scene1");

# 异步加载场景获取加载进度条
public class SceneTest : MonoBehaviour
{
    private void Start()
    {
        LoadSceneManager.Instance.LoadSceneAsync(1, Loading, Completed);
    }

    void Loading(float progress)
    {
        Debug.Log($"加载进度是{progress*100}%");
    }

    void Completed(AsyncOperation asyncOperation)
    {
        Debug.Log("场景加载完成");
    }
}

8、序列化字典,场景,vector,color,Quaternion

可序列化字典简单的使用

和普通字典的使用方法一样,只需要把Dictionary换成SerializableDictionary,并且使用时不需要先实例化了

public class SerializedTest : MonoBehaviour {
    //可序列化字典
    public SerializableDictionary<string, string> serializableDictionary;

    private void Start() {
        //添加键值对
        serializableDictionary.Add("name1", "小明");
        serializableDictionary["name2"] = "小红";
        //检查是否包含指定的键
        string key = "name1";
        Debug.Log($"是否包含键为{key}:{serializableDictionary.ContainsKey(key)}");
        //获取指定键的值
        Debug.Log($"获取键为name2的值:{serializableDictionary["name2"]}");
        //移除键值对
        serializableDictionary.Remove("name1");
        //获取键值对数量
        Debug.Log($"获取键值对数量:{serializableDictionary.Count}");
        //清空字典
        //serializableDictionary.Clear();
    }
}

序列化场景

代码通过使用SceneField类和SceneFieldPropertyDrawer属性绘制器,开发者可以在自定义的脚本中方便地引用和管理场景对象,并在Inspector面板中进行编辑和选择操作。这对于需要频繁切换场景或者处理多个场景的情况非常有用。

public class SerializedTest : MonoBehaviour {
    //可序列化场景
    public SerializableScene scene1;
    public SerializableScene scene2;

    private void Start() {
        SceneManager.LoadScene(scene1);//跳转场景
    }
}

序列化vector

//普通Vector
public Vector3 vector3;
public Vector2 vector2;
//可序列化Vector
public SerializedVector3 serializedVector3;
public SerializedVector2 serializedVector2;

//Vector3和SerializedVector3可以随意转换
Debug.Log(vector3);
vector3 = serializedVector3;
Debug.Log(vector3);
serializedVector3 = Vector3.zero;
Debug.Log(serializedVector3);

序列化color

//颜色
public Color color;
//可序列化的颜色
public SerializedColor serializedColor;

color = new Color(1.0f, 0.5f, 0.0f, 1.0f);
Debug.Log(color);
serializedColor = new SerializedColor(0.0f, 1.0f, 0.0f, 1.0f);
Debug.Log(serializedColor);
color = serializedColor;
Debug.Log(color);

序列化旋转Quaternion

//旋转
public Quaternion quaternion;
//可序列化旋转
public SerializedQuaternion serializedQuaternion;

// 定义一个欧拉角(绕X、Y、Z轴的旋转)    
Vector3 eulerAngles = new Vector3(30f, 45f, 60f); 
// 将欧拉角转换为四元数
quaternion = Quaternion.Euler(eulerAngles);
// 将四元数转换为欧拉角
eulerAngles = quaternion.eulerAngles;
Debug.Log(eulerAngles);

//直接赋值
serializedQuaternion = Quaternion.Euler(eulerAngles);
serializedQuaternion = quaternion;

//互相转换
serializedQuaternion = quaternion.ConvertToSQuaternion();
quaternion = serializedQuaternion.ConvertToQuaternion();

9、UI管理器/UI框架

调用代码会自动创建画布
在这里插入图片描述

# 显示WelcomeUI面板,创建的脚本名字记得跟预制体物体名字一致
UIManager.Instance.ShowUI<WelcomeUI>("WelcomeUI");

# 提示框
UIManager.Instance.ShowTips("成功!", Color.green);

我们可以在UI初始化时,提前获取所有控件信息并存储在字典里,并且给特殊控件绑定好各种事件,比如按钮点击事件、单选框或者多选框值改变事件、滑动条值改变事件

public class SettingsUI : UIBase
{
    private void Start()
    {
        SetSliderValue();
    }

    #region 按钮点击事件
    string CloseBtn = "bg/退出按钮";
    string ResetBtn = "bg/重置按钮";
    protected override void OnButtonClick(string btnName)
    {
        if (btnName == CloseBtn) OnCloseBtn();
        if (btnName == ResetBtn) OnResetBtn();
    }
    void OnCloseBtn()
    {
        Close();//关闭界面
        UIManager.Instance.ShowTips("关闭界面!", Color.red);//提示
    }
    void OnResetBtn()
    {
        UIManager.Instance.ShowTips("重置成功!", Color.blue);
        AudioManager.Instance.ResetVolume();
        SetSliderValue();
    }
    #endregion

    #region 滑动条事件
    string MasterSlide = "bg/Volume/Master/Slide";
    string BGMSlide = "bg/Volume/BGM/Slide";
    string BGSSlide = "bg/Volume/BGS/Slide";
    string SoundSlide = "bg/Volume/Sound/Slide";
    string VoiceSlide = "bg/Volume/Voice/Slide";
    protected override void OnSliderValueChanged(string toggleName, float value)
    {
        if (toggleName == MasterSlide) OnSliderMasterVolume(value);
        if (toggleName == BGMSlide) OnSliderBGMVolume(value);
        if (toggleName == BGSSlide) OnSliderBGSVolume(value);
        if (toggleName == SoundSlide) OnSliderSoundVolume(value);
        if (toggleName == VoiceSlide) OnSliderVoiceVolume(value);
    }

    //修改音量
    void OnSliderMasterVolume(float value)
    {
        AudioManager.Instance.SetMasterVolume(value);
    }
    void OnSliderBGMVolume(float value)
    {
        AudioManager.Instance.SetBGMVolume(value);
    }
    void OnSliderBGSVolume(float value)
    {
        AudioManager.Instance.SetBGSVolume(value);
    }
    void OnSliderSoundVolume(float value)
    {
        AudioManager.Instance.SetSoundVolume(value);
    }
    void OnSliderVoiceVolume(float value)
    {
        AudioManager.Instance.SetVoiceVolume(value);
    }
    #endregion

    //按音量修改滑动条值
    void SetSliderValue()
    {
        GetControl<Slider>(MasterSlide).value = AudioManager.Instance.MatserVolume;
        GetControl<Slider>(BGMSlide).value = AudioManager.Instance.BGMVolume;
        GetControl<Slider>(BGSSlide).value = AudioManager.Instance.BGSVolume;
        GetControl<Slider>(SoundSlide).value = AudioManager.Instance.SoundVolum;
        GetControl<Slider>(VoiceSlide).value = AudioManager.Instance.VoiceVolume;
    }
}

效果

在这里插入图片描述

10、声音/音频/音效管理器

包括带自带对象池的2d、3d音效播放,AudioMixer的使用和如何控制音量,实现bgm背景音和BGS环境音的淡入淡出效果

BGM

# 播放BGM1
AudioManager.Instance.PlayBGM(BGM1);
# 播放BGM2
AudioManager.Instance.PlayBGM(BGM2);
# 暂停BGM
AudioManager.Instance.PauseBGM();
# 取消暂停BGM
AudioManager.Instance.UnPauseBGM();
# 停止BGM
AudioManager.Instance.StopBGM();

音效

# 播放2D音效
AudioManager.Instance.PlaySound(Sound1);

# 在指定目标对象身上播放3D音效
AudioManager.Instance.PlaySound(Sound2, gameObject);

# 使用对象池在世界空间中指定的位置播放3D音效
AudioManager.Instance.PlaySound(Sound2, Vector3.one);

BGS环境音

# 播放环境音1
AudioManager.Instance.PlayBGS(BGS1);
# 播放环境音2
AudioManager.Instance.PlayBGS(BGS2);
# 暂停环境音
AudioManager.Instance.PauseBGS();
# 取消暂停环境音
AudioManager.Instance.UnPauseBGS();
# 停止环境音
AudioManager.Instance.StopBGS();

播放MS提示音效

AudioManager.Instance.PlayMS(ms);

播放和停止Voice角色语音

# 播放角色语音
AudioManager.Instance.PlayVoice(voice);
# 停止角色语音
AudioManager.Instance.StopVoice();

设置音量

# 设置总音量为1
AudioManager.Instance.SetMasterVolume(1);
# 设置BGM音量为0.8
AudioManager.Instance.SetBGMVolume(0.8f);
# 设置音效音量为0.5
AudioManager.Instance.SetSoundVolume(0.5f);
# 设置环境音音量为0.2
AudioManager.Instance.SetBGSVolume(0.2f);
# 设置角色语音音量为0
AudioManager.Instance.SetVoiceVolume(0);
# 重置音量
AudioManager.Instance.ResetVolume();

获取音量

float matserVolume = AudioManager.Instance.MatserVolume;
float bGMVolume = AudioManager.Instance.BGMVolume;
float bGSVolume = AudioManager.Instance.BGSVolume;
float soundVolum = AudioManager.Instance.SoundVolum;
float voiceVolume = AudioManager.Instance.VoiceVolume;

效果

在这里插入图片描述

11、存档存储数据持久化系统

实现对存档的创建,获取,保存,加载,删除,缓存,加密,支持多存档

存档文件支持很多数据类似,这里我选择Json,可读性较强,易修改。

SaveData和setting分别存储用户存档和设置型存档。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

用户存档下根据saveID分成若干文件夹用于存储具体的对象。

// GameSetting类中存储着游戏名称,作为全局数据
[Serializable]
public class GameSetting
{
    public string gameName;
}

[Serializable]
public class GameSetting2
{
    public string gameName;
}

public class SaveTest : MonoBehaviour {
    GameSetting gameSetting;
    GameSetting2 gameSetting2;
    SaveItem saveItem;
    Dictionary<string, string> info = new Dictionary<string,string>();
    private void Awake() {
        //添加测试数据
        gameSetting = new GameSetting();
        gameSetting.gameName = "测试";

        gameSetting2 = new GameSetting2();
        gameSetting2.gameName = "测试2"; 
    }

    private void OnGUI()
    {
        GUIStyle buttonStyle = new GUIStyle(GUI.skin.button);   
        buttonStyle.fontSize = 25; // 设置字体大小
        int width = 400;
        int height = 150;

        //设置型存档 
        if (GUI.Button(new Rect(0, 0, width, height), "保存设置数据1", buttonStyle))
        {
            SaveManager.Instance.SaveSetting(gameSetting);
        }
        if (GUI.Button(new Rect(0, height, width, height), "追加设置数据2", buttonStyle))
        {
            SaveManager.Instance.SaveSetting(gameSetting2);
        }
        if (GUI.Button(new Rect(0, height*2, width, height), "加载设置数据1", buttonStyle))
        {
            string gameName = SaveManager.Instance.LoadSetting<GameSetting>().gameName;
            Debug.Log("gameName: " + gameName);
        }
        if (GUI.Button(new Rect(0, height*3, width, height), "删除设置存档", buttonStyle))
        {
            SaveManager.Instance.DeleteAllSetting();
        }

        //用户存档
        if (GUI.Button(new Rect(width, 0, width, height), "添加一个存档", buttonStyle))
        {
            saveItem = SaveManager.Instance.CreateSaveItem();
        }
        if (GUI.Button(new Rect(width, height, width, height), "保存用户存档数据1", buttonStyle))
        {
            info["name"] = "小明";
            info["age"] = "15";
            info["heright"] = "180";
            SaveManager.Instance.SaveObject(info, saveItem);
        }
        if (GUI.Button(new Rect(width, height*2, width, height), "追加数据2", buttonStyle))
        {
            SaveManager.Instance.SaveObject(gameSetting, saveItem);
        }
        if (GUI.Button(new Rect(width, height*3, width, height), "打印用户存档数据1", buttonStyle))
        {
            Dictionary<string, string> info = SaveManager.Instance.LoadObject<Dictionary<string, string>>(saveItem);
            Debug.Log("姓名:" + info["name"] + ",年龄:" + info["age"] + ",身高:" + info["heright"]);
        }
        if (GUI.Button(new Rect(width, height*4, width, height), "获取所有用户存档", buttonStyle))
        {
            SaveManager.Instance.GetAllSaveItem();//最新的在最后面
            SaveManager.Instance.GetAllSaveItemByCreatTime();//最近创建的在最前面
            SaveManager.Instance.GetAllSaveItem();//最近更新的在最前面
        }

        //删除用户存档
        if (GUI.Button(new Rect(width*2, 0, width, height), "删除用户存档数据1", buttonStyle))
        {
            SaveManager.Instance.DeleteObject<Dictionary<string, string>>(saveItem);
        }

        if (GUI.Button(new Rect(width*2, height, width, height), "删除所有用户存档", buttonStyle))
        {
            SaveManager.Instance.DeleteAllSaveItem();
        }
        if (GUI.Button(new Rect(width*2, height*2, width, height), "删除某一个用户存档", buttonStyle))
        {
            SaveManager.Instance.DeleteSaveItem(saveItem);
        }

        //删除所有存档 用户+设置
        if (GUI.Button(new Rect(width*3, 0, width, height), "删除所有存档", buttonStyle))
        {
            SaveManager.Instance.DeleteAll();
        }
    }
}

更新

  • 2024/10/8

    第一次更新

  • 2024/10/9

    修改UI框架

    新增AudioManager音频管理器

  • 2024/10/10

    新增SaveManager数据存档持久化管理器

    UI界面基类优化

  • 2024/10/11

    框架目录调整

    SoundVolume命名错误修复

  • 2024/10/14

    修改目录结构和新增mono基类方法和工具类

封装自己的框架

如果你并不是很想使用XYFrame,而是想封装自己的框架,也可以查看我的专栏,里面详细分享了我逐步实现每个管理器的思路和方法。

注意本专栏不是教你如何使用我的框架,而是希望每个人都可以开发定制属于自己的框架。

【专栏】unity进阶知识

标签:框架,AudioManager,void,height,Instance,unity,width,public,XYFrame
From: https://blog.csdn.net/qq_36303853/article/details/142833921

相关文章

  • vue-java分享源码基于Spring Boot框架的学生作业课程管理系统的设计与实现
    目录功能和技术介绍系统实现截图本项目源码获取地址下载开发核心技术介绍:为什么选择最新的Vue与SpringBoot技术核心代码部分展示功能和技术介绍SpringBoot和Vue作为当前主流的技术框架,具有开发效率高、安全性强、用户体验良好等优点。使用开源的SpringBoot框架进行......
  • 微服务02 Kafka消息队列, Dubbo, Springcloud微服务框架, Nacos
    3.6Kafka部署kafka下载链接http://kafka.apache.org/downloads#清华源https://mirrors.tuna.tsinghua.edu.cn/apache/kafka/kafka版本格式kafka_<scala版本>_<kafka版本>#示例:kafka_2.13-2.7.0.tgz官方文档:http://kafka.apache.org/quickstart#二进制安装......
  • Java毕业设计-基于SSM框架的在线学习系统项目实战(附源码+论文)
    大家好!我是岛上程序猿,感谢您阅读本文,欢迎一键三连哦。......
  • 【Unity塔防游戏素材包】Tower Defense Pack - Low Poly 3D Art
    TowerDefensePack-LowPoly3DArt是一个专为塔防类游戏设计的Unity插件,提供丰富的低多边形3D资源,涵盖了塔防游戏所需的各种元素,如塔楼、敌人、环境道具等。这些资源风格统一,兼具简约和精致,非常适合开发具有卡通风格、低多边形风格的塔防游戏。主要功能:多样化的塔......
  • 【Unity寻路插件】A Pathfinding Project Pro
    A*PathfindingProjectPro是一款功能强大且高度优化的路径寻路插件,专为Unity开发者打造。它基于A*算法,广泛应用于游戏AI和实时策略游戏的寻路需求,尤其适合需要高效处理复杂路径计算的大型项目。该插件不仅支持常见的二维和三维场景,还提供多种寻路算法、性能优化工具......
  • Swarm 框架登场:OpenAI 第 3 阶段「敲门砖」;马斯克的 Teslabot 实际有人远程操控丨 RTE
       开发者朋友们大家好: 这里是「RTE开发者日报」,每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享RTE(Real-TimeEngagement)领域内「有话题的新闻」、「有态度的观点」、「有意思的数据」、「有思考的文章」、「有看点的会议」,但内容仅代表编......
  • 基于Java使用SpringBoot+Vue框架实现的前后端分离的美食分享平台
    ✌全网粉丝20W+,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌......
  • (开题)flask框架寝室综合管理系统(程序+论文+python)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着互联网技术的飞速发展,人们的娱乐方式日益多样化,其中网络游戏已成为众多年轻人休闲娱乐的首选。然而,在游戏过程中,许多玩家会遇到技术瓶......
  • (开题)flask框架陪玩小程序(程序+论文+python)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着互联网技术的飞速发展,人们的娱乐方式日益多样化,其中网络游戏已成为众多年轻人休闲娱乐的首选。然而,在游戏过程中,许多玩家会遇到技术瓶......
  • nbsaas vue3管理后台框架
    nbsaasvue3管理后台框架一、项目概述NbsaasAdminVue是一个基于Vue.js3.0构建的轻量级后台管理系统,结合了现代前端技术栈的最佳实践,旨在帮助开发者快速构建具有高可扩展性和良好用户体验的后台管理系统。该项目拥有简洁的UI设计,强大的功能模块,支持多种自定义配置,......