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

news2025/1/13 9:46:49

目录

前言:

整个流程:

一、配置路径

二、打包

三、初始化资源

四、测试打包


前言:

        如果使用了GameFrameWork框架的话,你会发现你点击Build And Run按钮打包运行大概是运行不起来的。本篇就讲了怎么打包游戏运行。

        我觉得我对于资源加载这块儿理解也不够深,所以本篇主要记录方法流程,不讲原理。想探究原理的可以先去看看官方手册,看看GF官网,然后看看其它GF大佬的B站视频啊,博客啊啥的(多看看,每一篇都有值得吸收的碎片,然后把这些碎片再拼成自己脑中的体系图景)。       

        废话不多说,开干!

整个流程:

  •    配置路径,准备用UGF自带的Editor打包
  •    打出AB包
  •    把打好的包复制进StreamingAssets文件夹(如果已经build了)    
  •    build工程

一、配置路径

        如过没有配置过路径的话,打开GameFramework的资源工具Resource Editor是这样的:

        

也就是最右边一列的资产列表是空的。

(关于这个打包工具官网有相关介绍可以先看看)

所以这里需要自己手动添加一个配置文件,告诉这个打包器需要打包的资源路径。

在Assets/GameMain/Configs下手动创建文件ResourceEditor.xml:

内容为:

<?xml version="1.0" encoding="UTF-8"?>
<UnityGameFramework>
  <ResourceEditor>
    <Settings>
      <SourceAssetRootPath>Assets/GameMain</SourceAssetRootPath>
      <SourceAssetSearchPaths>
        <SourceAssetSearchPath RelativePath="" />
      </SourceAssetSearchPaths>
      <SourceAssetUnionTypeFilter>t:Scene t:Prefab t:Shader t:Model t:Material t:Texture t:AudioClip t:AnimationClip t:AnimatorController t:Font t:TextAsset t:ScriptableObject</SourceAssetUnionTypeFilter>
      <SourceAssetUnionLabelFilter>l:ResourceInclusive</SourceAssetUnionLabelFilter>
      <SourceAssetExceptTypeFilter>t:Script</SourceAssetExceptTypeFilter>
      <SourceAssetExceptLabelFilter>l:ResourceExclusive</SourceAssetExceptLabelFilter>
      <AssetSorter>Path</AssetSorter>
    </Settings>
  </ResourceEditor>
</UnityGameFramework>

 (配置文件的内容看英文就明白个大概了,如果想弄懂的话)

配置文件创建了,然后要告诉框架这个配置文件的路径,需要使用一个叫“ResourceEditorConfigPath”的属性来配置。下面来搞。

在Assets/GameMain/Scripts路径下建立Editor文件夹:

文件夹里面手动创建GameFrameworkConfigs.cs(名字实际上应该无所谓):

 里面配置一下刚刚创建的配置文件的路径:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using GameFramework;
using UnityGameFramework.Editor.ResourceTools;
using System.IO;
namespace ShadowU
{
    public static class GameFrameworkConfigs
    {
        [ResourceEditorConfigPath]
        public static string ResourceEditorConfig = Utility.Path.GetRegularPath(Path.Combine(Application.dataPath, "GameMain/Configs/ResourceEditor.xml"));
    }
}

如果不懂为啥可以去恶补一下c#的Attribute的相关知识。

保存。

然后再打开打包的资源编辑器:

这样在右边一列就能够看到自己的资源了。


二、打包

然后打包的任务通俗的说就是把右边的资源放到左边。这个界面的操作说明官网有(官网为数不多的教程就有讲这个的。。。)

然后关于打AB包怎么组合比较好可以参考Unity的官方手册:为 AssetBundle 准备资源 - Unity 手册 (unity3d.com)

这里为了演示就不一个包一个包打了直接一把梭:

然后左边就是选择打包的文件:

 细节不管了,先跑起来再说。

点击右下角save(默认会在Assets/GameFramework/Configs路径下生成ResourceCollection.xml):

然后打开工具的builder:

自己设置好你的Output Directory。

(这里的Internal Resource Version每打一次包就会自增,所以我这里是10.。。。)

 save是保存这个界面填写的配置(默认会在Assets/GameFramework/Configs路径下生成ResourceBuilder.xml)。

按Start Build Resources开始打包!

打包后,到自己设置的输出文件夹里:

 各个文件夹的介绍官网都有写:使用 AssetBundle 构建工具 | Game Framework

然后我们只需要把 Package(单机模式)或 Packed(可更新模式)中对应版本(如 0_1_0_1)、对应平台的内容(如 windows),完整拷贝至 Unity 工程的 Assets/StreamingAssets 中,即可Build了。(StreamingAssets文件夹自己创建):

 然后打包之前可以先在编译器运行一下非编译器资源模式。

把这个取消勾选:

然后运行。。。。。

你会发现报错,运行不了。

因为还有一步。


三、初始化资源

虽然已经把游戏所需要的资源打包放好了,但是要让程序使用它们还得通过框架对这些资源进行初始化。

不过初始化很简单,就一个语句:

GameEntry.Resource.InitResources(OnInitResourcesComplete);

其中传入的OnInitResourcesComplete是初始化完成的回调函数。

用一个标记来判断是否初始化完成:

m_InitResourcesComplete = false;

 回调函数就这么写:

        private void OnInitResourcesComplete()
        {
            m_InitResourcesComplete = true;
            Log.Info("Init resources complete.");
        }

 因为我流程写得相对于StarForce的精简了很多,所以我初始化资源、加载资源、启动游戏等逻辑都放在了ProcedureLaunch.cs里面,所以我加了一点处理来保证初始化资源-->初始化完成-->加载资源-->加载资源完成-->启动游戏这些操作按顺序执行。所以代码如下:

(如果觉得乱直接去学习StarForce的代码即可)

 using GameFramework.Fsm;
using GameFramework.Event;
using UnityGameFramework.Runtime;
using System.Collections.Generic;
using UnityEngine;
namespace ShadowU
{
    public class ProcedureLaunch : ProcedureBase
    {
        public override bool UseNativeDialog
        {
            get
            {
                return true;
            }
        }

        private Dictionary<string, bool> m_LoadedFlag = new Dictionary<string, bool>();//用来标记是否已经加载

        private bool m_InitResourcesComplete = false;

        private bool temp = false;

        public static readonly string[] DataTableNames = new string[]
       {
            "Scene",
            "Character",
            "Entity",
            "Enemy"
       };

        protected override void OnEnter(IFsm<GameFramework.Procedure.IProcedureManager> procedureOwner)
        {
            base.OnEnter(procedureOwner);
            Debug.Log("launch!");

            //初始化资源标记
            m_InitResourcesComplete = false;

            temp = false;

            // 注意:使用单机模式并初始化资源前,需要先构建 AssetBundle 并复制到 StreamingAssets 中,否则会产生 HTTP 404 错误
            GameEntry.Resource.InitResources(OnInitResourcesComplete);

            //注册事件
            GameEntry.Event.Subscribe(LoadConfigSuccessEventArgs.EventId, OnLoadConfigSuccess);
            GameEntry.Event.Subscribe(LoadConfigFailureEventArgs.EventId, OnLoadConfigFailure);
            GameEntry.Event.Subscribe(LoadDataTableSuccessEventArgs.EventId, OnLoadDataTableSuccess);
            GameEntry.Event.Subscribe(LoadDataTableFailureEventArgs.EventId, OnLoadDataTableFailure);

           
        }

        protected override void OnLeave(IFsm<GameFramework.Procedure.IProcedureManager> procedureOwner, bool isShutdown)
        {
            base.OnLeave(procedureOwner, isShutdown);
            //注销事件
            GameEntry.Event.Unsubscribe(LoadConfigSuccessEventArgs.EventId, OnLoadConfigSuccess);
            GameEntry.Event.Unsubscribe(LoadConfigFailureEventArgs.EventId, OnLoadConfigFailure);
            GameEntry.Event.Unsubscribe(LoadDataTableSuccessEventArgs.EventId, OnLoadDataTableSuccess);
            GameEntry.Event.Unsubscribe(LoadDataTableFailureEventArgs.EventId, OnLoadDataTableFailure);

        }

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

            if (!m_InitResourcesComplete)
            {
                // 初始化资源未完成则继续等待
                return;
            }

            if (!temp)//temp用于保证这里的代码只执行一次
            {
                m_LoadedFlag.Clear();
                //预加载配置
                PreloadResources();
                //加载数据表
                foreach (string dataTableName in DataTableNames)
                {
                    LoadDataTable(dataTableName);
                }
                temp = true;
            }

            foreach (KeyValuePair<string,bool> loadedFlag in m_LoadedFlag)
            {
                if (!loadedFlag.Value)
                {
                    return;//说明有资源没有加载成功
                }
            }

            //通过加载的配置表来设置下一个转换场景的ID
            procedureOwner.SetData<VarInt32>("NextSceneId",GameEntry.Config.GetInt("Scene.Menu"));
            //一帧后直接转到菜单流程
            ChangeState<ProcedureChangeScene>(procedureOwner);
        }

        private void PreloadResources()
        {
            LoadConfig("DefaultConfig");
        }

        private void LoadConfig(string configName)
        {
            string configAssetName = AssetUtility.GetConfigAsset(configName, false);
            m_LoadedFlag.Add(configAssetName, false);
            GameEntry.Config.ReadData(configAssetName, this);
        }
        private void LoadDataTable(string dataTableName)
        {
            string dataTableAssetName = AssetUtility.GetDataTableAsset(dataTableName, false);
            m_LoadedFlag.Add(dataTableAssetName, false);
            GameEntry.DataTable.LoadDataTable(dataTableName, dataTableAssetName, this);
        }

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

            m_LoadedFlag[ne.ConfigAssetName] = true;  //资源加载成功了则设置一下标记为true
            Log.Info("Load config '{0}' OK.", ne.ConfigAssetName);
        }

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

            Log.Error("Can not load config '{0}' from '{1}' with error message '{2}'.", ne.ConfigAssetName, ne.ConfigAssetName, ne.ErrorMessage);
        }
        private void OnLoadDataTableSuccess(object sender, GameEventArgs e)
        {
            LoadDataTableSuccessEventArgs ne = (LoadDataTableSuccessEventArgs)e;
            if (ne.UserData != this)
            {
                return;
            }

            m_LoadedFlag[ne.DataTableAssetName] = true;
            Log.Info("Load data table '{0}' OK.", ne.DataTableAssetName);
        }

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

            Log.Error("Can not load data table '{0}' from '{1}' with error message '{2}'.", ne.DataTableAssetName, ne.DataTableAssetName, ne.ErrorMessage);
        }
        private void OnInitResourcesComplete()
        {
            m_InitResourcesComplete = true;
            Log.Info("Init resources complete.");
        }
    }

}

 搞定。


四、测试打包

再在编译器运行一下非编译器资源模式:

 可以启动,点击开始后也能正常运行。

那下面就可以打包了:

Build And Run,选择好文件夹,打包,运行!

 搞定!

同时StreamingAssets文件夹的内容会同时拷贝到打包好的工程的StreamingAssets文件夹:

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/178953.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

什么是YOLOR?

简述YOLOR 是一种用于对象检测的最先进的机器学习算法&#xff0c;与 YOLOv1-YOLOv5 不同&#xff0c;原因在于作者身份、架构和模型基础设施的差异。YOLOR 代表“你只学习一种表示”&#xff0c;不要与 YOLO 版本 1 到 4 混淆&#xff0c;其中 YOLO 代表“你只看一次”。 YOLO…

Docker的常用命令

文章目录 目录 文章目录 前言 一、帮助命令 二、镜像命令 1.查看镜像 2.搜索镜像 3.下载镜像 4.删除镜像 三、容器命令 1.启动容器 2.查看容器 3.退出容器 4.删除容器 5.启动和停止容器 四、常用的其它命令 后台运行 查看日志 查看容器中进程的信息 查看镜像的元数据…

lego-loam学习笔记(一)

前言&#xff1a; 主要记录配置编译lego-loam源码时遇到的问题和解决的方法。 系统&#xff1a;ubuntu18.04 一、安装gtsam 因为系统是18.04所以不需要作很大的更改&#xff0c;按照官网的doc一步一步的来就行了。 根据官网&#xff1a; GitHub - RobustFieldAutonomyLab…

DlhSoft Gantt Chart Light Library自定义的网格列

DlhSoft Gantt Chart Light Library自定义的网格列 Improved the loading of Microsoft Project XML files and the exporting of images from ScheduleChartDataGrid.Added new TotalResourceEffort and TotalResourceCompletedEffort properties to compute the real effort …

MySQL数据库数据动态监控(canal+Kafka)

参考资料: 参考文章https://gper.club/articles/7e7e7f7ff3g59gc6g6d canal官网 https://github.com/alibaba/canal

JavaWeb项目中添加live2d模型

前言&#xff1a;之前个人博客中配置的live2d模型的API失效了&#xff0c;所以重新折腾了一下&#xff0c;在自己服务器配置了 live2d 的 API&#xff0c;在此记录一下 JavaWeb项目中添加live2d模型 之前在个人博客中使用的 live2d 模型一直用的是网上一个大佬免费提供的 API …

Mybatis 的中高级特性使用

简介&#xff1a; MyBatis 的真正强大在于它的语句映射&#xff0c;这是它的魔力所在。由于它的异常强大&#xff0c;映射器的 XML 文件就显得相对简单。如果拿它跟具有相同功能的 JDBC 代码进行对比&#xff0c;你会立即发现省掉了将近 95% 的代码。MyBatis 致力于减少使用成…

小学生编程一些log

家里孩子也逐渐开始学习编程了&#xff0c;这里是一些经验积累&#xff0c;log下&#xff0c;希望能节省一些大家的探索时间&#xff1b; 方块编程 开始起手是一些scratch类的编程&#xff0c;使用方块类的&#xff0c;网课就可以&#xff0c;我这里尝试的是核桃编程&#xff…

蓝桥杯2020省赛python

蓝桥杯2020省赛Python 第一题&#xff1a;门牌制作 用了一个时间复杂度是n的算法&#xff0c;反正是填空题也不会出现TLE的事&#xff0c;只要别太离谱就行了。 利用python 的count函数 res 0 for i in range(1,2021):i str(i)res i.count(2) print(res)答案是2 第二题&…

【目标检测论文解读复现NO.26】基于改进YOLOv5s网络的实时输液监测

前言 此前出了目标改进算法专栏&#xff0c;但是对于应用于什么场景&#xff0c;需要什么改进方法对应与自己的应用场景有效果&#xff0c;并且多少改进点能发什么水平的文章&#xff0c;为解决大家的困惑&#xff0c;此系列文章旨在给大家解读最新目标检测算法论文&#xff0c…

115、【回溯算法】leetcode ——216.组合总和III:回溯法+剪枝优化(C++版本)

题目描述 原题链接&#xff1a;216.组合总和III 解题思路 整体回溯法思路类似于 77. 组合&#xff08;回溯法剪枝优化&#xff09;&#xff0c;与之不同的是&#xff0c;需要多一个相加和为n的判定条件&#xff0c;可以让每次传入数的时候进行n - i&#xff0c;直至找到n 0时…

CAPBase理论

一、CAP 理论CAP 理论指出对于一个分布式计算系统来说&#xff0c;不可能同时满足以下三点&#xff1a;一致性&#xff1a;在分布式环境中&#xff0c;一致性是指数据在多个副本之间是否能够保持一致的特性&#xff0c;等同于所有节点访问同一份最新的数据副本。在一致性的需求…

英飞凌TC3xx系列介绍01-GTM系统介绍

本文框架1. 本系列前言2. GTM模块系统介绍2.1 GTM模块常用缩略语3. 系列介绍规划1. 本系列前言 英飞凌TC3xx是英飞凌AURIX 2G系列单片机&#xff0c;该系列单片机是32位微控制器&#xff0c;具有多个TriCore CPU、程序及数据存储器、总线、中断系统、DMA及功能强大的外围设备。…

linux基本功系列之su命令

文章目录一. su命令介绍二. 语法格式及常用选项三. 参考案例3.1 切换到root用户3.2 切换到指定用户3.3 不切换成root&#xff0c;但执行root才能执行的命令总结前言&#x1f680;&#x1f680;&#x1f680; 想要学好Linux&#xff0c;命令是基本功&#xff0c;企业中常用的命令…

【MySQL】第十部分 常用的聚合函数

【MySQL】第十部分 常用的聚合函数 文章目录【MySQL】第十部分 常用的聚合函数10. 常用的聚合函数10.1 MIN和MAX函数10.2 COUNT函数10.3 AVG和SUM函数10.4 GROUP BY10.5 HAVING总结10. 常用的聚合函数 定义: 对一组数据进行汇总的函数&#xff0c;输入的是一组数据的集合&…

英语学习打卡day5

2023.1.25 1.aqua n.水;溶液;浅绿色 The construction of underground aqua storage tank 地下水储罐的建设 2.do sth for dear life 拼命做某事 If you do something for dear life, you do it with as much effort as possible, usually to avoid danger. 3. 4.swoop …

vue-grid-layout数据可视化图表面板优化过程所遇问题汇总

对于drag事件不熟悉的&#xff0c;请先阅读&#xff1a;《drag事件详解&#xff1a;html5鼠标拖动排序及resize实现方案分析及实践》之前老项目grafana面板&#xff0c;如下图所示&#xff08;GEM添加图表是直接到图表编辑&#xff0c;编辑完成后自动插入到面板最后&#xff09…

Flume集群安装部署、Kafka集群安装部署以及Maxwell安装部署实战

1、Flume集群安装部署 1.1、安装地址 Flume官网地址&#xff1a;http://flume.apache.org/文档查看地址&#xff1a;http://flume.apache.org/FlumeUserGuide.html下载地址&#xff1a;http://archive.apache.org/dist/flume/ 1.2、安装部署 将apache-flume-1.9.0-bin.tar.…

Redis实现笔记点赞排行榜 | 黑马点评-达人探店

一、发布探店笔记 探店笔记类似点评网站的评价&#xff0c;往往是图文结合。对应的表有两个 探店笔记表&#xff08;主键、商户id、用户id、标题、文字、图片、探店文字描述、点赞数量、评论数量&#xff09;评价表&#xff08;笔记的评价&#xff09;先上传图片请求一次保存…

【Java基础】--Java排序

【Java基础】--Java排序1、选择排序(Select Sort)2、冒泡排序(Bubble Sort)3、插入排序(Insert Sort)4、希尔排序(Shell Sort)5、归并排序(Merge Sort)6、快速排序(Quick Sort)7、堆排序(Heap Sort)小结待排序的元素需要实现 Java 的 Comparable 接口&#xff0c;该接口有 com…