GameFrameWork框架(Unity3D)使用笔记(八) 实现场景加载进度条

Unity——两种进度条的制作 Unity两种进度条制作 阅读详情
AI摘要

文章介绍了如何在使用GameFramework框架开发游戏时,创建并显示加载进度条以提升用户体验。通过在ProcedureChangeScene流程中加载新场景并更新UI进度,确保加载界面在场景切换时正确显示。文章还提到了测试方法和解决UI重叠问题的策略,并提供了相关的代码示例。

前言:

        游戏在转换场景的时候,需要花费时间来加载相关的资源。而这个过程往往因为游戏场景的规模和复杂度以及玩家电脑配置的原因花费一小段时间(虽然这个项目里用不到)。

        所以,如果这一小段时间,画面就卡在这里,啥也做不了,玩家也不知道啥时候能加载好。这个等待的时间实际上非常地影响玩家的使用体验。

        目前大多数游戏在转换关卡这种时候都会有个加载界面,显示加载进度。这样玩家可以对啥时候能加载好有个心理预估(判断要不要因为加载太久浪费时间不如卸载游戏(开个玩笑))。

        一般加载场景显示进度条的方法搜搜就有了,就是利用Unity自带的异步加载函数SceneManager.LoadSceneAsync()加载场景,并且通过AsyncOperation跟踪加载进度,从而设置进度条之类的。

        不过,在GameFramework框架下,加载场景的模块被进一步封装,那怎么在UGF下实现加载的进度条就是本篇的主要内容。


一、实现过程讲解

        我看过一些非GF的加载场景的方案,大多数都是:对于从场景a-->场景b的过程,将其变为从场景a-->场景c-->场景b。

        其中,场景c里面主要就只有一个加载界面,主要用来显示进度条等内容。这样的话,从a->c可以非常快速地跳转(因为c中就只有个UI所以即便配置不高也能很快跳转)然后玩家在c中观看进度条的时候,后台异步加载场景b,加载完毕后立刻转到场景b。

        但是,在GF框架下,有个不同的地方。就是GF框架预制体所在的Launcher场景是一直存在的,并且框架的UI统一在这个场景里管理。

        所以在GF里实现进度条的功能,我的方案是直接在ProcedureChangeScene流程里面加载新场景的同时显示进度条UI,并且在加载完成后关闭UI。

        此外,由于一些原因(参考这一篇:http://t.csdn.cn/65FDe),想要测试这个进度条的真正效果,需要把当前工程Build再运行测试。


一、拼制UI

 在场景里面拼个进度条UI:

然后写UI的逻辑脚本,这里实现控制UI进度条的函数方便之后调用:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace ShadowU
{
    public class LoadingForm: UGuiForm
    {
        public GameObject mask;     //进度条的遮罩
        public Text loadingText;    //加载中的文字

        protected override void OnClose(bool isShutdown, object userData)
        {
            base.OnClose(isShutdown, userData);
        }

        protected override void OnInit(object userData)
        {
            base.OnInit(userData);
        }

        protected override void OnOpen(object userData)
        {
            base.OnOpen(userData);
            loadingText.text = "加载中.  .  .  .  .  .  ";
        }

        protected override void OnUpdate(float elapseSeconds, float realElapseSeconds)
        {
            base.OnUpdate(elapseSeconds, realElapseSeconds);
            //控制加载中文字后的句号浮动
            string temp = loadingText.text;
            temp.Insert(3, temp[temp.Length - 1].ToString()).Remove(temp.Length - 1);
            loadingText.text = temp;
        }
        void SetProcess(float a)
        {
            a = Mathf.Clamp(a,0f,1.0f);//将数值控制在0-1
            mask.transform.SetLocalScaleX(a);
        }
    }
}

接上脚本,设置好public参数,做成预制体:


二、修改ProcedureChangeScene流程代码

         ProcedureChangeScene开始的时候,加载出Loading界面,同时开始异步加载新场景。

        通过LoadSceneUpdateEvent事件来更新加载界面进度条的进度。

        最后,在场景加载完成后关闭Loading界面即可。

        新的ProcedureChangeScene代码如下:


using GameFramework.Fsm;
using GameFramework.Event;
using GameFramework.DataTable;
using UnityGameFramework.Runtime;
using UnityEngine;
using UnityEngine.SceneManagement;
using System;

namespace ShadowU
{
    public class ProcedureChangeScene : ProcedureBase
    {
        private const int MenuSceneId = 1;   //菜单场景的ID 

        private bool m_ChangeToMenu = false; //是否转换为菜单
        private bool m_IsChangeSceneComplete = false; //转换场景是否结束

        private LoadingForm m_LoadingForm;    //加载界面
        public override bool UseNativeDialog
        {
            get
            {
                return true;
            }
        }

        protected override void OnEnter(IFsm<GameFramework.Procedure.IProcedureManager> procedureOwner)
        {
            base.OnEnter(procedureOwner);

            Debug.Log("ChangeScene!");
            m_IsChangeSceneComplete = false; //如果为true的话 则在update中会切换流程

            //打开加载界面
            GameEntry.UI.OpenUIForm(AssetUtility.GetUIFormAsset("LoadingForm"), "Default", 1, this);

            //注册事件
            GameEntry.Event.Subscribe(LoadSceneSuccessEventArgs.EventId,OnLoadSceneSuccess);
            GameEntry.Event.Subscribe(LoadSceneFailureEventArgs.EventId, OnLoadSceneFailure);
            GameEntry.Event.Subscribe(LoadSceneUpdateEventArgs.EventId, OnLoadSceneUpdate);
            GameEntry.Event.Subscribe(LoadSceneDependencyAssetEventArgs.EventId, OnLoadSceneDependencyAsset);
            GameEntry.Event.Subscribe(OpenUIFormSuccessEventArgs.EventId,OnOpenUIFormSuccess);

            //隐藏所有实体
            GameEntry.Entity.HideAllLoadingEntities();
            GameEntry.Entity.HideAllLoadedEntities();

            //卸载所有场景
            string[] loadedSceneAssetNames = GameEntry.Scene.GetLoadedSceneAssetNames();

            foreach (string sn in loadedSceneAssetNames)
                GameEntry.Scene.UnloadScene(sn);

            //还原游戏速度
            GameEntry.Base.ResetNormalGameSpeed();

            
            //获取下一个场景的ID
            int sceneId = procedureOwner.GetData<VarInt32>("NextSceneId");
            m_ChangeToMenu = sceneId == MenuSceneId; //判断是否是转到菜单
            IDataTable<DRScene> dtScene = GameEntry.DataTable.GetDataTable<DRScene>();
            DRScene drScene = dtScene.GetDataRow(sceneId); //获取数据表行
            if(drScene == null)
            {
                Log.Warning("Can not load scene '{0}' from data table.", sceneId.ToString());
                return;
            }
            GameEntry.Scene.LoadScene(AssetUtility.GetSceneAsset(drScene.AssetName),Constant.AssetPriority.SceneAsset,this);
        }



        protected override void OnLeave(IFsm<GameFramework.Procedure.IProcedureManager> procedureOwner, bool isShutdown)
        {
            base.OnLeave(procedureOwner, isShutdown);

            GameEntry.Event.Unsubscribe(LoadSceneSuccessEventArgs.EventId, OnLoadSceneSuccess);
            GameEntry.Event.Unsubscribe(LoadSceneFailureEventArgs.EventId, OnLoadSceneFailure);
            GameEntry.Event.Unsubscribe(LoadSceneUpdateEventArgs.EventId, OnLoadSceneUpdate);
            GameEntry.Event.Unsubscribe(LoadSceneDependencyAssetEventArgs.EventId, OnLoadSceneDependencyAsset);
            GameEntry.Event.Unsubscribe(OpenUIFormSuccessEventArgs.EventId,OnOpenUIFormSuccess);

            //关闭UI
            if (m_LoadingForm != null)
            {
                m_LoadingForm.Close(isShutdown);
                m_LoadingForm = null;
            }
        }

        protected override void OnUpdate(IFsm<GameFramework.Procedure.IProcedureManager> procedureOwner, float elapseSeconds, float realElapseSeconds)
        {
            base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);


            if (!m_IsChangeSceneComplete)   
            {
                return;  //还没完成场景切换
            }

            if (m_ChangeToMenu)
            {
                ChangeState<ProcedureMenu>(procedureOwner);   //菜单
            }else
            {
                ChangeState<ProcedureMain>(procedureOwner);   //游戏运行流程
            }
        }
        
        private void OnLoadSceneSuccess(object sender,GameEventArgs e)
        {
            LoadSceneSuccessEventArgs ne = (LoadSceneSuccessEventArgs)e;
            if(ne.UserData != this)
            {
                return;
            }
            Log.Info("Load scene '{0}' OK.", ne.SceneAssetName);
            m_IsChangeSceneComplete = true;
        }
        private void OnLoadSceneFailure(object sender, GameEventArgs e)
        {
            LoadSceneFailureEventArgs ne = (LoadSceneFailureEventArgs)e;
            if (ne.UserData != this)
            {
                return;
            }

            Log.Error("Load scene '{0}' failure, error message '{1}'.", ne.SceneAssetName, ne.ErrorMessage);
        }

        private void OnLoadSceneUpdate(object sender, GameEventArgs e)
        {
            LoadSceneUpdateEventArgs ne = (LoadSceneUpdateEventArgs)e;
            if (ne.UserData != this)
            {
                return;
            }

            Log.Info("Load scene '{0}' update, progress '{1}'.", ne.SceneAssetName, ne.Progress.ToString("P2"));
            //更新加载界面的进度条
            if(m_LoadingForm != null)
                m_LoadingForm.SetProcess(ne.Progress);
        }

        private void OnLoadSceneDependencyAsset(object sender, GameEventArgs e)
        {
            LoadSceneDependencyAssetEventArgs ne = (LoadSceneDependencyAssetEventArgs)e;
            if (ne.UserData != this)
            {
                return;
            }

            Log.Info("Load scene '{0}' dependency asset '{1}', count '{2}/{3}'.", ne.SceneAssetName, ne.DependencyAssetName, ne.LoadedCount.ToString(), ne.TotalCount.ToString());
        }
        private void OnOpenUIFormSuccess(object sender, GameEventArgs e)
        {
            OpenUIFormSuccessEventArgs ne = (OpenUIFormSuccessEventArgs)e;
            if (ne.UserData != this)
            {
                return;
            }

            m_LoadingForm = (LoadingForm)ne.UIForm.Logic;
        }
    }
}

 三、测试效果

        直接编辑器模式运行的话看场景加载并不是异步的,所以要测试这个进度条的真正效果需要打包运行。

        关于打包的过程之后的文章里会讲,这里就先跳过了。

        测试:

 进度条的功能是完成了!

但是。。。又出了新的问题:菜单界面在加载界面之上。

不过编辑器模式运行并没有这个问题:

    

但是没有问题只是看上去的。。。如果我立即暂停后观察,其实这个模式下也会两个UI同屏,只不过相对来说时间比较短暂。我经过一段时间分析后,想到UGuiForm里面在关闭和打开界面的时候都有淡入淡出的逻辑,于是作出如下假设:

加载界面看到菜单界面并不是渲染层级先后的问题,而是它们都在淡入或淡出过程中。所以说,他们都处于半透明状态所以能都看得见。

(因为基于这个假设能解决问题那我就不去证明我这个假设到底对不对了嘿嘿~) 

那解决办法就很灵活了。比如可以判断取消打开加载界面的淡入效果。不过我觉得这样改结构会很不美观。

于是我打算这样处理:让加载界面至少停留一秒。同时减小淡入淡出的时间。

在UGuiForm.cs里面修改淡入淡出时间

修改一下ProcedureChangeScene的代码(增加了和loadingTimer变量有关的部分):


using GameFramework.Fsm;
using GameFramework.Event;
using GameFramework.DataTable;
using UnityGameFramework.Runtime;
using UnityEngine;
using UnityEngine.SceneManagement;
using System;

namespace ShadowU
{
    public class ProcedureChangeScene : ProcedureBase
    {
        private const int MenuSceneId = 1;   //菜单场景的ID 

        private bool m_ChangeToMenu = false; //是否转换为菜单
        private bool m_IsChangeSceneComplete = false; //转换场景是否结束

        private LoadingForm m_LoadingForm;    //加载界面
        private float loadingTimer;           //加载界面停留的计时器
        public override bool UseNativeDialog
        {
            get
            {
                return true;
            }
        }

        protected override void OnEnter(IFsm<GameFramework.Procedure.IProcedureManager> procedureOwner)
        {
            base.OnEnter(procedureOwner);

            Debug.Log("ChangeScene!");
            m_IsChangeSceneComplete = false; //如果为true的话 则在update中会切换流程

            //打开加载界面
            GameEntry.UI.OpenUIForm(AssetUtility.GetUIFormAsset("LoadingForm"), "Default", 1, this);
            loadingTimer = 1.0f;         //加载界面至少停留一秒

            //注册事件
            GameEntry.Event.Subscribe(LoadSceneSuccessEventArgs.EventId,OnLoadSceneSuccess);
            GameEntry.Event.Subscribe(LoadSceneFailureEventArgs.EventId, OnLoadSceneFailure);
            GameEntry.Event.Subscribe(LoadSceneUpdateEventArgs.EventId, OnLoadSceneUpdate);
            GameEntry.Event.Subscribe(LoadSceneDependencyAssetEventArgs.EventId, OnLoadSceneDependencyAsset);
            GameEntry.Event.Subscribe(OpenUIFormSuccessEventArgs.EventId,OnOpenUIFormSuccess);

            //隐藏所有实体
            GameEntry.Entity.HideAllLoadingEntities();
            GameEntry.Entity.HideAllLoadedEntities();

            //卸载所有场景
            string[] loadedSceneAssetNames = GameEntry.Scene.GetLoadedSceneAssetNames();

            foreach (string sn in loadedSceneAssetNames)
                GameEntry.Scene.UnloadScene(sn);

            //还原游戏速度
            GameEntry.Base.ResetNormalGameSpeed();

            
            //获取下一个场景的ID
            int sceneId = procedureOwner.GetData<VarInt32>("NextSceneId");
            m_ChangeToMenu = sceneId == MenuSceneId; //判断是否是转到菜单
            IDataTable<DRScene> dtScene = GameEntry.DataTable.GetDataTable<DRScene>();
            DRScene drScene = dtScene.GetDataRow(sceneId); //获取数据表行
            if(drScene == null)
            {
                Log.Warning("Can not load scene '{0}' from data table.", sceneId.ToString());
                return;
            }
            GameEntry.Scene.LoadScene(AssetUtility.GetSceneAsset(drScene.AssetName),Constant.AssetPriority.SceneAsset,this);
        }



        protected override void OnLeave(IFsm<GameFramework.Procedure.IProcedureManager> procedureOwner, bool isShutdown)
        {
            base.OnLeave(procedureOwner, isShutdown);

            GameEntry.Event.Unsubscribe(LoadSceneSuccessEventArgs.EventId, OnLoadSceneSuccess);
            GameEntry.Event.Unsubscribe(LoadSceneFailureEventArgs.EventId, OnLoadSceneFailure);
            GameEntry.Event.Unsubscribe(LoadSceneUpdateEventArgs.EventId, OnLoadSceneUpdate);
            GameEntry.Event.Unsubscribe(LoadSceneDependencyAssetEventArgs.EventId, OnLoadSceneDependencyAsset);
            GameEntry.Event.Unsubscribe(OpenUIFormSuccessEventArgs.EventId,OnOpenUIFormSuccess);

            //关闭UI
            if (m_LoadingForm != null)
            {
                m_LoadingForm.Close(isShutdown);
                m_LoadingForm = null;
            }
        }

        protected override void OnUpdate(IFsm<GameFramework.Procedure.IProcedureManager> procedureOwner, float elapseSeconds, float realElapseSeconds)
        {
            base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);


            if (!m_IsChangeSceneComplete)   
            {
                return;  //还没完成场景切换
            }

            m_LoadingForm.SetProcess(1);

            if(loadingTimer > 0)  
            {
                loadingTimer -= elapseSeconds;//更新计时器
                return;
            }

            if (m_ChangeToMenu)
            {
                ChangeState<ProcedureMenu>(procedureOwner);   //菜单
            }else
            {
                ChangeState<ProcedureMain>(procedureOwner);   //游戏运行流程
            }
        }
        
        private void OnLoadSceneSuccess(object sender,GameEventArgs e)
        {
            LoadSceneSuccessEventArgs ne = (LoadSceneSuccessEventArgs)e;
            if(ne.UserData != this)
            {
                return;
            }
            Log.Info("Load scene '{0}' OK.", ne.SceneAssetName);
            m_IsChangeSceneComplete = true;
        }
        private void OnLoadSceneFailure(object sender, GameEventArgs e)
        {
            LoadSceneFailureEventArgs ne = (LoadSceneFailureEventArgs)e;
            if (ne.UserData != this)
            {
                return;
            }

            Log.Error("Load scene '{0}' failure, error message '{1}'.", ne.SceneAssetName, ne.ErrorMessage);
        }

        private void OnLoadSceneUpdate(object sender, GameEventArgs e)
        {
            LoadSceneUpdateEventArgs ne = (LoadSceneUpdateEventArgs)e;
            if (ne.UserData != this)
            {
                return;
            }

            Log.Info("Load scene '{0}' update, progress '{1}'.", ne.SceneAssetName, ne.Progress.ToString("P2"));
            //更新加载界面的进度条
            if(m_LoadingForm != null)
                m_LoadingForm.SetProcess(ne.Progress);
        }

        private void OnLoadSceneDependencyAsset(object sender, GameEventArgs e)
        {
            LoadSceneDependencyAssetEventArgs ne = (LoadSceneDependencyAssetEventArgs)e;
            if (ne.UserData != this)
            {
                return;
            }

            Log.Info("Load scene '{0}' dependency asset '{1}', count '{2}/{3}'.", ne.SceneAssetName, ne.DependencyAssetName, ne.LoadedCount.ToString(), ne.TotalCount.ToString());
        }
        private void OnOpenUIFormSuccess(object sender, GameEventArgs e)
        {
            OpenUIFormSuccessEventArgs ne = (OpenUIFormSuccessEventArgs)e;
            if (ne.UserData != this)
            {
                return;
            }

            m_LoadingForm = (LoadingForm)ne.UIForm.Logic;
        }
    }
}

此外还有个细节:就是进度条到90就不动了。其实场景加载到90%的时候就已经加载完了,最后的10%就在于有没有把场景显示出来。那为了看起来不膈应,我上面的代码里在加载完场景后手动把进度条设置为100:

打包看下最终效果:

 效果挺理想的,那就这样了!

        

Unity场景进度条加载 首先,创建Canvas,在Canvas中创建一个Button和一个Panel Button:点击之后进入场景加载 Panel:场景加载面板 其次,在panel当中,我们在创建slider和Text Text:用来描述进度条的百分比,所以text可有可无,看自己意愿 slider :就是我们的进度条了 Panel建好后,将SetActive设置为false,因为进度条要在点击Button后才会出现 所有gameobject创建好后,我们就可以开始写脚本了。关于进度条的脚本... 阅读详情

相关推荐

GameFrameWork框架(Unity3D)实战指南:从AssetBundle配置到热更新发布

本文详细介绍了GameFrameWork框架在Unity3D中的实战应用,重点讲解AssetBundle配置与热更新发布的完整流程。通过XML文件配置资源打包规则、资源分组原则及打包策略,帮助开发者高效管理游戏资源。同时提供热更新实战方案和常见问题排查技巧,助力游戏开发流程优化。

weixin_29196613的博客 427

Unity实现场景加载进度条

学习使用场景加载进度条

qq_44887198的博客 1450

【GameFramework框架】一、框架介绍

这是GameFramework框架教程的第一篇,但是博主不准备直接就讲GameFramework框架。【GameFramework框架】二、GameFramework框架介绍了。框架(Framework)通常被理解为一种基础要素的集合,它们用于承载系统的必要功能。约束性:框架定义了解决特定问题的边界,并将相关的软件组件约束在这个范围内,以保持框架的内聚性和解决问题的专注性。支撑性:框架本身不直接解决问题,而是提供一个基础的支撑结构,使得在其上构建的解决方案更为灵活和高效。

优快云博客专家,Unity3D高级软件工程师,《Unity 3D从入门到实战》作者。 1万+

GameFramework框架

ellan做事风格非常低调,属于实干派,几乎没有宣传过框架,但是多年持续维护更新,框架实际是提炼于知名的商业项目。虽然框架文档十分匮乏,新人上手相对困难,但是GF依然靠着过硬的代码质量吸引开发者使用和学习。每个模块的xxxManager都会实现对应的IxxxManager接口,UGF只会直接引用接口,不会直接引用Manager。如果需要调用依赖于引擎实现的接口,可以定义对应的IHelper接口并在UGF层实现接口,GF层只管调用不管具体实现。对常用模块封装,规范开发过程,保证产品质量,内置19个模块。

—巨人绿 4507

【Unity3D框架】GameFramework框架完全教程《全网最全》-专栏文章目录

最近准备学习框架,了解到GameFramework框架是国产Unity3D框架,准备学习一下,但是奈何全网关于这个框架的教程实在太少。为了让自己学习方便一些,也为了让后来者乘凉。将框架以自己的理解整理目录,并且补全教程。觉得教程有帮助别忘了一键三连哦。

优快云博客专家,Unity3D高级软件工程师,《Unity 3D从入门到实战》作者。 2万+

【GameFramework框架内置模块】15、场景(Scene)

场景(Scene)模块,提供场景管理的功能,负责场景的加载、卸载、切换和管理。可以方便地管理不同场景之间的切换以及不同场景之间的信息传递。

优快云博客专家,Unity3D高级软件工程师,《Unity 3D从入门到实战》作者。 1883

GameFrameWork框架(Unity3D)使用笔记(一)Entry

GameFrameWork框架(Unity3D)使用笔记(一)Entry。本篇讲解了如何引用框架以及创建GameEntry。

HowToPause的博客 6942

【GameFramework框架内置模块】18、界面(UI)

界面(UI)提供管理UI界面和界面组的功能,比如显示界面、激活界面、改变界面层级等。界面(UI)为Unity的GUI系统提供了灵活和强大的功能,帮助开发者快速构建游戏UI。还可以与现有的Unity 的UI插件(如NGUI、FGUI)及GUI系统(UGUI)无缝集成,只要派生自类并实现自己的界面类即可使用。界面使用结束后可以不立即销毁,等待下一次使用。

优快云博客专家,Unity3D高级软件工程师,《Unity 3D从入门到实战》作者。 3133

GameFrameWork框架(Unity3D)使用笔记(二)ProcedureChangeScene

上一篇中已经成功引入了框架,并且创建了游戏入口。本篇的主要内容为创建游戏的启动流程,场景转换流程(本来要写菜单流程但是最后发现篇幅太大。。。。)(再次强调,本系列笔记偏实践,主要记录使用过程,对于具体的框架讲解可以搜到很多大佬的教程,同时也非常建议自行阅读源码,可以学到很多。)如果看过可以看到它里面做了很多的流程,比如版本检测、资源检测、更新、预加载、场景切换、初始化资源等。而我这里就不全部模仿了。在这次的案例中,我先只写几个必要的流程,先能跑起来再说。

HowToPause的博客 3212

【GameFramework扩展应用】6-4、GameFramework框架增加AB包加解密功能

做热更的时候加载的是资源,如果不对这些资源进行加密的话,很容易被人破解,那么应该如何做加解密呢。内置的:使用的加密算法为GameFramework.Utility.Encryption.GetQuickXorBytes();:使用的加密算法为GameFramework.Utility.Encryption.GetXorBytes();OK,那么要如何是实现我们自定义的加解密方法呢。因为加载方式会走LoadResourceAgentHelper的ParseBytes(byte[] bytes)

优快云博客专家,Unity3D高级软件工程师,《Unity 3D从入门到实战》作者。 2334

【GameFramework扩展应用】6-1、接入热更新框架HybridCLR

是一款基于Unity的通用游戏框架。提供了游戏开发中常用的框架基础模块,将基础模型进行了封装,在资源管理和资源更新方面比较完善,可以大大加大开发进程,加快开发速度,并且还在在此此处上保证产品质量。HybridCLR是一款特性完整、零成本、高性能、低内存的近乎完美的C#热更新方案。这篇文章就来介绍一下的示例项目StarForce是如何接入HybridCLR热更新框架的。*注意:这篇文章的重点是接入HybridCLR热更新框架,将不过多介绍HybridCLR热更新框架是如何实现热更新流程的,对于。

优快云博客专家,Unity3D高级软件工程师,《Unity 3D从入门到实战》作者。 1667

【Unity 3D】GameFramework、QFramework框架简介及应用实战(超详细 附源码)

【Unity 3D】GameFramework、QFramework框架简介及应用实战(超详细 附源码)

showswoller的博客 1万+

【GameFramework扩展应用】6-3、GameFramework框架增加日志保存功能

GameFramework框架运行后,可以发现Game视图有个小按钮,点开就是框架提供的调试器窗口:Console选项卡可以在运行的时看不同的日志类型,来分析我们项目运行中出现的问题。当然,除了在控制台打印日志,我们使用框架更多的是想要将日志保存到文件的功能,这样才能方便查看。接下来就来看一下如何实现日志保存功能。

优快云博客专家,Unity3D高级软件工程师,《Unity 3D从入门到实战》作者。 841

GameFrameWork框架(Unity3D)使用笔记(九) AssetBundle和游戏打包

如果使用了GameFrameWork框架的话,你会发现你点击Build And Run按钮打包运行大概是运行不起来的。本篇就讲了怎么打包游戏运行。我觉得我对于资源加载这块儿理解也不够深,所以本篇主要记录方法流程,不讲原理。想探究原理的可以先去看看官方手册,看看GF官网,然后看看其它GF大佬的B站视频啊,博客啊啥的(多看看,每一篇都有值得吸收的碎片,然后把这些碎片再拼成自己脑中的体系图景)。废话不多说,开干!

HowToPause的博客 5434

系统安装、qt配置、安装pcie驱动

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 安装Linux系统指定:ununtu20.04并配置相关软件环境 前言 提示:这里可以添加本文要记录的大概内容: ununtu20.04、Qt 5.9.0、pcie驱动 提示:以下是本篇文章正文内容,下面案例可供参考 一、安装系统 制作系统盘(win10),在开机时按相应键进入BIOS,(华硕需要先改配置启动->CSM->开启->第一个选项选第一个或第二个),等待即可 进入后按照https://www.sysgeek.

weixin_44832804的博客 2205

窥秘Windows 10:SAM密码破解

Windows 10作为广受欢迎的操作系统,拥有一套强大的安全措施来保护用户账号和数据安全。然而,有时候我们需要了解更多关于密码破解的知识,以加强我们的防护措施。本文将深入探讨如何突破Windows 10的SAM密码,以便更好地了解密码安全性并加强系统的保护。

Sgirll的博客 6842

GameFrameWork框架(Unity3D)实践笔记(一)启动与入口设计

本文详细介绍了在Unity3D项目中实践GameFrameWork框架的第一步:设计与实现自定义的GameEntry入口。通过创建partial class“三件套”,将框架内置组件与游戏自定义逻辑解耦,提供统一的静态访问点,为构建健壮、可维护的游戏项目奠定坚实的架构基础。

weixin_29011667的博客 227

手把手教你用Python实现双三次插值(附OpenCV对比测试)

本文深入解析了双三次插值算法的数学原理,并提供了从零开始的Python实现教程。通过与OpenCV官方实现的对比测试,详细评估了不同插值算法(包括最邻近差值、双线性插值)在图像质量与计算性能上的差异,帮助开发者掌握高质量图像缩放的核心技术。

weixin_29310605的博客 294

GameFrameWork框架(Unity3D)实战指南:从AssetBundle配置到独立游戏构建

本文详细介绍了GameFrameWork框架在Unity3D中的实战应用,重点讲解AssetBundle配置与独立游戏构建流程。从资源编辑器环境搭建到AssetBundle打包策略,再到游戏构建集成,提供了一套完整的解决方案,帮助开发者高效管理游戏资源并实现热更新功能。

weixin_30825581的博客 485

PotPlayer终极画质调校:深入MadVR渲染器设置,让你的显示器发挥100%潜力

本文深入探讨了如何通过MadVR渲染器优化PotPlayer的画质设置,充分发挥高端显卡和显示器的潜力。从色彩空间匹配、色深优化到HDR元数据处理,提供了一套完整的配置指南,帮助用户实现影院级视觉体验。特别适合拥有NVIDIA RTX或AMD RX系列显卡的用户进行精细调校。

weixin_42530458的博客 600

汽车电子电气架构

控制器:从多独立 ECU → 域控制器(DCU) → 中央计算平台 + 区域控制器,硬件集成度持续提升,冗余减少;算力:从分散无集中算力 → 按域分配算力 → 全域算力集中,算力量级从 MIPS 跃升至 TOPS,支撑高阶智驾;网络:从低速 CAN/LIN 独占 → 以太网为主、总线为辅 → 高速以太网主干,数据传输速率提升千倍;软硬件:从软硬件深度绑定 → 初步解耦 → 完全解耦(SOA),实现 “硬件预埋、软件解锁”;线束。

LXY_LXY_的博客 1436

GameFrameWork框架(Unity3D)实践笔记(一) 核心入口与模块化设计

本文详细介绍了在Unity3D项目中实践GameFrameWork框架的第一步:创建核心入口GameEntry与实现模块化设计。通过分析框架自带的Entry内核与自定义入口的区别,阐述了自定义GameEntry在解耦、集中管理和预留扩展方面的重要作用。文章提供了从项目准备、代码编写到场景配置的完整实践步骤,并强调了模块化设计思想对构建清晰、可维护游戏架构的关键意义。

weixin_28025327的博客 246

同花顺PC端逆向解析:Hook注入与加密破解实战指南

在Windows客户端数据采集场景中,当常规HTTP爬虫失效时,内存级逆向分析成为获取实时行情数据的关键路径。其核心涉及进程注入、运行时解密、反调试绕过等底层技术,本质是理解PE加载机制、函数调用约定与内存保护策略的协同过程。同花顺作为典型加固客户端,采用ASPack加壳+自研解密+多线程校验三重防护,迫使开发者转向APC注入、动态密钥提取与XXTEA算法复刻等高阶手段。本文聚焦于DLL注入选型依据、解密函数定位方法及二进制Blob结构化解析,最终实现从内存读取到Pandas DataFrame的端到端数据

weixin_32234493的博客 1198

[GameFramework]Demo1-如何创建一个GameFramework项目

为了弥补官方文档的严重缺失,同时也希望Game Framework这个框架能稍微流行开来(不管它优不优秀,代码是绝对值得学习的),木头我就自愿帮框架作者写一些基础的Demo教程吧。 噢,天呐,我真伟大(注意,这不是一篇翻译的文章!) 这一篇,我们先从创建一个GameFramework项目开始。 1.下载GameFramework Package 首先要到框架的官网下载资源包:http://gameframework.cn/download 资源包里包含了GameFramework框架的Dll(源码可以到

fuqiang3270的专栏 744

Go语言爬虫:chromedp 的详细使用

chromedp 是 Go 语言中无头浏览器自动化的终极利器。它能驱动真实的 Chrome 浏览器,处理 JavaScript 渲染、复杂交互和反爬虫机制

数据知道的博客 4493

[QMT量化交易小白入门]-十二、QMT回测龙头打首板和连板的策略

class a():passA = a() #创建空的类的实例 用来保存委托状态field_list定义了需要的市场数据字段,而类a用于保存交易状态。

木头大左的博客 4757
上一篇: 基于pyautogui的自动识别定位原神风物之诗琴按键弹奏程序
下一篇: GameFrameWork框架(Unity3D)使用笔记(九) AssetBundle和游戏打包
咖啡咖_CoffCa
博客等级 码龄6年 116粉丝 58原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

咖啡咖_CoffCa

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值