BestHttp 说明文档翻译

5

这个当时再找关于网络的插件,就看到了这个,边看文档便翻译,虽然最后还是没有用过这个插件,但这里备份下,说不定下次就用上了。

 

BestHttp 文档

介绍

BestHTTP是一个机遇RFC_2616的HTTP/1.1实现,这个支持几乎所有的unity移动端和pc平台。

我的目标是创建一个简单的使用方法,但是也很有用的插件,作为unity插件能够发挥HTTP/1.1的潜力。

这个文档是个简单快速的教学文档,并没有包含所有的函数与属性。

你也可以在包中找到一些 有用的demo:

* Load Image Test:

一个简单的交互式demo,用来演示下载一张图片并用它来作为texture

* Rest API Test:

这个例子演示怎么使用BestHTTP与RestAPI service结合。这个例子用到了json,但BestHTTP本身是不需要任何第三方依赖的。

* Audio Streaming Test:

一个非常简单的例子来演示BestHTTP的流能力

* Stream Leaderboard Test:

另一个流的例子用来演示 慢的带宽(或较慢的server处理)与有效的客户端的缓存。这种方法我们限制用户与server带宽以及server的处理能力。

安装

你需要将plugins文件夹从BestHttp文件夹中移动到assets文件夹。

快速开始:

首先,你需要添加以下代码:

using BestHTTP;

GET requests

向web Server发送一个请求的简单办法就是创建一个 HTTPRequest对象,并向他的构造函数提供url与回调函数。

创建之后,我们质素要调用Send()函数,就发送请求了:

HTTPRequest request = new HTTPRequest(new Uri(“https://google.com”), onRequestFinished);
request.Send();

其中的回调函数 OnRequestFinished()可能的实现为:

void OnRequestFinished(HTTPRequest request, HTTPResponse response)

{

Debug.Log(“Request Finished! Text received: ” + response.DataAsText);

}

就如你看到的,回调函数参数包含一个源request,以及一个从Server获取到的应答数据的HTTPResponse 对象。

如果这个对象为null表示有错误,并且request对象会有一个异常的属性,可以获取额外的关于这个错误的信息。

当请求是在单独的线程中执行,回调函数都是在Unity的主线程调用的,所以我们不需要做线程同步的一些事情。

如果我们想要写更简洁的代码,可以使用lambda语法,在这个例子中,我们可以这么写:

new HTTPRequest(new Uri(“https://google.com”), (request, response) =>
Debug.Log(“Finished!”)).Send();

POST Requests

上面这个例子是GET requsts. 如果我们不需要指定方法,所有的请求都默认是GET Requests。构造函数还有一个参数用来指定请求的方法:

HTTPRequest request = new HTTPRequest(new Uri(“yourserver.com/posturi”),

HTTPMethods.Post,

OnRequestFinished);

request.AddField(“FieldName”, “Field Value”);

request.Send() ;

你可以使用RawData属性来设置字段来POST:

HTTPRequest request = new HTTPRequest(new Uri(“yourserver.com/posturi”),

HTTPMethods.Post,

OnRequestFinished);

request.RawData = Encoding.UTF8.GetBytes(“Field Value”);

request.Send() ;

除了GET,POST之外,你还可以使用HEAD,PUT,DELETE,PATCH:

HEAD:

HTTPRequest request = new HTTPRequest(new Uri(“server.com/posturi”), HTTPMethods.Head,

OnRequestFinished);

request.Send();

PUT:

HTTPRequest request = new HTTPRequest(new Uri(“server.com/posturi”), HTTPMethods.Put,

OnRequestFinished);

request.Send();

DELETE:

HTTPRequest request = new HTTPRequest(new Uri(“server.com/posturi”),

HTTPMethods.Delete,

OnRequestFinished);

request.Send() ;

PATCH:

HTTPRequest request = new HTTPRequest(new Uri(“server.com/posturi”),

HTTPMethods.Patch,

OnRequestFinished);

request.Send();

怎么使用下载数据

大多数时候我们的请求是从server上获取数据。原始的数据可以从HTTPResponse对象的数据属性中访问到。来看个下载image的例子:

new HTTPRequest(new Uri(“http://yourserver.com/path/to/image.png”), (request, response) =>
{
var tex = new Texture2D(0, 0);
tex.LoadImage(response.Data);
guiTexture.texture = tex;
}).Send();

当然有更简单的写作方法:

new HTTPRequest(new Uri(“http://yourserver.com/path/to/image.png”), (request, response) =>
guiTexture.texture = response.DataAsTexture2D).Send();

除了DataAsTexture2D之外还有DataAsText用来转换应答数据为utf8的字符串。在未来可能会有更多的转换类型。

注意:所有的在本文档中的例子没有做错误检测!在你的产品中别忘了做null检测。

从WWW切换

你可以yield一个HTTPRequest通过协同调用:

HTTPRequest request = new HTTPRequest(new Uri(“http :// server.com”));

request.Send();

yield return StartCoroutine (request);

Debug.Log(“Request finished! Downloaded Data:” + request.Response.DataAsText);

Debug.Log的调用只有当request完成之后。这种方式你就可以不必提供一个回调函数了(如果你想你仍然可以使用)。

进阶话题:

这一part将会介绍一些非常有用的用法。

我们可以非常方便的使用HTTPRequest的构造函数来启用或禁用一些基本特性,这些参数如下:

* methodType:

我们想server发送的请求类型,默认的方法类型为 HTTPMethods.Get

* isKeepAlive:

表明我们需要tcp链接,保持与Server的链接,所以连贯的http请求不需要重复链接。默认为true,它可以为我们保留一段时间。否则如果我们知道不再需要requests了,那就可以设置为false.

* disableCache:

告诉BestHTTP使用还是跳过整个缓存机制。如果这个值为true,则系统不会从一个保存的response中查找,也不会保存response.默认是false

身份验证

Best HTTP支持基本的和精华的验证,通过HTTPRequest的Credentials属性:

using BestHTTP.Authentication;

var request = new HTTPRequest(new Uri(“https :// httpbin . org / digest – auth / auth – int / usr / paswd”), (req, resp)

=>

{

if (resp.StatusCode != 401)

Debug.Log(“Authenticated”);

else

Debug.Log(“NOT Authenticated”);

Debug.Log(resp.DataAsText);

5

});

request.Credentials = new Credentials(“usr”, “paswd”);

request.Send()

默认情况下,我们提供给HTTPRequest构造函数的回调函数只会调用一次,当server的应答全部下载完成与处理完成的时候。如果用这种方式,我们下载一个很大的文件超出了我们移动设备的内存,则应用就会crash,用户就会开始骂娘。

要避免这种情况,BestHTTP被设计为很简单的控制这种情况:只要设置某个flag为true, 每获取我们规定大小的数据一次就调用一次我们的回调函数。

另外如果我们没有关闭缓存系统,下载的response就会被保存,所以下一次我们可以从本地缓存stream整个response,而不需要修改我们的代码,甚至不需要去接触web Server(注意:server必须发送有效的缓存头(“Expires”header:查看 RFC))。

看个例子:

   1: var request = new HTTPRequest(new Uri("http://yourserver.com/bigfile"), (req, resp) =>

   2: {

   3:     List<byte[]> fragments = resp.GetStreamedFragments();

   4:     // Write out the downloaded data to a file:

   5:     using (FileStream fs = new FileStream("pathToSave", FileMode.Append))

   6:     foreach(byte[] data in fragments)

   7:     fs.Write(data, 0, data.Length);

   8:     if (resp.IsStreamingFinished)

   9:     Debug.Log(“Download finished!”);

  10: });

  11: request.UseStreaming = true;

  12: request.StreamFragmentSize = 1 * 1024 * 1024; // 1 megabyte

  13: request.DisableCache = true; // already saving to a file, so turn off caching

  14: request.Send();

上面这个代码发生了什么:

* 我们打开了flag – UseStreaming, 所以我们的回调函数可能会被调用多次。

* StreamFragmentSize表明我们每次希望接收到的数据的最大长度。

* 当每StreamFragmentSize的chunk下载之后都被调用一次回调函数,直到IsStreamingFinished为true

* 要获取下载的数据,需要使用 GetStreamedFragments()函数。我们需要将他的结果保存到一个临时变量,因为其内部的buffer将会在这次调用之后清空,所以连续调用这个函数的话只会获得null的结果。

* 我们这里禁止了使用缓存,因为我们已经将他保存到文件中并且不想占用太多的空间。

Caching(缓存)

缓存也是基于HTTP/1.1 RFC. 它使用headers来保存与验证response.缓存机制工作于后台,对于它我们仅有的控制权就是来决定启用还是禁用。

如果被缓存的response有“Expires”的header并包含一个未来的日期,BestHTTP就会直接使用缓存的数据,而不需要在经过server的验证。这意味着我们不需要与server进行tcp链接。这可以保存我们的时间,节约带宽,并离线作业。

虽然缓存是自动的,我们还有一些控制的东西,或者我们可以获取一些信息,通过使用HTTPCacheServices类:

* BeginClear():

在一个单独的线程中,开始时清空整个缓存。

* BeginMaitainence():

通过这个函数,我们可以基于最后访问时间进行对缓存的删除。它删除访问时间对于指定的时间较旧的,我们也可以使用这个函数来保证缓存大小在控制之下:

// Delete cache entries that weren’t accessed in the last two weeks, then delete entries to keep the size of

// the cache under 50 megabytes, starting with the oldest.

// 删除缓存中在两周内没有访问的数据,保持缓存大小在50M以下,从最旧的开始

   1: HTTPCacheService.BeginMaintainence(new HTTPCacheMaintananceParams(TimeSpan.FromDays(14),50 * 1024 * 1024));

* GetCacheSize():

获取缓存的大小,基于bytes

* GetCacheEntryCount():

获取缓存中保存的条目数量。缓存条目的平均大小可以通过计算获得:

   1: float avgSize = GetCacheSize() / (float)GetCacheEntryCount() .

Cookies

控制cookies的操作对于程序员来说是透明的。设置请求cookei头,解析,维护response的Set-Cookie头都在插件中自动完成。

任然有一些控制的途径:

* 可以在每个request中禁用,或者设置全局属性,在HTTPRequest对象的IsCookiesEnabled属性或HTTPManager.IsCookiesEnables属性

* Cookie可以通过调用CookieJar.Clear()函数来删除

* 新的Server发送的cookie,可以通过response的Cookies属性来访问

* 有许多全局设置关于cookies的,可以查看 全局设置 的了解更多。

Proxy(代理)

一个HTTPProxy对象可以设置为一个HTTPRequest的Proxy属性。这种方式将request通过给与的代理:

   1: request.Proxy = new HTTPProxy(new Uri("http :// localhost :3128"));

下载进度跟踪

要跟踪与显示下载进度,你可以使用HTTPRequest类的OnProgress事件。这个事件的参数是源HTTPRequest对象,下载的bytes长度,数据的总长度

   1: var request = new HTTPRequest(new Uri(address), OnFinished);

   2: request.OnProgress = OnDownloadProgress;

   3: request.Send();

   4: void OnDownloadProgress(HTTPRequest request, int downloaded, int length) {

   5: float progressPercent = (downloaded / (length * 100.0f));

   6: Debug.Log(“Downloaded: ” + progressPercent.ToString(“F2”) + “%”);

   7: }

终止一个Request

你可以通过调用HTTPRequest对象的Abort()函数来终止一个进行中的request:

request = new HTTPRequest(new Uri(“http://yourserver.com/bigfile“), (req, resp) => { … });
request.Send();
// And after some time:
request.Abort();

这时回调函数会被调用,response会是null.

超时

对于一个request你可以设置两个超时:

* ConnectTimeout: 通过属性你可以控制你的APP与Server之间要等待一个连接的时间。默认为20秒

   1: request = new HTTPRequest(new Uri("http://yourserver.com/"), (req, resp) => { … });

   2: request.ConnectTimeout = TimeSpan.FromSeconds(2);

   3: request.Send();

* Timeout: 这个属性可以等待一个request的处理时间(发送一个request,下载一个response的时间)

   1: request = new HTTPRequest(new Uri("http://yourserver.com/"), (req, resp) => { … });

   2: request.Timeout = TimeSpan.FromSeconds(10);

   3: request.Send();

全局设置

通过下面这些属性,我们可以改变默认值,否则就在HTTPRequest的构造函数中指定。所以大部分这些属性都是节约时间的快捷方式。

这些改变将会影响到接下来的所有request的创建。

可以通过HTTPManager类的静态属性来改变默认值:

* MaxConnectionPerServer:

允许连接到一个主机的数量。

http://example.orghttps://example.org 是两个不同的server。默认值是4

* KeepAliveDefaultValue:

这个值是HTTPRequest.IsKeepAlive的默认值。如果为false,则tcp链接就会在每次request之前i建立,并在之后关闭。如果希望有连续不断的请求最好改为false(应该为true吧?我看错了?)。HTTPRequest构造函数中的值只对这个request管用。默认值为true

* IsCachingDisabled:

这个属性用来启用或禁用缓存服务。HTTPRequest的构造函数中的这个值只对这个request有效。默认值为true

* MaxConnectionIdleTime:

指定BestHTTP的闲置等待时间在结束最后的request销毁链接之前。默认为2分钟

* IsCookiesEnabled:

这个变量可以启用或禁用Cookie操作。默认为true

* CookieJarSize:

可以被操作的Cookie的数量。默认为10485760(10M)

* EnablePrivateBrowsing:

如果这个操作打开则不会再硬盘上写入Cookie.默认为false

* ConnectTimeOut:

HTTPRequest的默认ConnectTimeout值。默认20秒

* RequestTimeOut:

HTTPRequest的默认Timeout值,默认60秒

示例代码:

   1: HTTPManager.MaxConnectionPerServer = 10;

   2: HTTPManager.RequestTimeout = TimeSpan.FromSeconds(120);

线程安全

因为插件内部是使用线程来平行的处理所有request,所有共享数据(cache,cookie,等等)都被考虑已经实现了线程安全。一些点最好还是要知道一下:

* Request的回调函数的调用,以及其他所有的回调函数(比如WebSocket的回调)都被设计在Unity的主线程(就像unity的事件,比如awake,start,update等等)中调用,所以你不需要做任何线程同步的工作。

创建,发送请求使用多个线程是安全的,但是你需要调用 BestHTTP.HTTPManager.Setup();函数在发送任何请求之前在Unity事件中(比如awake,start)

WebSocket

我们可以通过WebSocket类来使用WebSocket的特性。只需要给WebSocket构造函数传入Server的URL

   1: var webSocket = new WebSocket(new Uri(“wss://html5labs-interop.cloudapp.net/echo”));

之后我们可以注册我们的事件监听:

* OnOpen event:

当与Server正式建立连接时候会被调用,这个事件之后WebSocket的IsOpen属性变为true,知道我们或server端关闭连接,或者有错误发生。

   1: webSocket.OnOpen += OnWebSocketOpen;

   2: private void OnWebSocketOpen(WebSocket webSocket)

   3: {

   4:     Debug.Log("WebSocket Open!");

   5: }

* OnMessage event:

从Server接收到一段文本消息时触发。

   1: webSocket.OnMessage += OnMessageReceived;

   2: private void OnMessageReceived(WebSocket webSocket, string message)

   3: {

   4:     Debug.Log("Text Message received from server: " + message);

   5: }

* OnBinary event:

从Server接收到一段二进制数据时触发

   1: webSocket.OnBinary += OnBinaryMessageReceived;

   2: private void OnBinaryMessageReceived(WebSocket webSocket, byte[] message)

   3: {

   4:     Debug.Log("Binary Message received from server. Length: " + message.Length);

   5: }

* OnClosed event:

当我们或Server关闭连接,或一个内部错误发生的时候会触发。

当客户端通过Close函数关闭连接时可以提供一个Code和一条message来标明关闭的原因。Server可以处理这个CODE与Message.

   1: webSocket.OnClosed += OnWebSocketClosed;

   2: private void OnWebSocketClosed(WebSocket webSocket, UInt16 code, string message)

   3: {

   4:     Debug.Log(“WebSocket Closed!”);

   5: }

* OnError event:

触发时机为:不能连接到server,有内部错误发生,连接丢失。

第二个参数是Exception对象,可以为null.这种情况可以通过WebSocket的InternalRequest来获得更多信息。

   1: webSocket.OnError += OnError;

   2: private void OnError(WebSocket ws, Exception exception)

   3: {

   4:     string errorMsg = string.Empty;

   5:     if (ws.InternalRequest.Response != null)

   6:     errorMsg = string.Format("Status Code from Server: {0} and Message: {1}",

   7:                             ws.InternalRequest.Response.StatusCode,

   8:                             ws.InternalRequest.Response.Message);

   9:     Debug.Log(“An error occured: " + (ex != null ? ex.Message : "Unknown Error " +errorMsg);

  10: }

* OnIncompleteFrame event:

查看 Advanced Websocket 那节吧。

当我们注册了时间之后我们就可以打开连接:

   1: webSocket.Open();

之后我们就可以获得OnOpen事件,我们就可以给Server发送消息了

   1: // Sending out text messages:

   2: webSocket.Send(“Message to the Server”);

   3: // Sending out binary messages:

   4: byte[] buffer = new byte[length];

   5: //fill up the buffer with data

   6: webSocket.Send(buffer);

所有交互完成之后可以关闭连接:

   1: webSocket.Close();

Advanced WebSocket

* Ping messages:

可以启用一个新的线程发送Ping message到server通过设置StartPingThread属性为true在我们接收到OnOpen事件之前。这种方法会定期的向server发送Ping message.间隔可以通过设置PingFrequency属性设置(默认为1000ms)

* Pong messages:

所有从server接收到的Ping message都会被插件自动转换为一个Pong应答

*Streaming:

长文本或二进制消息将会通过片段化获得。这些片段会默认通过插件自动的装配起来,这种机制可以被重写,如果我们注册了OnIncompleteFrame事件的话。这个事件将会在每次客户端接收到不完全的片段的时候调用,这时这些片段将会被插件忽略,不会去组装它们也不会保存它们。这个时间可以用来完成streaming

当前支持的HTTP/1.1特性:

这些特性大部分都是隐藏的或被自动使用的:

● HTTPS

● Store responses in a cache

● Cache validation through the server

● Stream from cache

● Persistent connections

● gzip, deflate content encoding

● Raw and chunked transfer encoding

● Range requests

● Handle redirects

● POST forms and files

● WWW Authentication

FAQ

Q: 我接收到以下错误信息:Internal Compiler error. See the console log for

more information. output was:

Unhandled Exception: System.Reflection.ReflectionTypeLoadException: The classes in the

module cannot be loaded.

A: 检查 安装 那一节的步骤

Q: What Stripping Level can be used with BestHTTP?

A: All stripping levels supported. However there are some cases where you need a link.xml, for

these cases a link.xml is included. You have to copy/merge this xml.

Easy Save 2 说明文档简单翻译(四)

0

Saving and Loading PNG and JPG Images

你可以使用EasySave为Texture2D加载一张JPEG,PNG图片,也可以保存Texture2D为PNG图片。

Loading an Image as a Texture2D

你可以通过使用ES2.LoadImage来为Texture2D加载JPEG或PNG。

例如,从用于的硬盘中加载一张JPG到GameObject的material中,可以使用一下代码:

   1: renderer.material.mainTexture = ES2.LoadImage("C:/Users/User/myImage.jpg");

Saving a Texture2D as a PNG

保存Texture2D为PNG,使用ES2.SaveImage函数

例如,保存GameObject material的texture:

   1: ES2.SaveImage(renderer.material.mainTexture, "C:/Users/User/MyImage.png");

 

 

Loading An Audio File As An AudioClip

EasySave允许加载 MP3,Ogg, WAV,XM,IT,MOD,S3M格式的文件称为Unity的AudioClips,使用ES2.LoadAudio函数。

注意你不能在Mac与PC上加载MP3文件,也不能在移动设备上加载Ogg文件。

   1: audio.clip = ES2.LoadAudio("C:/User/Users/myAudio.ogg");

   2: audio.Play();

 

 

Faster Saving and Loading using ES2Writer and ES2Reader

如果需要保存与加载额外的执行效率,或额外的灵活性,那么我们建议你使用 ES2Writer与ES2Reader.

这个比起多次调用ES2.Save与ES2.Load有更快的速度。

Using ES2Writer and ES2Reader with Tags

和save,load一样,writer与reader同样可以使用tags.

在开始之前,你需要注意你不可以使用reader或writer打开同一个文件多次,否则会有意外的行为发生。

Saving to a File using Tags

要保存数据到文件,你需要通过ES2Writer.Creater创建ES2Writer并调用Write函数来保存数据到文件。当你结束保存文件,你必须调用writer的Save函数来保存数据。

除非你使用的是Using语法,否则你必须调用writer的Dispose函数,当你结束的时候。

   1: using(ES2Writer writer = ES2Writer.Create("myFile.txt"))

   2: {

   3:     // Write our data to the file.

   4:     writer.Write(this.name, "nameTag");

   5:     writer.Write(this.transform, "transformTag");

   6:     writer.Write(newint[]{1,2,3},"intArrayTag");

   7:     // Remember to save when we're done.

   8:     writer.Save();

   9: }

Loading From a File using Tags

使用ES2Reader.Create创建一个ES2Reader,并调用Read函数来从文件中读取数据。

你也可以使用Self-assigning Read函数来直接加载组件。

除非你使用using语法,否则最后要调用Dispose函数。

   1: using(ES2Reader reader = ES2Reader.Create("myFile.txt"))

   2: {

   3:     // Read data from the file in any order.

   4:     reader.Read<Transform>("transformTag", this.transform);

   5:     this.name = reader.Read<string>("nameTag");

   6:     int[] myIntArray = reader.ReadArray<int>("intArrayTag");

   7: }

Using ES2Writer and ES2Reader Sequentially

最快的加载数据方式就是按你保存时的顺序加载,不适用tags.前面的例子中,如果当保存或加载不适用tag就是这里的快速了。

按照你保存时的顺序读取数据,这是非常重要的,否则你会得到一个运行时错误。

同时也要注意当你连续保存时,我们使用 Save(false)来代替Save()用来告诉EasySave不使用Tag。

Saving to a file Sequentially

   1: using(ES2Writer writer = ES2Writer.Create("myFile.txt"))

   2: {

   3:     // Write our data to the file in the order we are going to read it.

   4:     writer.Write(this.name);

   5:     writer.Write(this.transform);

   6:     writer.Write(newint[]{1,2,3});

   7:     // Remember to save when we're done.

   8:     writer.Save(false);

   9: }

Loading from a File Sequentially

用ES2Reader.Create(filepath)创建ES2Reader并调用其Read(data)来加载文件中的数据。

   1: using(ES2Reader reader = ES2Reader.Create("myFile.txt"))

   2: {

   3:     // Read the data from the file in the same order as we saved it.

   4:     this.name = reader.Read<string>();

   5:     reader.Read<Transform>(this.transform);

   6:     int[] myIntArray = reader.ReadArray<int>();

   7: }

Easy Save 2 说明文档简单翻译(三)

0

Encryption

EasySave给与你使用 AES 128-bit的加密能力。

要启用它,你需要设置encrypt参数为true,同时也可以设置加密密码。

加密is good for 混淆(obfuscation).However, when ultimate security is important we advise you instead store data on a secure server using HTTPS, which is supported by Easy Save.

   1: /* Save data with encryption */

   2: ES2.Save(123, "file.es?encrypt=true&password=pass");

   3: /* Load data with encryption */

   4: inti = ES2.Load<int>("file.es?encrypt=true&password=pass");

 

 

Saving and Loading From Web

EasySave允许你使用WEB PHP文件保存数据到MySQL,数据库由EasySave提供。

他保存到数据库使用EasySave自己的格式,你可以使用ES2Web.UploadRaw(string data)和ES2Web.LoadRaw()来上传于下载数据,从数据库中。

Web Setup

1. 从 Assets/Plugins/Easy Save 2/Web文件夹中找到ES2.php,ES2SQL.sql文件。

clipboard

2. 在一个MySQL中使用ES2SQL.sql文件。记住这个表的名称,待会你会用到。

clipboard[1]

注意:示意图只是显示你怎么使用PHPMyAdmin控制面板来插入表,并不是一定要用这中方式。

3. 打开ES2.php,修改其中的标记信息:hostnam,usernam,password,database name,

clipboard[2]

4. 也在这个文件中输入username与password, 在Unity中调用ES2Web功能时需要使用

clipboard[3]

5. 将这个文件放到你的web服务器,并进入这个网址,如果成功你会看到信息:

ES2.php and MySQL database are working correctly

6. 现在你可以在Unity中使用ES2Web了。

确定在使用ES2Web功能时,你提供的username password与ES2PHP中的一致。

    Saving to Web

我们使用协同来上传于下载, 这就允许我们使用多帧来下载数据。连我们建议熟悉下协同在尝试保存于下载web数据之前。

这个例子中,我们创建一个协同上传一个Mesh到web:

1. 首先,创建ES2Web对象,使用到ES2.php的URL作为path.在URL中我们也可以提供参数。一个重要的参数就是webfilename,这个决定了在我们MySQL服务器中的逻辑文件。

2. 另一个重要参数是webusername,webpassword,这两个就是在ES2PHP中的username,password.同时我们还可以使用tag与encrypt参数。

3. 现在我们yield ES2Web.Upload(data)来上传我们的数据。

4. 最后,我们通过ES2Web.errorcode与ES2Web.error检测是否有返回错误。下面会有错误列表。

   1: public IEnumerator UploadMesh(Meshmesh,stringtag)

   2: {

   3:     // Create a URL and add parameters to the end of it.

   4:     stringmyURL = "http://www.server.com/ES2.php";

   5:     myURL += "?webfilename=myFile.txt&webusername=user&webpassword=pass";

   6:     // Create our ES2Web object.

   7:     ES2Webweb = newES2Web(myURL + "&tag="+ tag);

   8:     // Start uploading our data and wait for it to finish.

   9:     yieldreturnStartCoroutine(web.Upload(mesh));

  10:  

  11:     if(web.isError)

  12:     {

  13:         // Enter your own code to handle errors here.

  14:         Debug.LogError(web.errorCode + ":"+ web.error);

  15:     }

  16: }

    Loading From Web

这个例子中我们从web下载一条数据,你也可以下载整个文件(只要不指定tag参数即可)

1. 首先,创建ES2Web 对象

2. yield ES2.Download().

3. 一旦下载完成,我们需要检查错误,

    1. 保存数据到本地文件使用ES2Web.SaveToFile(path)

    2. 直接从下载的数据中加载ES2Web.Load(tag),或其他load函数(看API)

   1: public IEnumerator DownloadMesh(stringtag)

   2: {

   3:     // Create a URL and add parameters to the end of it.

   4:     stringmyURL = "http://www.server.com/ES2.php";

   5:     myURL += "?webfilename=myFile.txt&webusername=user&webpassword=pass";

   6:     // Create our ES2Web object.

   7:     ES2Webweb = newES2Web(myURL + "&tag="+ tag);

   8:  

   9:     // Start downloading our data and wait for it to finish.

  10:     yieldreturnStartCoroutine(web.Download());

  11:  

  12:     if(web.isError)

  13:     {

  14:         // Enter your own code to handle errors here.

  15:         Debug.LogError(web.errorCode + ":"+ web.error);

  16:     }

  17:     else

  18:     {

  19:         // We could save our data to a local file and load from that.    

  20:         web.SaveToFile("myFile.txt");

  21:         // Or we could just load directly from the ES2Web object.

  22:         this.GetComponent<MeshFilter>().mesh = web.Load<Mesh>(tag);

  23:     }

  24: }

    Delete from Web

使用ES2Web.Delete(path)来删除数据,其他步骤通上面的一样

   1: public IEnumerator DeleteWebFile(stringfile)

   2: {

   3:     // Create a URL and add parameters to the end of it.

   4:     stringmyURL = "http://www.server.com/ES2.php";

   5:     myURL += "?webfilename="+file+"&webusername=user&webpassword=pass";

   6:     // Create our ES2Web object.

   7:     ES2Webweb = newES2Web(myURL);

   8:  

   9:     // Start downloading our data and wait for it to finish.

  10:     yieldreturnStartCoroutine(web.Delete());

  11:  

  12:     if(web.isError)

  13:     {

  14:         // Enter your own code to handle errors here.

  15:         Debug.LogError(web.errorCode + ":"+ web.error);

  16:     }

  17: }

    integrating with a login system(整合一个登陆系统)

ES2.php文件中包含一个 Authenticate($username,$password)方法,用来验证你的登陆。

username is the webusername specified in Unity.

password is the webPassword specified in Unity. By default Easy Save 2 sends the password as an MD5 hash, so you may need to convert your password to an MD5 hash using PHP’sMD5($str) method.

Alternatively you can get ES2 to send your password in plain text. To do this, set thehashType variable of your ES2Web objects to ES2Web.HashType.None. However, it is not advised that you do this unless you are using HTTPS.

The Authenticate method should return false if either the username or password do not match, or true if they both match.

    Error Codes

“00”

Unity有一个上传错误。可能是因为URL不存在,或Server关闭了。

“01”

不能连接到数据库,或数据库登陆错误

“02”

username,password与ES2.php中的不一致

’03”

ES2.php中没有数据接收到

“04”

数据库中找不到ES2相关的表

“05”

你要下载的数据根本不存在

 

 

Saving and Loading from Resources

Unity的Resources文件夹允许你在加载其中的文件,包括EasySave2的保存文件。

Saving to Resources

只有在Editor状态的时候EasySave才可以保存到Resources.如果没有这个文件夹就创建一个。

如果你想要保存数据到Resources并在之后的运行中使用它们,所有文件都必须以 .bytes 后缀。

因为ES2.Save允许一个绝对路径,我们可以使用Application.dataPath来获取我们Assets文件夹的绝对路径,从而可以获取Resources文件夹路径。

或你直接将文件拖到Resources中。

   1: ES2.Save(123, Application.dataPath+"/Resources/myFile.bytes?tag=myInt");

Loading From Resources

要从Resources中加载数据,你需要设置你的保存位置为Resources,你可以通过使用参数来设置,或通过使用ES2Settings对象。

注意不同于保存,,我们不需要提供Resources文件夹的路径。

   1: // Load from Resources using the savelocation parameter

   2: intmyInt = ES2.Load<int>("myFile.bytes?tag=myInt&savelocation=resources");

   3: // Load from Resources using ES2Settings

   4: ES2Settingssettings = newES2Settings();

   5: settings.location = ES2Settings.SaveLocation.Resources;

   6: intmyInt = ES2.Load<int>("myFile.bytes?tag=myInt", settings);

Easy Save 2 说明文档简单翻译(二)

0

Saving and Loading from File(保存或加载文件)

EasySave允许你保存或加载文件。文件将被默认创建在 Application.persistentDataPath中,这个是保证存在的。你也可以指定任何的绝对路径,只要这个路径可用。

你不可以为Unity Web玩家保存到文件,EasySave将自动保存到PlayerPrefs,即使你给了一个文件名或绝对路径。

Saving and Loading from File

首先,要提供一个文件名作为path参数,你也可以指定一个文件夹,如果不存在将会自动创建。

你可以使用任何扩展名的文件,只要目标操作系统允许。通常我们使用”.txt”

   1: /* Save the value 123 to a file named myFile.txt */

   2: ES2.Save(123,  "myFile.txt");

   3: /* Now load that int back from the file */

   4: intmyInt = ES2.Load<int>("myFile.txt");

   5: /* Save myFile.txt inside myFolder */

   6: ES2.Save(123,  "myFolder/myFile.txt");

   7: /* And now load it back */

   8: intmyInt = ES2.Load<int>("myFolder/myFile.txt");

使用绝对路径

一个绝对路径必须以盘符或slash开始,/或\都可以,基于你的目标平台系统。

你必须确定这个路径在runtime时是存在的,并且你有权限可以在这个位置写数据。我们建议你只在必要的时候使用绝对路径。

   1: /* Save our int to an absolute file on Windows */

   2: ES2.Save(123, "C:/Users/User/myFile.txt");

   3: /* Load from an absolute file on OSX */

   4: intmyInt = ES2.Load<int>("/Users/User/myFile.txt");

 

 

Exists and Delete(判断存在与删除)

Exists

ES2.Exists(path) 检测给与的path的数据是否存在。这个特别适用于你不太确定数据是否存在的时候。

这个函数也可以用于文件夹与tags

   1: /*If myData exists, load it*/

   2: if(ES2.Exists("myData"))

   3: myInt = 

   4: ES2.Load<int>("myData");

   5: /*If myFolder exists, save to it*/

   6: if(ES2.Exists("myFolder/"))

   7: ES2.Save(123, 

   8: "myFolder/myFile.txt");

Delete

ES2.Delete(path)被用来删除数据,包括文件,文件夹,tags.

你必须小心使用它,因为他甚至可以删除非EasySave创建的文件或文件夹。

   1: /* Delete a key */

   2: ES2.Delete("myInt");

   3: /* Delete a file */

   4: ES2.Delete("myFile.txt");

   5: /* Delete myFolder */

   6: ES2.Delete("aFolder/myFolder/");

   7: /* Delete a tag */

   8: ES2.Delete("myFile.txt?tag=myTag");

 

 

Parameters

参数允许我们设置EasySave的path.

它的格式类似于HTTP的查询字符串,?表示开始解析参数,用&来分开每个参数。

比如,要启用加密并设置加密的密码,我们可以轻易的将参数增加到path的末尾:

   1: ES2.Save(123,"myFile.txt?encrypt=true&password=myPassword");

参数列表


一般参数

tag

允许你在同一个文件中保存多条数据,使用tag来区分这多条数据。
例子:myFile.txt?tag=MyData

encrypt

启用加密操作

例子:myFile.txt?encrypt=true&password=myPassword

password 使用加密时使用的密码
savelocation

我们想要在哪里执行操作,文件,PlayerPrefs或Resources

例子:myFile.txt?savelocation=file

webusernam

当使用web 功能时为ES2.php提供用户名称。

例子:http://www.mysite.com/ES2.php?webusername=MyUsername&webpassword=MyPassword

webpassword 同上,密码。
webfilename

我们想要保存到web的文件名称

例子:http://www.mysite.com/ES2.php?webfilename=MyFile.txt

Mesh参数

savenormals

保存mesh的时候是否保存normal

例子:myFile.txt?savenormals=false

saveuv

是否保存UV
例子:myFile.txt?saveuv=true

saveuv2 是否保存UV2
savetangents 是否保存切线tangent

 

 

Saving Multiple Variables to One File using Tags

EasySave允许你想一个文件中保存多条数据,使用tags来区分。

如果使用已经存在的tag则会覆盖原来的这条数据。

你可以在一个文件中使用tag保存不同类型的数据,并使用任意的顺序加载。

你可以使用ES2.Delete(path)来删除tag,或删除删除文件来删除所有的tags

   1: /* Save two different pieces of data to one file */

   2: ES2.Save("myObjectName", 

   3: "file.txt?tag=nameTag");

   4: ES2.Save(transform, 

   5: "file.txt?tag=trTag");

   6: /* Overwrite a tag with a new value */

   7: ES2.Save("NewName", 

   8: "file.txt?tag=nameTag");

   9: /* Load our data in any order */

  10: ES2.Load<Transform>("file.txt?tag=trTag", 

  11: transform);

  12: name = 

  13: ES2.Load<string>("file.txt?tag=nameTag");

  14: /* Delete all tags by deleting entire file */

  15: ES2.Delete("file.txt");

Easy Save 2 说明文档简单翻译(一)

0

这个也是很强大的插件,内容也挺简单的其实。到其官方网站上都能找到教程,所以还是为了防止自己一段时间不用忘掉了,所以翻译了一下,做个备份。

 

Supported Types(支持保存的类型)

Primitive Types

  • string
  • float
  • byte
  • bool
  • char
  • int
  • long
  • short
  • uint
  • ulong
  • ushort

Unity Types

  • Vector2
  • Vector3
  • Vector4
  • Quaternion
  • Color
  • Color
  • Texture2D
  • Material
  • Mesh
  • AudioClip
  • Rect
  • Bounds

Collections

  • Array [ ]
  • 2D Array [,]
  • Dictionary<TKey, TValue>
  • List<T>
  • Queue<T>
  • HashSet<T>
  • Stack<T>

Note: Saving collections containing collections is not directly supported

Components

  • Transform
  • SphereCollider
  • BoxCollider
  • CapsuleCollider
  • MeshCollider

Note: All Components are saved by value, not by reference.

 

Basic Saving and Loading(基本的保存与载入)

保存变量与组件

要保存变量,我们使用 ES2.Save(variable, path).

第一个参数是我们想要保存的变量,而且其类型必须符合支持的类型。

第二个参数是一个path,用来作为id。可以是一个简单的名称、文件名、文件路径或其他什么。

   1: /* Save the value 123 to a key named myInt */

   2:  

   3: ES2.Save(123,  "myInt");

   4:  

   5: /* Save this transform to a file named File.txt */

   6:  

   7: ES2.Save(this.transform,  "File.txt");

加载变量

要加载变量,使用 ES2.Load<Type>(path). ‘Type”是你要加载的变量的类型,path必须是你保存时使用的path.

如果你不确定数据是否存在,你可以使用 ES2.Exists(path)来检测:

   1: /* Load the int we saved into myInt */

   2:  

   3: myInt = ES2.Load<int>("myInt");

   4:  

   5: /* Check that there is data to load */

   6:  

   7: if(ES2.Exists("myInt"))

   8:  

   9: /* Load the int we saved into myInt */

  10:  

  11: myInt = ES2.Load<int>("myInt");

加载组件

因为组件是unity中工作的,所以我们必须提供增加次组件的数据

使用 ES2.Load(path, component)

   1: /* 

   2: 

   3: Load the Transform we saved 

   4: 

   5: into the Transform of this object 

   6: 

   7: */ 

   8:  

   9: ES2.Load<Transform>("File.txt", this.transform);

 

Paths(路径)

在EasySave中,路经典详细描述了数据。比如,我们可能使用一个路径来告诉EasySave我们保存的是什么数据,以及从那里加载数据。

我们也可以增加 参数 在路径的后面来指定设置。

Types of Path


Key

用key作为path id保存一条数据,和使用PlayerPrefs是一样的效果:

   1: ES2.Save(data, "myKey");

File

这个指定了一个文件,你可以保存一条数据,也可以使用它Tags来保存多条数据。

如果你指定了一个文件名,这个文件路径将相对于EasySave的默认路径 relative.

你也可以指定绝对路径,在windows中必须从驱动盘符开始(比如C:/)或一个slash(/或\)

   1: // Relative file

   2:  

   3: ES2.Save(data, "myFile.txt");

   4:  

   5: // Absolute file

   6:  

   7: ES2.Save(data, "C:/Users/User/myFile.txt");

   8:  

Folder

这个指定了一个文件夹。你可以使用相对或绝对路径。

一个文件夹路径必须以splash结尾。

   1: // Relative folder

   2:  

   3: ES2.Exists("myFolder/anotherFolder/");

   4:  

   5: // Absolute folder 这个没有splash,是不是错了我擦

   6:  

   7: ES2.Exists("C:/Users/User/myFolder");

   8:  

URL

一个URL被用于当保存或加载数据从web使用ES2Web的时候。

一个URL路径必须以http:// 或 https:// 开头

   1: ES2Webweb = newES2Web("http://www.site.com");

Steer2 说明教程翻译

0

这个插件挺小巧挺厉害的,所以忍不住多用了几次,刚接触的时候就将它的说明文档为翻译了一下,虽然这个插件很简单,而且看几个例子就知道怎么回事了,但还是贴出来备份一下吧。其实很多都是按自己的理解来的,还有一些没有理解硬翻的。。。

 

Steer2

Quick Start

要创建一个操纵代理,只要在你的游戏对象上增加”Steering Agent”组件即可。这个组件提供了控制速度、灵敏度来控制你的代理。

ip_image002

  • Max Velocity : 你的代理可以达到的最大速度
  • Mass:代理的质量,决定了你的代理的加速度以及改变方向的速度。如果设为一个很大的值,则会使得代理转弯时很慢但会是一个平滑的角。
  • Friction:代理的摩擦力。当没有一个持续的里作用于它的时候就会慢下来然后停止。
  • Rotate Sprite:是否让游戏对象朝向目标方向。

要给代理添加特定的行为,可以从以下组件中选择。每一个都提供了一个移动行为,并提供了多个可修改的变量。可以给一个代理增加多个行为组件。

  • Seek : 代理会寻找并接近目标
  • Flee: 代理将会逃离目标
  • Pursue:代理将会追赶另一个代理,并会预测目标代理的位置。
  • Evade:代理将会逃离目标代理,并会预测目标代理的位置
  • FllowPath:代理会沿着一串路径点移动
  • Flock : 代理们将会同附近的代理组群

Steering Behaviors

如果一个代理有多个行为,则最后的行为将是这些行为的组合计算获得的。所有的控制行为都有一个”weight”参数。这个参数控制在整个移动中会体现多少细节上的效果。你可以各自控制不同的行为的这个参数来使得最后的行为更为复杂一点。

         Seek(寻找)

ip_image004

  • TargetPoint :目标点

Flee(逃离)

ip_image006

如果目标点在自己的半径范围内则进行逃离

  • Target Point : 要逃离的目标点
  • Flee Radius : 逃离的半径范围
  • Draw Gizmos: 在Editor模式可以看到半径

Arrive(到达)

ip_image008

到达目标点,并在进入目标的半径范围后进行平滑的停止移动。

  • Target Point: 目标
  • Slow Radius: 进入该半径后代理开始慢下来
  • Stop Radius: 进入该半径后代理开始停止
  • Draw Gizmos: 会在Editr模式画出目标点的两个半径的圆

Pursue(追赶,跟踪)

ip_image010

追赶目标代理,并预测目标代理的路径。

  • Target Agent : 目标代理

Evade(逃避)

ip_image012

逃离目标代理,并预测目标代理路径。

  • Target Agent: 要逃离的目标代理
  • Flee Radius: 进入这个半径就开始逃离
  • Draw Gizmos:会在目标代理上绘制Gizmo

Follow Path:

ip_image014

代理会沿着路径点移动,并在最后一个点的时候平稳着陆。

  • Path : 一系列的点
  • Slow Radius: 当下一个点是最后一个点时,代理进入该半径后就开始减速
  • Stop Radius : 当下一个点时最后一个点时,进入该半径就开始停止移动
  • Next Coord Radius: 代理必须进入到这个区域才能开始移动到下一个点
  • Loop: 选中后代理将会循环移动
  • Draw Gizmos:

Flock

ip_image016

这个集群行为是有点复杂的,因为涉及到多个代理,他们会在靠近时聚集在一起并根据给与的参数开始周旋。你可能需要搞乱weight来实现想要的效果。

  • Neighbor Radius: 进入到这个半径内的代理将会尝试聚集,任何代理离开了这个半径将会被忽略。
  • Alignment Weight:组成队列的力的大小。这个力将尝试将多个代理的朝向统一起来。
  • Cohesion Weight:凝聚力大小。这个力将尝试将多个代理拉在一起组成一个group
  • Separation Weight:间隔力。这个力会尝试在代理间分开一段距离,如果有重叠则会停止移动一下。

Building Your Own Behaviors

要实现你自己的控制行为,你可以继承”SteeringBehaviour”来实现。Override GetVelocity()函数来返回你自己的速度。其父类有个公共变量”agent”,保存当前游戏对象。你可以想使用其他变量一样来使用这个”agent”来访问速度。”SteeringAgent.AgentList”维护一个全局代理列表。

你可以看下其他行为的代码实现方式,来参考实现你自己的。

Audio Toolkit 说明翻译

0

Audio Toolkit在其官方网站的一些说明,我做了写汉化,因为自己记性差,到下次用的时候可能就又要返回头去看说明,所以索性就先翻译一下,方便以后查阅。都是按自己的理解翻译的,如果有什么错误,可以指出。

 

 

How To Use:

* 创建一个GameObject命名为”AudioController”,并添加AudioComtroller脚本。这个对象唯一。

* 创建一个AudioObject prefab包含以下组件:Unity本身的AudioSource,AudioObject,PoolableObject(如果你想用pool的话)

clipboard

*然后在这个prefab上自定义你的AudioSource参数。下一步,指定你的自定义的这个prefab到AudioController中的“audio Object”参数上:

clipboard[1]

*创建你的音频目录,在AudioController的属性面板中。比如”Music”,”SFX”等等。

clipboard[2]

*audio要能执行需要创建一个”audio item” 在指定的目录中,并且是需要唯一名称。

你也可以从project面板中选择多个audio片段然后点击”Add Selected Audio clips”.这会为每个片段创建一个audio item.

clipboard[3]

*如果你愿意,你也可以为你的audio Item创建多个子item.一个子item指向实际的音频文件。如果拥有了超过一个的子item,则Audio Toolkit将会随机播放,或按照一定的顺序播放,你可以进行设置。

你也可以从Project视图中选择多个audio片段,然后点击”Add Selected audio clips”按钮,你就会为每个片段都创建为一个子item。

clipboard[4]

要播放一个audio item, 只需要调用static function:

AudioController.Play( “MyUniqueAudioItemName” )

使用AudioController.PlayMusic( “MusicAudioItemName” )来播放音乐,这个函数保证在同一时间只能有一个音乐文件在播放,在音乐转换时可以由淡入淡出的效果,可以再AudioController中配置。

进一步的例子:

AudioController.Play( “MySoundEffect1” );
AudioController.Play( “MySoundEffect2”, new Vector3( posX, posY, posZ ) );
AudioController.PlayMusic( “MusicTrack1” );
AudioController.SetCategoryVolume( “Music”, 0.5f );
AudioController.PauseMusic();

///PoolableObject文件头说明///////////////////////////////////////////////////////////////////////////////////////////

用法:

把PoolableObject脚本组件添加到想要入池的prefab上。你可以在属性面板中设置该对象在池中的最大值。

替换所有Instantiate(prefab)的地方,替换为 ObjectPoolController.Instantiate(prefab).

替换所有Destroy(objectInstance)为 ObjectPoolController.Destroy(objectInstance)

注意Awake() 与 OnDestroy()也会被调用,不管怎样,要确保所有组件数据在Awake中能够初始化所有可能在生命历程中会被改变的数据。

Start()也会被调用,紧随Awake()在ObjectPoolController.Instaniate(…)中,不会在下一帧调用。

如果一个池中物的父节点是非池中物,则这个父节点必须使用ObjectPoolController.Destroy(…)来进行destroy操作。

要明白OnDestroy()会被调用多次:

a) 当object被添加到池中的时候会调用 ObjectPoolController.Destroy()

b) 当object确实被销毁的时候,比如加载新的场景时。

引用一个池中的对象不会变为null一旦一个object已经被”destroyed”并移到池中,使用PoolableReference如果你需要一些check。

PoolableObject说明:

添加这个脚本到你的prefab使他成为池中物。

查看ObjectPoolController来了解怎么设置池中的prefab.

下面这些消息是向池中物对象发送的:

Awake(),OnDestroy(),是当池中对象被active或deactive时。

这个方式就类似于一般behaviour的instantiated与destroy.

只有当 sendAwakeStartOnDestroyMessage 被选中时才会发送这两个消息。

OnPoolInstanceAwake 与 OnPoolableInstanceDestroy 是在当对象是确实的被实例化与销毁时调用。

因为当前Unity的机制问题,OnPoolableInstanceDestroy在Flash中不起作用。

OnPoolableObjectActivated 与 OnPoolableObjectDeactivated 是在池中对象active与deattive时调用。

这两个消息只有当 sendPoolableActivateDeactivateMessage被选中时才发送。

ObjectPoolController说明:

一个静态类用于创建与销毁池中对象。

什么是池?。。。

池怎么工作?。。。

怎么在池中设置一个prefab:

首先是给这个prefab添加PoolableObject脚本组件。你可以在属性面板中设置这个prefab在池中的最大数量。

替换Instantiate(myprefab)为ObjectPoolController.Intantiate(myprefab)

替换Destroy(myObjectInstance)为ObjectPoolController.Destroy(myObjectInstance)

注意,要理解下面这个:

所有数据必须在Awake,Start中被初始化。

OnDestroy将会在这个object被Unity删除的时候被调用第二次。

如果一个池中物对象的父对象不是一个池中物,那这个扶对象被删除的时候也必须使用ObjectPoolControler.Destroy(…).

如果你持有一个池中物对象的引用,则ObjectPoolControll.Destroy之后这个引用不会被变为null,就像一般Unity对象的用法一样。这是因为这个对象仍然存在—只是在池中。

要确保你持有的这个池中物的引用是可用的,你必须使用PoolableReference

PoolableReference说明:

辅助类,用于解决当持有一个池中物的引用,但该池中物被ObjectPoolController.Destroy移回到池中时该引用变为null的情况。

一个组件要替掉一般的脚本组件的引用而是用池中物对象:

MyScriptComponent scriptComponent = PoolableObjectController.Instantiate(prefab).GetComponent<MyScriptComponent>();

var myReference = new PoolableReference<MyScriptComponent>(scriptComponent);

if(myReference.Get() != null) // 将会检测这个实例化的是否仍属于源对象

{

    myReferrence.Get().MyComponentFunction();

}

Audio Toolkit 说明翻译

0

Audio Toolkit在其官方网站的一些说明,我做了写汉化,因为自己记性差,到下次用的时候可能就又要返回头去看说明,所以索性就先翻译一下,方便以后查阅。都是按自己的理解翻译的,如果有什么错误,可以指出。

 

 

How To Use:

* 创建一个GameObject命名为”AudioController”,并添加AudioComtroller脚本。这个对象唯一。

* 创建一个AudioObject prefab包含以下组件:Unity本身的AudioSource,AudioObject,PoolableObject(如果你想用pool的话)

clipboard

*然后在这个prefab上自定义你的AudioSource参数。下一步,指定你的自定义的这个prefab到AudioController中的“audio Object”参数上:

clipboard[1]

*创建你的音频目录,在AudioController的属性面板中。比如”Music”,”SFX”等等。

clipboard[2]

*audio要能执行需要创建一个”audio item” 在指定的目录中,并且是需要唯一名称。

你也可以从project面板中选择多个audio片段然后点击”Add Selected Audio clips”.这会为每个片段创建一个audio item.

clipboard[3]

*如果你愿意,你也可以为你的audio Item创建多个子item.一个子item指向实际的音频文件。如果拥有了超过一个的子item,则Audio Toolkit将会随机播放,或按照一定的顺序播放,你可以进行设置。

你也可以从Project视图中选择多个audio片段,然后点击”Add Selected audio clips”按钮,你就会为每个片段都创建为一个子item。

clipboard[4]

要播放一个audio item, 只需要调用static function:

AudioController.Play( “MyUniqueAudioItemName” )

使用AudioController.PlayMusic( “MusicAudioItemName” )来播放音乐,这个函数保证在同一时间只能有一个音乐文件在播放,在音乐转换时可以由淡入淡出的效果,可以再AudioController中配置。

进一步的例子:

AudioController.Play( “MySoundEffect1” );
AudioController.Play( “MySoundEffect2”, new Vector3( posX, posY, posZ ) );
AudioController.PlayMusic( “MusicTrack1” );
AudioController.SetCategoryVolume( “Music”, 0.5f );
AudioController.PauseMusic();

///PoolableObject文件头说明///////////////////////////////////////////////////////////////////////////////////////////

用法:

把PoolableObject脚本组件添加到想要入池的prefab上。你可以在属性面板中设置该对象在池中的最大值。

替换所有Instantiate(prefab)的地方,替换为 ObjectPoolController.Instantiate(prefab).

替换所有Destroy(objectInstance)为 ObjectPoolController.Destroy(objectInstance)

注意Awake() 与 OnDestroy()也会被调用,不管怎样,要确保所有组件数据在Awake中能够初始化所有可能在生命历程中会被改变的数据。

Start()也会被调用,紧随Awake()在ObjectPoolController.Instaniate(…)中,不会在下一帧调用。

如果一个池中物的父节点是非池中物,则这个父节点必须使用ObjectPoolController.Destroy(…)来进行destroy操作。

要明白OnDestroy()会被调用多次:

a) 当object被添加到池中的时候会调用 ObjectPoolController.Destroy()

b) 当object确实被销毁的时候,比如加载新的场景时。

引用一个池中的对象不会变为null一旦一个object已经被”destroyed”并移到池中,使用PoolableReference如果你需要一些check。

PoolableObject说明:

添加这个脚本到你的prefab使他成为池中物。

查看ObjectPoolController来了解怎么设置池中的prefab.

下面这些消息是向池中物对象发送的:

Awake(),OnDestroy(),是当池中对象被active或deactive时。

这个方式就类似于一般behaviour的instantiated与destroy.

只有当 sendAwakeStartOnDestroyMessage 被选中时才会发送这两个消息。

OnPoolInstanceAwake 与 OnPoolableInstanceDestroy 是在当对象是确实的被实例化与销毁时调用。

因为当前Unity的机制问题,OnPoolableInstanceDestroy在Flash中不起作用。

OnPoolableObjectActivated 与 OnPoolableObjectDeactivated 是在池中对象active与deattive时调用。

这两个消息只有当 sendPoolableActivateDeactivateMessage被选中时才发送。

ObjectPoolController说明:

一个静态类用于创建与销毁池中对象。

什么是池?。。。

池怎么工作?。。。

怎么在池中设置一个prefab:

首先是给这个prefab添加PoolableObject脚本组件。你可以在属性面板中设置这个prefab在池中的最大数量。

替换Instantiate(myprefab)为ObjectPoolController.Intantiate(myprefab)

替换Destroy(myObjectInstance)为ObjectPoolController.Destroy(myObjectInstance)

注意,要理解下面这个:

所有数据必须在Awake,Start中被初始化。

OnDestroy将会在这个object被Unity删除的时候被调用第二次。

如果一个池中物对象的父对象不是一个池中物,那这个扶对象被删除的时候也必须使用ObjectPoolControler.Destroy(…).

如果你持有一个池中物对象的引用,则ObjectPoolControll.Destroy之后这个引用不会被变为null,就像一般Unity对象的用法一样。这是因为这个对象仍然存在—只是在池中。

要确保你持有的这个池中物的引用是可用的,你必须使用PoolableReference

PoolableReference说明:

辅助类,用于解决当持有一个池中物的引用,但该池中物被ObjectPoolController.Destroy移回到池中时该引用变为null的情况。

一个组件要替掉一般的脚本组件的引用而是用池中物对象:

MyScriptComponent scriptComponent = PoolableObjectController.Instantiate(prefab).GetComponent<MyScriptComponent>();

var myReference = new PoolableReference<MyScriptComponent>(scriptComponent);

if(myReference.Get() != null) // 将会检测这个实例化的是否仍属于源对象

{

    myReferrence.Get().MyComponentFunction();

}