• 【Unity技巧】开发技巧(技巧篇)



    写在前面

    备忘录篇一样,这篇文章旨在总结Unity开发中的一些设计技巧,当然这里只是我通过所见所闻总结的东西,如果有不对之处欢迎指出。

    技巧1:把全局常量放到一个单独的脚本中

    很多时候我们需要一些常量,例如是否输出Log,正式服务器和测试服务器的IP等等,我们可以把这些常量写在同一个脚本里,并设置属性为public static,然后在其他脚本里直接访问该变量即可。当代码量越来越大时,你会发现这样会减少很多查找常量的时间。而且,这样更改时也非常方便,例如当需要发布新版本时,你只要把该脚本中的log开关设为false就可以了。又或者公司更改了服务器地址,一个简单字符串的更改就可以了。

    例如,我们在名为Const.cs的脚本中添加如下代码:

    [csharp] view plain copy print?在CODE上查看代码片派生到我的代码片
    1. public class Const {  
    2.   
    3.     public static bool IsWriteMsg = true;  
    4.   
    5.     public static bool IsDebugBuild = true;  
    6. }  


    其中IsWriteMsg表明是否需要将文本写到本地以供查看,IsDebugBuild表明是不是Debug模式(一般用于控制是否输出Log)。

    技巧2:把全局函数放到一个单独的脚本中

    和上一条类似,有时我们需要一些经常使用的、且无关对象的函数,例如解析系统某些特定含义的字符串、得到角色在场景中的位置等。我们可以把这些函数写在同一个脚本里,并设置函数属性为public static即可。

    技巧3:保存字符串和JSON信息

    我们经常需要和字符串打交道,例如得到服务器传来的消息等等,而且想要保存它们,复制粘贴又太麻烦了,作为一个很懒的程序员,怎么能一直重复做一件事情呢!

    例如,我们在名为GlobalFunc.cs(即为技巧2中提到的全局函数脚本)的脚本中,添加如下代码(关于Json部分,需要LitJson插件,可参见这篇博文)(注意:其中有用到技巧1中的Const.cs脚本中的变量):

    [csharp] view plain copy print?在CODE上查看代码片派生到我的代码片
    1. using UnityEngine;  
    2. using System;  
    3. using System.Text;  
    4. using System.IO;  
    5. using System.Collections;  
    6. using System.Collections.Generic;  
    7. using LitJson;  
    8.   
    9. public class GlobalFunc {  
    10.   
    11.     static public void SaveJson(object obj, string filepathandname)  
    12.     {  
    13.         Debug.LogWarning("========> SaveJson:   " + filepathandname);  
    14.           
    15.         // ELIMINATE WARNING  
    16.         //string levelnameLower = Application.loadedLevelName.ToLower();  
    17.           
    18.         if(Application.isEditor)  
    19.         {  
    20.             string file = "./" + filepathandname;  
    21.               
    22.             if (File.Exists(file) )  
    23.             {  
    24.                 File.Delete (file);  
    25.             }  
    26.               
    27.             System.IO.TextWriter writer = new System.IO.StreamWriter(file, false);  
    28.               
    29.             LitJson.JsonWriter jw = new JsonWriter( writer as System.IO.TextWriter );  
    30.               
    31.             jw.PrettyPrint = true;  
    32.               
    33.             try  
    34.             {  
    35.                 LitJson.JsonMapper.ToJson( obj, jw );  
    36.             }  
    37.             catch(Exception e)  
    38.             {  
    39.                 UnityEngine.Debug.LogError(e);    
    40.             }  
    41.               
    42.             writer.Close();  
    43.         }  
    44.     }  
    45.       
    46.     static public void SaveText(string tex, string filepathandname)  
    47.     {  
    48.         if(Const.IsWriteMsg || !Const.IsDebugBuild)  
    49.         {  
    50.             return;  
    51.         }  
    52.         Debug.LogWarning("========> SaveJson:   " + filepathandname);  
    53.           
    54.         //string levelnameLower = Application.loadedLevelName.ToLower();  
    55.           
    56.         string file = "";  
    57.           
    58.         if(Application.platform == RuntimePlatform.Android )  
    59.         {  
    60.             file = Application.persistentDataPath+"/"+filepathandname;  
    61.         }  
    62.         else if(Application.isEditor)  
    63.         {  
    64.             file = "./" + filepathandname;  
    65.         }  
    66.         if(file == "")  
    67.         {  
    68.             return ;  
    69.         }  
    70.         if (File.Exists(file) )  
    71.         {  
    72.             File.Delete (file);  
    73.         }  
    74.         System.IO.TextWriter writer = new System.IO.StreamWriter(file, false);  
    75.           
    76.         writer.Write(tex);  
    77.           
    78.         writer.Close();  
    79.     }  
    80.       
    81.     static public string LoadText(string filepathandname)  
    82.     {  
    83.         Debug.LogWarning("========> LoadJson: " + filepathandname);  
    84.         System.IO.TextReader r = new System.IO.StreamReader("./" + filepathandname);  
    85.         string tmp = r.ReadToEnd();  
    86.   
    87.         r.Close();  
    88.   
    89.         return tmp;  
    90.     }  
    91. }  



    技巧4:自定义弹出框

    弹出框,类似于Windows编程中常见的各种MessageBox,它们有固定的界面格式,程序员一般只要指定style、title和内容即可。

    详见这篇博文

    技巧5:暂停游戏

    关于Time.timeScale来暂停游戏的细节,请见《Unity备忘录篇》

    如果使用Time.timeScale = 0来暂停游戏,那么下面两种方法可能可以帮助你:

    • 把所有的移动都放到FixedUpdate中(不太可能)
    • Update中,所有的移动都使用Time.deltaTime控制
     
    当然,还有另一种比较麻烦但扩展性很强的方法。如果一个物体需要一个暂停动作,例如停止动画等等,可以让它的脚本实现OnPauseGame()函数,而在重启时实现OnResumeGame() 函数。那么暂停游戏可以通过调用所有对象上的OnPauseGame()函数:
    [csharp] view plain copy print?在CODE上查看代码片派生到我的代码片
    1. Object[] objects = FindObjectsOfType (typeof(GameObject));  
    2. foreach (GameObject go in objects) {  
    3.     go.SendMessage ("OnPauseGame", SendMessageOptions.DontRequireReceiver);  
    4. }  

    然后再调用OnResumeGame() 进行重启。
     
    一个基本的脚本类似下面这样:
    [csharp] view plain copy print?在CODE上查看代码片派生到我的代码片
    1. protected bool paused;  
    2.    
    3. void OnPauseGame ()  
    4. {  
    5.     paused = true;  
    6. }  
    7.    
    8. void OnResumeGame ()  
    9. {  
    10.     paused = false;  
    11. }  
    12.    
    13. void Update ()  
    14. {  
    15.     if (!paused) {  
    16.     // do movement  
    17.     }  
    18. }  

    这样方法有一个非常大的好处就是,你可以自己定制所有物体在暂停和重启时的行为,例如存储和加载数据等等。
     

    技巧6:使用Vector3.Lerp移动物体

    我们可以使用Lerp函数实现在两个点——start和to,进行插值,其中t是插值比率。

    [csharp] view plain copy print?在CODE上查看代码片派生到我的代码片
    1. transform.position = Vector3.Lerp(start, to, t);  


    当t<=0时,Lerp函数返回start;当t>=1时,Lerp函数返回to。因此,如果你想要在某个时间内把物体从start移动到to位置,你可以通过不断增加t(通常每帧增加的值为Time.deltaTime/NumberOfSecondsToComplete)来实现。像下面这样:

    [csharp] view plain copy print?在CODE上查看代码片派生到我的代码片
    1. Vector3 _start;  
    2. Vector3 _target;  
    3. float _t;  
    4.    
    5. void Update()  
    6. {  
    7.      transform.position = Vector3.Lerp(_start, _target, _t);  
    8.      _t += Time.deltaTime/2; //Take 2 seconds  
    9. }  
    10.    
    11. public void SetTargetPosition(Vector3 newTargetPosition)  
    12. {  
    13.     _start = transform.position;  
    14.     _target = newTargetPosition;  
    15.     _t = 0;  
    16. }  


    还有一种情况就是,你想要从物体的当前位置开始进行一个平滑的移动。这时,我们需要把start替换成物体本身的位置,transform.position。

    [csharp] view plain copy print?在CODE上查看代码片派生到我的代码片
    1. void Update(){  
    2.     transform.position = Vector3.Lerp(transform.position, target.position, Time.deltaTime);  
    3. }  
    一些例子使用Time.time作为插值比率。但这种方法会发生一些莫名其妙的错误,因此你的移动可能只会发生在游戏的一开始几秒钟。

    Shader中避免If语句

    可以使用lerp和step函数来代替使用If语句。例如:

    1. /* y1, y2, b1, b2 */  
    2. float4 constants = float4(5, 6, 2, 3);  
    3.   
    4. float2 tmp = 10 * constants.xy + constants.zw;  
    5. x = lerp(tmp[1], tmp[0], step(x, 0.5));  

    参考:

    http://gamedev.stackexchange.com/questions/45398/avoid-if-statements-in-directx-10-shaders

    http://gamedev.stackexchange.com/questions/59476/using-two-shaders-instead-of-one-with-if-statements

  • 相关阅读:
    hdu 1083 Courses
    hdu 1068 Girls and Boys
    hdu 2988 Dark roads
    hdu 1879 继续畅通工程
    hdu 1875 畅通工程再续
    hdu 1233 还是畅通工程
    hdu 4040 (贪心算法)
    FZU 2111 Min Number
    Reconstructing Cloud-Contaminated Multispectral Images With Contextualized Autoencoder Neural Networks(自编码机重建云污染区)
    跑深度学习网络遇到的一些错误总结
  • 原文地址:https://www.cnblogs.com/android-blogs/p/6424105.html
Copyright © 2020-2023  润新知