一张大的tif地图怎么牛肉是否要煮熟才能够放到米里面去放到unity3d里

Unity工程里的那些东西
1、特殊文件夹()
Unity工程根目录下,有三个特殊文件夹:Assets、Library、ProjectSettings
Unity工程中所用到的所有Asset都放在该文件夹中,是资源文件的根目录,很多API都是基于这个文件目录的,查找目录都需要带上Assets,比如AssetDatabase。
Unity会把Asset下支持的资源导入成自身识别的格式,以及编译代码成为DLL文件,都放在Library文件夹中。
ProjectSettings
编辑器中设置的各种参数
下面都是存在Assets目录下的文件的了。
为Unity编辑器扩展程序的目录,可以在根目录下,也可以在子目录下,只要名字叫“Editor”,而且数量不限。Editor下面放的所有资源文件和脚本文件都不会被打进包中,而且脚本只能在编辑器模式下使用。一般会把扩展的编辑器放在这里,或只是编辑器程序用到的dll库,比如任务编辑器、角色编辑器、技能编辑器、战斗编辑器……以及各种小工具。
Editor Default Resources
名字带空格,必须在Assets目录下,里面放编辑器程序用到的一些资源,比如图片,文本文件等。不会被打进包内,可以直接通过EditorGUIUtility.Load去读取该文件夹下的资源。
Gizmos.DrawIcon在场景中某个位置绘制一张图片,该图片必须是在Gizmos文件夹下。
void OnDrawGizmos() {
Gizmos.DrawIcon(transform.position, "0.png", true);
OnDrawGizmos是MonoBehaviour的生命周期函数,但是只在编辑器模式下每一帧都会执行。Gizmos类能完成多种在场景视图中绘制需求,做编辑器或调试的时候经常会用到,比如在场景视图中绘制一条辅助线。(用Debug.DrawLine,Debug.DrawRay也可以绘制简单的东西)
该文件夹一般会放置几种文件,第三方包、工具代码、sdk。
plugin分为两种:Managed plugins and Native plugins
Managed plugins:就是.NET编写的工具,运行于.NET平台(包括mono)的代码库,可以是脚本文件,也可以本身是DLL。NGUI源码就放在该文件夹下面的。
Native plugins:原生代码编写的库,比如第三方sdk,一般是dll、so、jar等等。
该文件夹下的东西会在standard compiler时编译(最先编译),以保证在其它地方使用时能找到。
存放资源的特殊文件夹,可以在根目录下,也可以在子目录下,只要名字叫“Resources”就行,比如目录:/xxx/xxx/Resources
和 /Resources 是一样的,而且可有多个叫Resources的文件夹。Resources文件夹下的资源不管用还是不用都会被打包进.apk或者.ipa,因为Unity无法判断脚本有没有访问了其中的资源。需要注意的是项目中可以有多个Resources文件夹,所以如果不同目录的Resources存在同名资源,在打包的时候就会报错。
Resources中全部资源会被打包成一个缺省的AssetBundle(resources.assets)。
在该文件夹下的资源,可以通过Resources类进行加载使用。
Standard Assets
存放导入的第三方资源包。
StreamingAssets
该文件夹也会在打包的时候全部打进包中,但它是“原封不动”的打包进去(直接拷贝到的包里)。游戏运行时只能读不能写。
不同的平台最后的路径也不同,可以使用unity提供的Application.streamingAssetsPath,它会根据平台返回正确的路径,如下:
Mac OS or Windows:path = Application.dataPath + “/StreamingAssets”;
IOS:path = Application.dataPath + “/Raw”;
Android:path = “jar:file://” + Application.dataPath + “!/assets/”;
我们一般会把初始的AssetBundle资源放在该文件夹下,并且通过WWW或AssetBundle.LoadFromFile加载使用。
Hide Assets
隐藏文件夹和文件
以”.”开头
以”~”结尾
名字为”cvs”
扩展名为”.tmp”
An asset is representation of any item that can be used in your game or project. An asset may come from a file created outside of Unity, such as a 3D model, an audio file, an image, or any of the other types of file that Unity supports. There are also some asset types that can be created within Unity, such as an Animator Controller, an Audio Mixer or a Render Texture.
asset就是游戏中所用的资源,可以是用其它软件创建的,如3D model、audio、image等,和一些unity可创建的,如animator、audio mixer、render texture…
一些通常的Asset类型
Image: 支持绝大多数的image type,例如BMP、JPG、TIF、TGA、PSD
Model:eg、.max、.blend、.mb、.ma,它们将通过FBX插件导入。或者直接在3D app导出FBX放到unity project中
Mesh and Animations:unity支持绝大多数流行的3D app的model(Maya、Cinema 4D、3ds Max、Cheetah3D、Modo、Lightwave、Blender、SketchUp)
Audio Files:如果是非压缩的audio,unity将会根据import setting压缩导入()
Asset Store
里面有很多免费和收费的插件,可以供开发者下载使用。
下载的第三方工具是以package文件存在,导入package:
unity会自动导入Asset目录下的资源,可以是unity支持的,也可以是不支持的,而在程序中用到的(比如二进制文件)。
当在Asset下进行保存、移动、删除等修改文件的操作,unity都会自动导入。
自定义导入
导入外界的unity可识别的Asset时,可以自定义导入设置,在工程中点击资源文件,然后Inspector视图中就会看到相应的设置:
导入结果( )
导入资源之后,除了要生成.meta文件,unity并不是直接使用这些资源的,而是在导入的过程中,生成了unity内部特定的格式(unity可识别)文件在游戏中使用,储存在Library目录下,而原始资源不变,仍然放在原来位置。当然,每次修改原始文件,unity都会重新导入一次,才能在unity中看到改过之后的样子。
正因为Library存放了导入资源的结果,所以每次删除Library或里面某个文件,都会让unity重新导入相应的资源(生成内部格式),但对工程没有影响。
最终那些资源的导入结果就在metadata文件夹里
“the results of the import process are stored in a folder named for the first two digits of the Asset’s File GUID. This folder is stored inside the Library/metadata/ folder. The individual Objects are serialized into a single binary file that has a name identical to the Asset’s File GUID.”
import的结果存储在Library/metadata/文件夹下,并且把File GUID的前两位bit作为文件夹名,以File GUID作为文件名字。
Asset中的所有文件、文件夹,经过unity的导入过程后,会为每个都生成一个.meta文件,这个文件是unity内部管理文件的重要内容,里面记录着一些信息。
你知道unity是怎么管理资源依赖关系的吗?可以试着更改一个挂在prefab上的脚本的目录或者名字,而这些prefab依然可以正常的调用那些脚本。
unity在第一次导入新文件的时候,会生成一个Unique ID,用来标志这个asset,它就是unity内部用来区分asset的。Unique ID是全局唯一的,保存在.meta文件中。
在unity中资源间的依赖关系引用都是用Unique ID来实现的,如果一个资源丢失了.meta文件,那依赖它的资源就找不到它了。
If an asset loses its meta file (for example, if you moved or renamed the asset outside of Unity, without moving/renaming the corresponding .meta file), any reference to that asset will be broken. Unity would generate a new .meta file for the moved/renamed asset as if it were a brand new asset, and delete the old “orphaned” .meta file.
For example, in the case of a texture asset losing its .meta file, any Materials which used that Texture will now have no reference to that texture. To fix it you would have to manually re-assign that texture to any materials which required it.
In the case of a script asset losing its .meta file, any Game Objects or Prefabs which had that script assigned would end up with an “unassaigned script” component, and would lose their functionality. You would have to manually re-assign the script to these objects to fix this.
.meta文件内容如下,包括Unique ID和Import Setting的内容
unity支持三种脚本语言,分别是C#、JavaScript、Boo,最常用的是前两种,当然还有后来扩展的支持Lua脚本的库(slua、ulua)。
1.编译顺序
编译顺序的原则是在第一个引用之前编译它,参考可以知道,Unity中的可以将脚本代码放在Assets文件夹下任何位置,但是不同的位置会有不同的编译顺序。规则如下:
The phases of compilation are as follows:
Phase 1: Runtime scripts in folders called Standard Assets, Pro Standard Assets and Plugins.
Phase 2: Editor scripts in folders called Editor that are anywhere inside top-level folders called Standard Assets, Pro Standard Assets and Plugins.
Phase 3: All other scripts that are not inside a folder called Editor.
Phase 4: All remaining scripts (those that are inside a folder called Editor).
(1) 首先编译Standard Assets,Pro Standard Assets,Plugins文件夹(除Editor,可以是一级子目录或是更深的目录)下的脚本;
(2) 接着编译Standard Assets,Pro Standard Assets,Plugins文件夹下(可以是一级子目录或是更深的目录)的Editor目录下的脚本;
(3) 然后编译Assets文件夹下,不在Editor目录的所有脚本;
(4) 最后编译Editor下的脚本(不在Standard Assets,Pro Standard Assets,Plugins文件夹下的);
基于以上编译顺序,一般来说,我们直接在Assets下建立一个Scripts文件夹放置脚本文件,它处于编译的“第三位”。
2.编译结果:
项目工程文件夹中会生成类似如下几个文件, 按顺序分别对应着上述四个编译顺序:(GameTool是项目名称)
GameTool.CSharp.Plugins.csproj
GameTool.CSharp.Editor.Plugins.csproj
GameTool.CSharp.csproj
GameTool.CSharp.Editor.csproj
所有脚本被编译成几个DLL文件,位于工程根目录 / Library / ScriptAssemblies。
生成如下三个dll:
Assembly-CSharp-Editor.dll:包含所有Editor下的脚本
Assembly-CSharp-firstpass.dll:包含Standard Assets、Pro Standard Assets、Plugins文件夹下的脚本
Assembly-CSharp.dll:包含除以上两种,在Assets目录下的脚本。
Plugins()
内容包括了Plugin导入设置、怎样创建使用两种Plugin、怎样利用底层渲染接口以及一些基础知识。
在打包的时候,会把plugin里面的各种库,拷贝到包体中相应的位置(不同平台不一样,具体在可以把工程分别打成几个平台的包)
这是win32平台的包,Managed里面放置的托管库,Mono里面放的是mono的库,Plugins是平台库(native plugin)
分平台打包,就需要对不同平台的plugin区分,方法是在Plugins目录下建立相应平台的文件夹,unity在为不同平台打包的时候,除了会将相应平台的plugin里的脚本编译成Assembly-CSharp-firstpass.dll,还会把已经是dll、so等库直接拷贝到包内相应位置。
Plugins/x86:win32位平台plugin
Plugins/x86_64:win64位平台plugin
Plugins/Android:Android平台
Plugins/iOS:iOS平台
UnityEngine.Object是所有类的基类,它描述了Asset上使用的所有resource的序列化数据,它有几个重要的派生类:GameObject,Component,MonoBehaviour
GameObject
GameObject是组件的容器,所有Component都在可以挂在上面,Unity以组价化思想构建,所有功能拆分成各个组件,需要某个功能只需挂上相应的组件,组件之间相互独立,逻辑互补交叉。当然组件式开发也有最大的弊端就是组件之间的交互。
Component作为组件的基类,unity中有大量的组件,Transform、Renderer、Collider、MeshFilter都是组件。
MonoBehaviour
开发时创建的脚本,需要挂在GameObject上的脚本都是继承自MonoBehaviour。
ScriptableObject
自定义可被Unity识别的资源类型,可打成AssetBundle,可通过Resources or AssetBundle加载。
Asset和Object的关系
Object作为Asset的序列化数据,比如以Texture导入一张图片,那么就用Texture对象记录描述了该图片。
Asset可能有多个Object,比如prefab的GameObject上挂着多个组件,这样Asset和Object就是一对多的关系。那么问题来了,同一个Object怎么区分分别挂在不同GameObject上的对象的?等等,这里是一定要区分的,因为它们要包含序列化数据(在Inspector视图设置的),而不是在游戏运行中再new。
Class ID 和 File ID(object id)
先梳理一下关系,unity通过guid找到asset,其中asset上可能又挂了很多组件,每个组件又对应着一个class,而在序列化的时候是对象。Class ID是unity定义好的(),File ID是为对象生成的id,也就是说,我用guid + (class id 可有) + file id 就能确定某个资源上的组件对象。
是一种标记语言,如果不了解语言格式可以看。
Text-Based Scene Files
和二进制文件一样,unity还提供了基于文本的场景文件,使用YAML标记语言,通过文本描述了asset和object组件之间的关系是怎么关联、保存数据等。
通过设置Edit -& Project Setting -& Editor -& Asset Serialization -& Force Text,我们可以查看所有Object信息了。
下面是一个GameObejct的YAML document:
%TAG !u! tag:unity3d.com,2011:
--- !u!000
m_ObjectHideFlags: 1
serializedVersion: 2
m_Modification:
m_TransformParent: {fileID: 0}
m_Modifications: []
m_RemovedComponents: []
m_ParentPrefab: {fileID: 0}
m_RootGameObject: {fileID: 9832}
m_IsPrefabParent: 1
--- !u!1 &9832
GameObject:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: }
serializedVersion: 4
m_Component:
- 4: {fileID: 4536}
- 33: {fileID: 78356}
- 23: {fileID: 05954}
- 114: {fileID: 194584}
m_Layer: 0
m_Name: Cube
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &4536
Transform:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: }
m_GameObject: {fileID: 9832}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 0
第三行的字符串“— !u!000”,“!u!”后面的“1001”是Object的Class ID,“&”后面的“”是File ID。
接着第四行是Prefab,是Class Name;下面“m_”开头的是它的序列化属性,请看“m_RootGameObject”,记录着Prefab对象的根节点的GameObject对象,继续看后面“{fileID: 9832}”,file ID指向的刚好是第14行定义的GameObject对象;第20行m_Component属性,可以看出gameObject上挂了四个组件,通过前面的Class ID就可以查到是什么组件了。
Instance ID
在前面已经介绍了GUID、Class ID、File ID,先做个小结。Unity通过GUID找到asset文件,以至于我们可以随意更改asset文件的位置,但是.meta文件丢失就会导致找不到相应的资源,最常见的就是丢失脚本;接着在游戏中加载某个资源的时候,通过File ID找到组件的Object,如果Object没有被加载就找不到,则通过File ID找到数据源,通过Class ID找到类,然后实例化对象,初始化序列数据,并分配Instance ID,Object就加载好了。
但是每一个资源,这样每一次加载都需要对GUID和File ID遍历查找比较判断对应的Object是否加载,这样就会带来性能问题。所以基于这个原因,所以利用GUID和File ID生成一个Instance ID,在Unity内部维护了一个Instance ID的映射缓存来标识各个Object,每当有新的Objects添加到缓存中时,Instance ID以简单的单调递增的方式进行赋值。
另外Instance ID的生命周期和Object的创建销毁是一致的。
Unity3D工程各子文件说明
如何在unity中显示metadata文件
浅析游戏引擎的资源管理机制 扒一扒Unity3D中隐藏在背后的资源管理
unity的 断言 Unity 5.1 Assertion Library
新建Unity项目后包含的文件路径都是什么?
Unity工程项目一睹
Unity开发详解之新建工程(1/6)
Unity项目目录结构和简单的文件命名规范
(3-2)Unity3D/项目:Unity工程目录规范
没有更多推荐了,unity3D 5 pro
ios 8.1(6.1)
xcode 6.1(6.2)
1.新建unity3d工程,添加vuforia 4.0的工程包
Hierarchy中
删除原有camera
添加ARCamera
添加ImageTarget
2.在vuforia网站申请key license以及上传自己的需要识别的图片。成功后下载图片包,并添加进unity3D工程。设置工程
成功在ARCamera中 Inspector - App License Key添加key license
勾选Data Set Load Behaviour
勾选Load Data Set XX(XX是自己的图片名)
勾选 Activate
3.选Hierarchy - ImageTarget,设置识别图片
Inspector - Image Target Behaviour
Data Set  设置自己的图片
Image Target 自己图片的名字
4.Project中添加进自己的模型(YYY.fbx)设置识别的动态模型
将模型拖入ImageTarget作为子节点YYY(模型能识别了)
Inspector - Model - Select&
Rig - Animation Type
选Legacy(模型能动了)
5.添加GUI,支持播放视频(ios上)
在ASSETS中新建一个C#脚本,并拖入到Hierarchy - ARCamera - Camera上
//纯手敲,可能会有没检查的打字错误
public T//和谐睡因
void Start()
CameraDevice.Instance.SetFocusMode(CameraDevice.FOCUS_MODE_CONTINUOUSAUTO);
//相机对焦,IOS可有可无
void OnGUI()
if(GUI.Button(new Rect(20,20,100,50),"Play"))//添加的播放视频按钮
Handheld.PlayFullScreenMovie("xxx.mp4",Color.black,FullScreenMovieControlMode.Full);
//不可用原始图片大小,图片加入unity3D中时会自动改变大小,因此不能获取图片大小,此大小为睡因大小
float width = 144.0f;
float height = 64.0f;
GUI.DrawTexture(new Rect(0, Screen.height - height, wide, height),logo);
选择Hierarchy - ARCamera - Camera,将自己需要和谐睡因的图片拖入Inspector-C#脚本-logo。
xxx.mp4的文件位置很重要,一定要放在 &Assets/StreamingAssets/ 目录下,不放在此目录下则无法播放。
6.导入到XCODE工程,记得配置opengles2.0(详见我上一篇,)
阅读(...) 评论()Unity中资源打包成Assetsbundle的资料整理
最近在研究Unity中关于资源打包的东西,网上看了一堆资料,这里做个整合,说整合,其实也就是Ctrl-C + Ctrl-V,不是原创
首先为了尊重原创,先贴出原创者的文章地址:
本文原创版权归 csdn
所有,转载请详细注明原创作者及出处,以示尊重!
如果这篇文章对你有帮助,敬请关注作者《Unity手游之路》系列教程。
在手游的运营过程中,更新资源是比不可少的。资源管理第一步是资源打包。传统的打包可以将所有物件制成预设Prefab,打包成场景。今天我们来一起学习官方推荐的Assetbundle,它是Unity(Pro)提供的资源打包策略。利用AssetBundle,可以将几乎所有的资源都打包封装,便于客户端更新下载新的资源。
(转载请注明原文出处)
创建AssetBundle
1.创建一个空的Prefab,命名Cube,然后创建一个Cube,将其拉到刚创建好的Prefab
2.新建一个脚本ExportAssetBundles.cs(代码来自官方文档),保存在Asset/Editor目录下
[MenuItem("Assets/Build AssetBundle From Selection")]
static void ExportResourceRGB2()
string path = EditorUtility.SaveFilePanel("Save Resource", "", "New Resource", "assetbundle");
if (path.Length != 0)
Object[] selection = Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets);
BuildPipeline.BuildAssetBundle(Selection.activeObject, selection, path, BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets, BuildTarget.StandaloneWindows);
这时我们将看到Asset下面出现Build AssetBundle From Selection和Build Scene
3.选中预设Cube,运行Build AssetBundle From Selection。这时会弹出一个保存框,将其命名为cube.unity3d(这里为了测试方便,放在c盘。实际项目中,我们是需要将他们放在web服务器,供所有客户端下载更新)
4.新建一个场景scene1.unity,上面放置几个模型,然后保存
5.选中该场景,在之前的ExportAssetBundles.cs脚本中添加打包场景的函数,运行Assets-&Build Scene,保存为scene1.unity3d(这里为了测试方便,也放在c盘)
[MenuItem("Assets/Save Scene")]
static void ExportScene()
string path = EditorUtility.SaveFilePanel("Save Resource", "", "New Resource", "unity3d");
if (path.Length != 0)
Object[] selection = Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets);
string[] scenes = {"Assets/scene1.unity"};
BuildPipeline.BuildPlayer(scenes,path,BuildTarget.StandaloneWindows,BuildOptions.BuildAdditionalStreamedScenes);
a.AssetBundle的保存后缀名可以是assetbundle或者unity3d
b.BuildAssetBundle要根据不同的平台单独打包,BuildTarget参数指定平台,如果不指定,默认的webplayer加载AssetBundle我们通过一个简单的代码来演示如何加载assetbundle,包括加载普通asset和场景。
using UnityE
using System.C
public class Load: MonoBehaviour
private string BundleURL = "file:///C:/cube.assetbundle";
private string SceneURL = "file:///C:/scene1.unity3d";
void Start()
Debug.Log(BundleURL);
StartCoroutine(DownloadAssetAndScene());
IEnumerator DownloadAssetAndScene()
using (WWW asset = new WWW(BundleURL))
yield return
AssetBundle bundle = asset.assetB
Instantiate(bundle.Load("Cube"));
bundle.Unload(false);
yield return new WaitForSeconds(5);
using (WWW scene = new WWW(SceneURL))
yield return
AssetBundle bundle = scene.assetB
Application.LoadLevel("scene1");
a.LoadFromCacheOrDownload 可以指定版本,如果本地版本是新的,将不会从服务器读取
b.如果是多个资源打包在一起,我们要通过bundle.Load(),加载特定的资源
c.挂载在模型上的脚本也可以一起打包,但是保证脚本在原目录也要存在,否则加载出来无法运行。关于如何更新脚本,我将放在以后的章节中阐述。AssetBundle依赖关系
如果一个公共对象被多个对象依赖,我们打包的时候,可以有两种选取。一种是比较省事的,就是将这个公共对象打包到每个对象中。这样会有很多弊端:内存被浪费了;加入公共对象改变了,每个依赖对象都得重新打包。AssetBundle提供了依赖关系打包。我们通过一个简单的例子来学习
BuildPipeline.PushAssetDependencies();
var options =
BuildAssetBundleOptions.CollectDependencies |
BuildAssetBundleOptions.CompleteA
BuildPipeline.BuildAssetBundle(
AssetDatabase.LoadMainAssetAtPath("assets/artwork/lerpzuv.tif"),
null, "Shared.unity3d", options);
BuildPipeline.PushAssetDependencies();
BuildPipeline.BuildAssetBundle(
AssetDatabase.LoadMainAssetAtPath("Assets/Artwork/Lerpz.fbx"),
null, "Lerpz.unity3d", options);
BuildPipeline.PopAssetDependencies();
这个文件将共享这些资源,但是后续的资源包将无法继续共享它
BuildPipeline.PushAssetDependencies();
BuildPipeline.BuildAssetBundle(
AssetDatabase.LoadMainAssetAtPath("Assets/Artwork/explosive guitex.prefab"),
null, "explosive.unity3d", options);
BuildPipeline.PopAssetDependencies();
BuildPipeline.PopAssetDependencies();
我们在程序加载的时候必须保证先加载公共对象。否则,只能是在各个对象加载成功后,再通过程序手动添加进来,比较繁琐。在实际项目中,由于是团队开发,对象间的依赖关系通常会比较凌乱,最好在开发周期就定好相关的规范约束,方便管理。
总结这一节的内容偏实际操作,官方文档和雨松的blog中已经有更加详细介绍。如果大家还有不明白的地方,可以结合文档再实际操作一下。后面的章节,我将花更多的时间介绍核心的内容:资源的增量更新,和代码程序的更新。
源码http://pan.baidu.com/s/1i3BOAPn
参考资料1.http://www.xuanyusong.com/2.http://game.ceeger.com/Manual/DownloadingAssetBundles.html
Assetbundle 是Unity Pro提供提供的功能,它可以把多个游戏对象或者资源二进制文件封装到Assetbundle中,提供了封装与解包的方法使用起来很便利。
Assetbundle可以将Prefab封装起来,这是多么方便啊! 而且我也强烈建议大家将Prefab封装成Assetbundle,因为Prefab可以将游戏对象身上带的游戏游戏组件、游戏脚本、材质都封装在一起。当从服务器上将Assetbundle下载以后直接Instantiate就可以放入游戏中。
试想一下,如果只能将原始的二进制资源文件放在服务器上下载,当资源文件下载完毕后,需要动态的创建游戏对象、然后动态的将脚本绑定在游戏对象、动态的将贴图赋予游戏对象等等各种动态的操作。。所以强烈建议使用Prefa,不解释!!!!!
另外,我在举个例子,因为模型有可能会带很多动画文件,那么这样一组模型资源就可能是多个FBX 文件 和 若干png贴图文件 材质文件。这时我只需要把原始模型放入Prefab中,它就会包含这个模型的所有组件、甚至包括它的动画资源、贴图。那么如下图所示,Mode就是模型的Prefab文件,那么我仅仅只需要把Mode这个预设打包成Assetbundle即可。 当我在服务器上下载这个Assetbundle并且载入游戏中就可以直接使用了,切换动画、换贴图都可以。。
2.二进制文件
也并不是Assetbundle中全都要用预设,Assetbundle它也可以将二进制文件直接封装在里面,比如图片、声音、文本信息等等。
3.场景文件
在Unity中可以将一个场景保存在Scene中,Scene就会包含这个场景中的所有,那能不能把Scene也封装成Assetbundle中?答案是能,但是它不能在移动平台上用,因为移动平台上是不能更新脚本的,换句话来说就是即使将脚本绑定在Prefab中,然后下载Assetbundle后,所有脚本是不会执行的,后面说另外一种巧妙用法。
4.移动平台
上面MOMO已经将Assetbundle 的使用原理大致介绍了一下 ,我们在谈谈移动平台。脚本不能更新是移动平台下最大的伤,这就意味着开发者无法绕过App store和 google Play这种在线商店升级应用程序。唯一能做到的就是更新资源、举个例子,游戏中在处理版本升级时,一般会有个大版本号和一个小版本号,大版本号就是 2.0、3.0这种 版本需要在AppStore中更新,大版本主要是升级游戏脚本,然后当小版本号,比如2.0.1 或2.0.2这种只是更新游戏中的资源,通过自己游戏的服务器就可以完成,通过Assetbundle在自己服务器上下载,然后适应在游戏中。如果非要更新脚本,或不得不更新脚本那么只能在Appstore或者google
Play去更新大版本。
移动平台上不能更新脚本,那么Prefab上绑定的脚本怎么办?在任何平台上都可以把脚本添加到Prefab上,然后打包成Assetbundle,只有移动平台上有点特殊,比如将Test.cs这条脚本绑定在Prefab中,最后程序通过服务器下载这个Assetbundle ,当载入工程中这条脚本是不会被执行的。
但是如果本地工程有Test.cs这条脚本,那么Unity会自动将这条脚本绑定在下载的Prefab中,并且他们执行的非常好。如果本地工程中没有Test.cs这条脚本,那么Prefab上的脚本是永远都不会执行的。有时我们会在脚本中写一些Public的变量,有可能不同的Prefab上绑定的是相同的脚本,只是Inspector 脚本中的public参数不同。别担心这一点Assetbundle 中的Prefab也是没问题,所以说只要大版本中的脚本没问题,在小版本中只更新游戏资源是一点问题都么有的。
5.移动优化
之前我们说过可以将游戏中的某个游戏对象封装成Assetbundle,也可以将游戏中的整个场景也封装成Assetbundle。但是我认为需要巧妙的使用封装场景,因为场景中肯定有很多公用的模型,如果打包场景的话那么内存与size就是 公用模型的size * N个场景,想想其实挺恐怖的。其实我们可以巧妙的使用,首先把场景中公用的部分和私有的部分统统放入Unity, 然后烘培整个场景。 当场景烘培完毕后把公用的模型部分在拿出去,场景只只保留私有的模型。还可以做一个工具将公用模型在场景中的坐标保存在XML中(每个场景文件会对应一个公用模型的XML信息),最后在将公用的模型分别封装在别的Assetbundle中。
服务器上提供每个场景的Assetbundle ,和公用模型的Assetbundle,一般公用模型的Assetbundle可以放在常驻内存中(可能使用频繁、根据项目的不同而定)场景Assetbundle下载完毕后,现载入场景然后在根据场景对应的XML信息将公用模型部分动态的在添加到场景中,这样就完成了一个场景的构建。
对游戏中所有资源进行打包,比如按类型分为五个大部分 界面,模型,特效,声音,场景,脚本。
界面部分:
公用资源包(可复用的资源包)和 每个界面独有得资源包(不可复用的资源包)统一使用Prefab 打包成.assetbundle 二进制格式。
模型部分:
按角色分类,统一使用Prefab 打包成.assetbundle 二进制格式。 模型部分包括模型文件与动画文件,每一个模型文件对应一组动画文件。(如果模型需要换装还需提供对应换装的模型与贴图) ,因为unity4的重定向动画不支持动态加载,所以目前不需要考虑 不同大小 不同规格 不同性别 的模型重定向动画。
特效部分: 统一使用Prefab 打包成.assetbundle 二进制格式。
声音部分: 统一使用Prefab 打包成.assetbundle 二进制格式。
场景部分:场景和前面的有点区别,场景需要导出烘培的光信息并且只能烘培场景之上永远不动的模型,但是这些永远不动的模型有可能会同时在多个场景中使用,所以场景烘培完毕后要把重复使用的对象删除,(运行游戏在动态的加载进来)场景中只保留该场景中永远不会变的模型,以及烘培的光照信息。 打包场景后会生成.unity3D 二进制格式,它和 assetbundle 打包方式是不同的。(另外,也可以考虑 json xml 二进制 来动态组装场景)。
脚本部分:如果Prefab上是带脚本打包Assetbundle的话 脚本是不会被运行的(移动平台), 但是unity有一个技巧,Prefab上的脚本 如果本地有的话它会把本地的同名脚本绑定在Prefab对象上,它会很好的执行。
Prefab打包技巧: Prefab打包时自身是不占多少空间的 &=1KB 但是Prefab上是可以关联 这五大部分 “界面,模型,特效,声音,场景,脚本”以及在Hierarchy视图中 坐标/缩放/旋转。 关联这些信息以后就会很大,所以为了避免资源的浪费尽量避免Prefab重复关联。
一个prefab下面可以同时关联多个游戏对象 ,这里举个例子如果你的 Prefab下面放了一个模型 它的大小可能是500k ,在 Prefab下面放了十个完全相同模型 它的大小可能是501k 。 如果Prefab下面放了两个不同的模型,它的大小可能就会是 500k x 2 的size ,也就是说Prefab与关联的数量是无关的 。
加密部分: assetbundle 是可以转换成 字节数组 ,客户端与服务器约定一组解密 字节数组的算法就可以实现资源加密。
大版本升级:
unity的版本升级其实主要是升级主程序中的脚本。 因为所有的资源都是assetbundle 和 .unity3d 这些资源放在本地或者服务器 解包的方式是完全一样,所以理论上我们的主程序包的大小可以做到很小,可以很好设置把多少资源放在包里 或者把所少资源放在服务器上。在运行的时候服务端应该把所有 assetbundle 和 .unity3d的资源文件的下载地址列表返回给客户端。
小版本升级:
小版本升级也就是更新资源,因为不能更新脚本, 在登陆的时候服务端应该把所有 assetbundle 和 .unity3d的资源文件的下载地址列表返回给客户端。
还有个需要考虑的地方,比如现在大版本是2.0.0 ,小版本已经是2.0.5 ,用户的手机上是一个1.5.0的包。 此时用户在打开游戏的时候 应当强制它去appstore中去下载大版本2.0.0 ,当用户下载完毕后登陆游戏,此时服务器告诉客户端现在已经是2.0.5的小版本了,这时候客户端去下载对应小版本的所有 assetbundle 和 .unity3d文件地址列表。
增量更新:理论上增量更新是可行的。因为unity不能更新脚本,所以在处理增量更新的话 需要在代码中做可以兼容增量更新的可能。
因为Assetbundle这块的代码比较多,我还是决定分成两篇文章来写,这篇文章先说原理、下篇文章说代码。欢迎大家来讨论!
前几天我和Unity鑫哥聊天,他告诉我IOS上是无法运行时更新脚本、但是Android上是可以运行时更新脚本,我回家也试了一下但是没能成功,后来我考虑即使成功了项目中我也不打算那么做,因为这样Android和IOS 做起来的差别就太多了, 另外Unity商店中有一个处理运行时更新脚本的插件 unityLua 大家可以去研究研究。
上一次我们学习了。这次就可以用上场了,我们来探讨一下手游资源的增量更新策略。注意哦,只是资源哦。关于代码的更新,我们稍后再来研究。理论上这个方案可以使用各种静态资源的更新,不仅仅是assetbundle打包的。
(转载请注明原文地址)
现在的手游安装有几种方式。一种是安装的时候就把程序和资源安装到本地。另外一种是只安装程序和少量的必要资源,然后在启动的时候再把缺少的资源下载完整。手游一般不建议和传统页游一样,在运行过程中加载资源,那样做会导致用户体验会比较差些。上述的两种安装模式,在更新资源上本质都是相同的。都是比较服务器资源的版本和本地资源的版本,以确定哪些资源要下载(包括需要更新的和新增的)。实践
1.资源打包。
资源打包之前,要先规划好资源之间的相互依赖关系。把一些共性的东西抽取出来,尽量减少不必要的耦合。一些比较好的做法有,所有物件尽可能做成Prefab,场景上的东西越少越好,“一切都是动态加载”。
2.生成文件MD5
关于文件的MD5,这里就不详细描述了。大家可以简单理解它为一个文件的状态标记。如果文件有更改,那么它的md5一定是改变的,单纯的移动文件是不会更改的。md5验证还可以起到安全验证的作用,保证本地文件不被篡改。举个例子,我们经常从网上上下载软件时,一般都会给出一个md5值,你下载后,对比一下已下载文件的md5值,就可以知道文件有没有被篡改。在版本发布时,我们需要对所有打包好的文件计算md5值,然后保存在一个配置文件中。关于这部分的工作,我之前写过一个可视化小工具(),现在分享给大家。如果大家觉得有用,记得打星哦:)
3.版本比较
先加载本地的version.txt,将结果缓存起来。下载服务器的version.txt,与本地的version进行比较,筛选出需要更新和新增的资源
4.下载资源
依次下载更新的资源,如果本地已经有旧资源,则替换之,否则就新建保存起来
5.更新本地版本配置文件version.txt
用服务器的version.txt替换掉本地的version.txt。这样做是为了确保下次启动的时候,不会再重复更新了。
6.从本地加载assetbundle进行测试显示。
这里将一个模型制成Prefab,打包成assetbundle。程序从本地加载后,显示在场景中
7.更新服务器的assetbundle,重新生成版本号文件。
8.重复6的步骤
我们可以验证,我们的程序不用任何改动,资源已经实现了更新。场景中显示的已经是最新的模型了。
关于上述的流程,我写了一个小的演示demo。我这里没有用到web服务器,而是将本地的另外一个文件夹作为资源服务器目录。这里的目录只针对windows下的版本进行测试。如果要在手机平台上,需要记得更新相关的路径。
using UnityE
using System.C
using System.Collections.G
using System.T
using System.IO;
public class ResUpdate : MonoBehaviour
public static readonly string VERSION_FILE = "version.txt";
public static readonly string LOCAL_RES_URL = "file://" + Application.dataPath + "/Res/";
public static readonly string SERVER_RES_URL = "file:///C:/Res/";
public static readonly string LOCAL_RES_PATH = Application.dataPath + "/Res/";
private Dictionary&string, string& LocalResV
private Dictionary&string, string& ServerResV
private List&string& NeedDownF
private bool NeedUpdateLocalVersionFile = false;
void Start()
LocalResVersion = new Dictionary&string, string&();
ServerResVersion = new Dictionary&string, string&();
NeedDownFiles = new List&string&();
StartCoroutine(DownLoad(LOCAL_RES_URL + VERSION_FILE, delegate(WWW localVersion)
ParseVersionFile(localVersion.text, LocalResVersion);
StartCoroutine(this.DownLoad(SERVER_RES_URL + VERSION_FILE, delegate(WWW serverVersion)
ParseVersionFile(serverVersion.text, ServerResVersion);
CompareVersion();
DownLoadRes();
private void DownLoadRes()
if (NeedDownFiles.Count == 0)
UpdateLocalVersionFile();
string file = NeedDownFiles[0];
NeedDownFiles.RemoveAt(0);
StartCoroutine(this.DownLoad(SERVER_RES_URL + file, delegate(WWW w)
ReplaceLocalRes(file, w.bytes);
DownLoadRes();
private void ReplaceLocalRes(string fileName, byte[] data)
string filePath = LOCAL_RES_PATH + fileN
FileStream stream = new FileStream(LOCAL_RES_PATH + fileName, FileMode.Create);
stream.Write(data, 0, data.Length);
stream.Flush();
stream.Close();
private IEnumerator Show()
WWW asset = new WWW(LOCAL_RES_URL + "cube.assetbundle");
yield return
AssetBundle bundle = asset.assetB
Instantiate(bundle.Load("Cube"));
bundle.Unload(false);
private void UpdateLocalVersionFile()
if (NeedUpdateLocalVersionFile)
StringBuilder versions = new StringBuilder();
foreach (var item in ServerResVersion)
versions.Append(item.Key).Append(",").Append(item.Value).Append("\n");
FileStream stream = new FileStream(LOCAL_RES_PATH + VERSION_FILE, FileMode.Create);
byte[] data = Encoding.UTF8.GetBytes(versions.ToString());
stream.Write(data, 0, data.Length);
stream.Flush();
stream.Close();
StartCoroutine(Show());
private void CompareVersion()
foreach (var version in ServerResVersion)
string fileName = version.K
string serverMd5 = version.V
if (!LocalResVersion.ContainsKey(fileName))
NeedDownFiles.Add(fileName);
string localMd5;
LocalResVersion.TryGetValue(fileName, out localMd5);
if (!serverMd5.Equals(localMd5))
NeedDownFiles.Add(fileName);
NeedUpdateLocalVersionFile = NeedDownFiles.Count & 0;
private void ParseVersionFile(string content, Dictionary&string, string& dict)
if (content == null || content.Length == 0)
string[] items = content.Split(new char[] { '\n' });
foreach (string item in items)
string[] info = item.Split(new char[] { ',' });
if (info != null && info.Length == 2)
dict.Add(info[0], info[1]);
private IEnumerator DownLoad(string url, HandleFinishDownload finishFun)
WWW www = new WWW(url);
yield return
if (finishFun != null)
finishFun(www);
www.Dispose();
public delegate void HandleFinishDownload(WWW www);
总结资源更新的原理,本质上都是相似的。我之前也从事过页游的开发,资源更新流程也类似。所以技术的本质是掌握思维方式,平台和语言都是永远在变的。我们最后归纳一下流程:比较服务端的资源版本和本地的资源版本,找出需要更新的资源,然后依次下载。如果大家有更好的策略,欢迎分享探讨 。源码http://pan.baidu.com/s/1mgNnR8O
参考资料Unity3d官网文档
之前我们已经学过手机游戏的资源热更新策略了。在实际手游的开发运营中,我们需要经常修复bug,增加新玩法。这些通常都涉及到代码的更新。unity游戏代码的更新比较复杂,也存在不同的更新策略,各有优缺点,在不同的平台上做法也不尽相同。这里主要谈一些比较常用的策略和各大手机平台上的策略。大家有更好的思路,欢迎探讨。
(转载请注明出处 )
反射大部分编程语言都是支持反射的,利用反射,可以动态去加载所需的程序。C#也是同样可以用反射来实现。要实现代码的更新,我们在项目初期就要做好规划,将一些容易变更的业务逻辑代码独立划分。每次更新时,将代码打包成dll,再打包成资源文件。程序启动时,检查更新到客户端,客户端通过反射重新加载代码运行。下面通过一个简单的demo来演示。
1.在vs中新建一个代码库工程,命名为test
2.添加几个类Scirpt,Scirpt2,Data
3.将这个项目生成DLL,test.dll
4.新建一个unity项目,将DLL倒入到Asset,改名为test.bytes,不然可能会报错
5.利用我们之前实现过的打包脚本,将test.bytes打包成test.assetbundle。
6.创建CodeUpdate.cs脚本,用于加载代码资源,反射调用。
7.为了验证代码更新后,可以直接加载使用,我们可以更改一下Data.cs的代码,重复以上过程,可以看到,更新了代码打包后,我们重新运行游戏,就可以看到效果
public class Data
private int
public Data()
public override string ToString()
return attr.ToString();
public class Script: MonoBehaviour
void Start()
Debug.Log("------------------I am script 1");
Data data = new Data();
Debug.Log("-------------" + data.ToString());
CodeUpdate.cs
using UnityE
using System.C
public class CodeUpdate : MonoBehaviour {
private static readonly string DLL_URL = "file:///c:/test.assetbundle";
void Start () {
StartCoroutine(loadDllScript());
private IEnumerator loadDllScript()
WWW www = new WWW(DLL_URL);
yield return
AssetBundle bundle = www.assetB
TextAsset asset = bundle.Load("test",typeof(TextAsset)) as TextA
System.Reflection.Assembly assembly = System.Reflection.Assembly.Load(asset.bytes);
Type script1 = assembly.GetType("Script");
GameObject obj = new GameObject();
obj.AddComponent(script1);
Type script2 = assembly.GetType("Script2");
obj.AddComponent(script2);
完整安装包更新大部分的app更新都是采用完整包更新。在程序启动的时候,检查服务器的最新版本,如果比本地的版本要新,就下载服务器的版本,重新安装替换本地的程序。在IOS平台上,是由App Store来统一管理的。客户端程序只需检查版本,跳转到app store页面即可。android 平台的更新更灵活,略微复杂。在判断版本号,确定要更新后,直接就可以下载服务器的最新的apk文件,安装替换本地的。这里就不演示代码了。大家先理清楚思路,流程,就容易实现了。
LUA脚本更新
LUA一直是一种很神奇的脚本语言,无处不在,服务端,客户端,大型机,嵌入式设备都能看到它的踪影。虽然Unity3d官方不支持Lua脚本,但是已经有人写了c#版本的lua解析器了。我们可以将业务代码用Lua来实现。每次要更新代码的时候,只要将lua当做资源文件更新到客户端,运行即可。
C#版 Lua,有很多个版本,这里选择云风他们公司开源的UniLua,大家可以去Githunb下载
IOS平台比较遗憾,IOS是一个封闭的平台,所以它对app程序监管比较严格,一般情况下不运行热更新,每次版本更新都需要提交审核。所以涉及到手游代码的更新,都是采用完整包更新。LUA脚本更新的方式,有朋友试过说可以(他们一般是在程序上线一段时间后才使用Lua更新)。但是也存在风险的,如果被苹果发现,是属于违规的。这里不建议使用。
Android平台目前比较通用的方式是用代码dll反射更新机制。我们在实际过程中,将稳定不变的底层代码单独规划,用作游戏的主程序。全部业务逻辑代码发布时候,打包成dll,制成资源文件。客户端下载后,反射加载。只有当底层主程序要更新是,才单独下载主程序的apk文件,重新安装替换。平时的代码更新,可以随意更新代码dll
总结上面说的几种方式,各有优缺点。在不同的平台上策略也不尽相同。说一下我的经验:一般是优先发布android版本,有问题随时热更新代码调试。待版本稳定后,发布ios越狱版本。全部稳定后,最后才发布app store。众所周知,app store的审查周期比较长,有可能他们员工去休个假,几个星期才审核通过:)。每次审核不通过,又得重新修改提交审查,又是漫长的等待。在游戏界,时间就是生命。我们尽量在android平台上调试版本。
ps.大家有什么好的Unity3d技术点想讨论的,欢迎告知,我今后将会多多写一下大家比较感兴趣的实战内容。
最后祝大家工作顺利,项目大卖~。
Unity3d之AssetBundle打包与读取
AssetsBundle 学习(一)
Unity资源处理机制(Assets/WWW/AssetBundle/...)读取和加载资源方式详解
Unity5-ABSystem(四):AssetBundle依赖
u3d---打包资源AssetsBundle与读取
[Unity3d][NGUI]打包NGUI预制件成Assetbundle 两种思路.
Unity3d开发(十四) AssetBundle中的资源提取
Unity资源热更新之AssetsBundle
Unity5 AssetBundle的一些整理(一)
没有更多推荐了,

我要回帖

更多关于 把tif放到一张图上编辑 的文章

 

随机推荐