《平行的世界》读后笔记

0

昨天晚上算是将《平行的世界》读完,觉得不能白读啊,所以今天晚上凭回忆稍微记录一下,不知道记录到什么程度。

首先这本书大概讲的是什么的,就如书名所说,平行世界,两个地球被打通了。
在几万年前人类是分很多种族的,就像指环王里面 似的,什么矮人,精灵之类的,而几万年前的人类也是分种族的,而我们属于智人。其中还有一族叫做尼安德特人,根据现代科学各种考究,尼安德特人的大脑要比我们智人要大的,所以推论是比我们人类聪明的,但现在却早已灭绝,也有讨论说可能是我们智人导致的,总之我们智人所到之处总有东西需要被消灭的。

平行的世界,被打通的就是一个相反的地球。在另一个地球,延续下来的是一个尼安德特人的世界,而智人却早就灭绝了,而灭绝原因当然不是尼安德特人的问题。因为他们的世界非常安全,和平,每个人手腕上都会有一个叫做机侣的东西,你可以认为是一台手机嵌入到手臂上好了。而这个机侣可以将人定位,还可以将你的所作所为进行录像,就像时刻有人监视你似的,所以人们都很自律。另外,他们还会进行基因选择,将拥有“坏”基因的人进行阉割,不仅如此还会对与这个人拥有50%基因的人也进行阉割,这样就隔绝了这部分基因的遗传。

他们的环境非常好,不像我们的地球燃烧各种石油煤气导致大气污染,当尼安德特人第一次来到我们地球的时候总是会描述他们敏感的嗅觉对这边空气的抱怨。
他们的嗅觉敏感,敏感到就像是狗鼻子一样,可以嗅到其他人的身体激素,比如恐惧时散发的气味等。所以他们的建筑或交通工具都会利用这一点,比如为了防止激素频繁的被他人嗅到,电梯或飞行机里都会有通风设置,将激素散发的味道迅速的排出;在类似法庭的地方,被告要站在上风向,这样他的激素就可以被其他人嗅到从而做出判断。

我们的世界是人口大爆发,大爆发的原因就是我们从事农业的生产;而尼安德特人他们的人口一直保持在一定水平,首先因为他们还会进行打猎,其次就是合欢节制度。
他们的世界男人和女人是分开住的,只有在每月的几天中属于合欢节,男女才会见面,而且这些天的见面女人并不会怀孕。而每10年他们就会修改合欢节的日期一次,为的就是在这一次交合让女人怀孕生育。所以尼安德特人的年龄都是一代一代的人。虽说男女分开住,只能在合欢节见面,那非合欢节怎么办呢?那就是每个尼安德特人除了会有一个异性配偶之外,还会有一个同性配偶。我指的的确是“配偶”的意思。

另外一提的就是他们的房子,大部分他们的房子都是一棵树,在树的底部掏空进行安置,但别以为他们是什么野人,他们的科技研究很多方面都是比我们要高许多的。这样房子的设计也算是融于自然了。但因为他们的人口基本恒定,所以也没有什么房地产行业。。。大都是某人去世之后,新来的人就搬进去。如果要“造”新房子,会有专门的人种植这样的树。

他们虽然没有上过太空,可能因为以我们所知要上太空得烧石油,但他们的科技是比我们要高的,比如这次两个世界的打通,就是因为两个科学家在使用量子计算机的时候导致的意外。
所谓量子计算机,我的理解就是通过调动周围空间的粒子进行计算的机器,每个粒子都相当于一个超级计算器,而且是在同时计算,这样的话,就比如我们现在要破解个密码用我们的PC要用个几万几十万年的,而用量子计算机只需要几分钟甚至几秒钟。所以当这两个科学家在进行量子计算的时候,计算机调用了另一个平行宇宙的粒子,所以两个世界就被打通了。

故事就由此开始。现在想来,书中应该是有三条线。
第一条,就是这条世界被打通了,然后围绕两个世界打通之后发生什么事情而进行展开的线;
第二条,是女主角,被强奸了,而这次事件贯穿始终,并且这个强奸犯的历程也是有很多地方值得思考;
第三条,就是关于地球磁场的转向,一直会被提及,并且在最后来了个“圣光降临”体验,看到这里的时候起初我有点莫名其妙。

其实应该还有一条,但这一条大多时候并不是一系列的事件,大多时候是一些讨论,而且是书中很重要的讨论,那就是宗教问题。我对宗教没什么研究,就是在最后智人女主角与尼安德特男主角决定他们混血儿孩子基因的时候,女主角坚定的说孩子不能有宗教信仰的基因。

除了宗教问题比较多之外,还有的就是环境问题。最后智人的某个人(重要的人,我就不提了)要灭绝尼安德特人的导火索应该就是看到他们的世界太漂亮了。

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");

TextFx 说明文档简单翻译

0

TextFx是好牛X的文字特效插件,编辑器也好强大,所以翻译了一下他的说明文档做个备份。这是好久之前翻译的了,所以记得好像有些部分没有翻译,应该是自认为没什么用的部分吧。。。。好吧,有多少贴多少。

 

1. Basic Setup

Importing the plugin

导入包之后会看到TextFX文件夹。

里面会有 Editor 和 Scripts 文件夹。 在Scripts文件夹中有个Effectmanager.cs脚本,这是你唯一需要用到的组件。

Setting Up a Text Animation Object

1. 在场景中创建一个空对象

2. 在这个空对象上添加EffectManager组件

clipboard

3. 设置你想要的字体文件到 Font属性上。或设置你的bitmap字体文件数据和他的material到FontDataFile 与 Font Material属性上。

4. 在Text属性上输入你想要使用的文字。然后你就看到文字出现在场景中了。

clipboard[1]

5. 这里有一些有效的设置可以调整文本的基本的布局/外观:

    * Text – 显示的以及被动画效果影响的文字

    * Display Axis – 表示文字是横向还是纵向的

    * Text Anchor – 表示文本排列的位置(左,右,中间)

    * Character Size – 文本字体的大小。默认为1

    * Line Height – 就是行间隔。默认为1

    * Letter Spacing Offset – 字符间隔

    * Max Width – 文字一行最大的宽度,超过这个宽度会自动到下一行(我试了下,没效果??)。在编辑器中用红线表示。

    * Play On Start? – 是否在EffectManager第一次active的时候就自动执行动画

    * On Finish Action – 当动画结束的时候发生什么

6. 当你觉得看起来还不错的时候就可以调整位置啊什么的,然后就可以配置动画了。

2. Making/Using A Bitmap Font

就是bitfont。。。。

3. Creating An Animation

首先打开TextFX

clipboard[2]

clipboard[3]

General Setting

基础设置:

clipboard[4]

* 预览控制按钮:Play,Reset.

* Text – 显示的文本

* Animate Per – 执行动画的单位,每字符,每个词,每一行。这个值可以自定义,写你自己的动画。

* Time – 使用Unity中的时间还是使用实际时间。

Adding An Animation

默认情况下,一个新的EffectManager对象是没有任何动画设置的,所以你需要添加一个,点击“Add Animation”按钮

clipboard[5]

可能会有多个动画,使用 Anim(N) 来选择他们。

每个字符只能被一个动画控制,所以你可以指定一个字符子集,通过 Animate on:

clipboard[6]

TextFX Actions

每个TextFX动画是一个序列,拥有一个或多个Actions.

一个Action定义了吻门从开始状态到结束状态的转换。

你需要设置开始于结束的转换的colour,position,rotation,scale,还有Duration

每个Action都有以下选项:

clipboard[7]

1. Action Type – 表明这个action是一个普通的animation sequence,还是一个用来停止animation的break action。

2. Letter Anchor – 在这个action中每个字符的锚点。比如字符从那部分开始/结束旋转,缩放

3. Ease Type – 不介绍了。

4. Start/End Colour Gradients? – 使用一个flat颜色来标识开始/结束颜色,还是使用一个4颜色(字符mesh的4个角)混合。

5. Start/End Colour – action开始/结束时的颜色

6. Set Position Axis Ease? – 允许你覆盖”Ease Type”,为每个position轴独立选择easeType。

7. Start/End Position – action开始/结束时的位置

8. Force This Position? – 如果选中,将会强制将所有字符放到这个位置,忽略使用默认的Character Space.

9. Set Rotation Axis Ease? – 允许你覆盖“Ease Type”为每个rotation轴独立选择easeType

10. Start/End Euler Rotation – action开始/结束时的欧拉角度。

11. Set Scale Axis Ease? – 允许你覆盖”Ease Type”为每个Scale轴独立选择EaseType

12. Start/End Scale – action开始/结束时的缩放值

13. Force Same Start? – 强制所有字符在开始此Action的时候在同一时间执行。

14. Delay – 开始延迟

15. Duration – 动作整个过程的执行时间

16. Audio OnStart/OnFinish – action开始/结束时播放的Audio clip.在Audio And Patricle Effects中了解详细

17. Emitter OnStart/OnFinish – 粒子发射器动画的播放当action 开始/结束时。在Audio And Patricle Effects中了解详细

Advanced Action Setting

在action中每个主要的变换与时间参数都有额外的设置来定义延展每个字符。这些可以帮助你实现更多的特效。

* Constant(固定的) variables – 所有字符使用同一个值

clipboard[8]

* Random variables – 字符将每次使用一个随机从From 与 To 之间的值。

clipboard[9]

* Eased variables – 你文本的第一个字符需要有from值,最后一个字符需要有To值,中间的会进行插值。

你可以通过设置easing function来改变每个字符的过程值。

clipboard[10]

* 3-way Eased variables – 类似于之前的2-way,出了一个中间值。从from到这个中间值,然后从中间值到To。

clipboard[11]

More Than One Action

当你增加一个额外的action的时候,你会注意到一些细微的差别。

为了保存时间设置,你的第二个以及所有的子action都会继承前一个action的时间, 通过勾选Offset Prev?

这将会隐藏所有Start状态的设置。你只需要设置他怎么变化到这个action即可。

你也可以取消选择这个徐昂想,这样你就可以定义你自己的开始状态,但要当心可能导致不太和谐的动画过程。

clipboard[12]

Offset Variables From Last State

其实每个参数选项都可以进行继承前一个action的操作,当然除了第一个action中的参数。使用 Offset From Last?选项。

如果值为0,则会保持前一个状态的值。

如果前一个状态值是随机的,这种设置就会非常有用,

clipboard[13]

Per-Axis Easing Function Overrides

在你的Action的任何转换中,你都可以为每个轴设置独立的变化ease.

这允许你创建更多动态的移动效果。

试着唯爱你的位置变换改写轴easing,将会非常cool!

clipboard[14]

4. Advanced Animations

Break State Actions

你可以创建一个暂停状态通过创建 Break-State Action.

设置Action Type为BREAK将会暂停动画一段时间,这个时间是durations

如果时间值<=0,则意味着永远暂停在这个点。

如果动画在暂停状态,则可以通过调用 ContinueAnimation 来强制暂停结束,并开始执行下一个Action

看看脚本吧骚年,你会了解更多。

clipboard[15]

Custom Animation Letters

通过Animate On选项可以指定动画发生在哪些字符上面。默认的一个动画会影响所有的字符,但你可以选择所有一个子集。

注意:每个字符只能被一个动画影响。所以如果你使用了多个动画,那就必须确保其他动画没有影响到同一个字符。

clipboard[16]

5. Loops

Loops Menu

你可以设置你的一个或多个Action进行循环。

在窗口的左边你可以找到Loops Menu.

这里你可以看到当前可以循环的动画

clipboard[17]

Adding A Loop

一个循环的是由一个开始action索引与一个结束Action索引定义,并且还有循环次数。

如果次数为<=0,则是无限循环。

这里有两种循环:

* Normal loop : 就是那个从startIndex到endIndex,完成一遍之后再从startIndex开始

* ReversLoop : 

最后还有个DFO(Delay First Only).which will cause your loop to only apply action timing delays

for the first forward pass through the loop. This stops the letters getting more and more out of sync with

each loop iteration. Delays which are constant across all letters will still be applied, as these won’t

affect the sequencing between letters.

当你添加了一个循环,左边就可以看到一个Action树。

注意:点击并拖拽一个节点到另一个节点可以创建一个loop

注意:loop是可以嵌入到其他loop中的,但不能与其他loop交叉。比如一个0->2,另一个1->3,这不行!!

clipboard[18]

上面这个例子:

* 循环0两次

* reverse循环1,2三册

* 一直循环3

6 Audio And Particle Effects

Adding an Audio Clip

clipboard[19]

~~~

Adding a Particle Effect

clipboard[20]

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();

}