Unity问答系列1

1,让一个物体围绕某一点旋转,有几种方法?分别是什么?

答:见  http://blog.csdn.net/qiaoquan3/article/details/51306514
2,Mesh,Sphere,Box,Capsule,四种碰撞器。请按照性能开销由小到大进行排序。
答:collider的性能和效率大概的顺序是:Sphere Collider > Capsule Collider> Box Collider > Mesh Collider。取决于碰撞的定点数量和计算复杂度

4,请复制下列代码,并在编译器中测试:
void Start ()
{
        float a = 600.0f;
        float b = 1.0f - 80.0f / 100.0f;
        float c = a * b;
        int d = (int)c;
        Debug.Log (a);        
        Debug.Log (b);        
        Debug.Log (c);        
        Debug.Log (d);        
}
变量“d”的输出结果为多少?为什么?如果解决?

答:输出: 600,0.2,120,119;
首先,变量“d”的输出结果为119。
先解释为什么:在程序中精确计算中使用浮点数是非常危险的,尽管C#在浮点数运算时采取了很多措施使得浮点数运算的结果看起来是非常正常的。但实际上如果不清楚浮点数的特性而贸然使用的话(浮点数由于是计算机内部求补运算而进行的,因此可能存在误差。),将造成非常严重的隐患。而且在精度损失的时候,不会报告任何的错误,也不会有任何的异常产生~
小数多位后容易出现误差,使用double会看得更多有效数字,但依然会有误差,最后真正强转为int的实际上是一个199.9……无限接近于200的数,这个时候,应该改变计算公式。或者把最后的int d = (int)c;改为更高精度的decimal。即decimal d = (decimal)c; 可正常。
最后,所有的浮点型变量都存在精度损失的问题!而decimal是一个不折不扣的浮点型,不论它精度有多高,精度损失依然存在!如做大数据的百度,谷歌,财政等,肯定很多时候都要考虑这种问题。
高精度强制转换低精度就会必然丢失精度。修改方法:
int d = (int)c;  //会丢失精度
// float d = Mathf.CeilToInt(c); //ok
// int d = (int)Mathf.Ceil(c);     //ok
// float d = Mathf.Ceil(c);       //ok
// float d = (float)c;                //ok  double, decimal 
//      int d = (int)(c+0.1);           //ok

注:
a = Mathf.Floor(b)或者a = Mathf.FloorToInt(b):   取下限值 即a <= b
a = Mathf.Round(b)或者a = Mathf.RoundToInt(b):四舍六入,五取偶 ,
a = Mathf.Ceil(b)或者a = Mathf.CeilToInt(b):取下限值,a>=b

5,如何让粒子效果显示在UI前面?(NGUI或UGUI选其一回答)

答:

如果是NGUI修改粒子的renderQueue,修改尽量大就在所有UI上面,如果希望在2个UI之间就需要看看NGUI源码,http://m.blog.csdn.net/blog/yxriyin/44037673

如果是UGUI一种是可以使用相机把处理粒子,一种是设置sortingOrder http://www.xuanyusong.com/archives/3435

在NGUI中可以通过以下方式解决
(1)修改脚本中的RenderQueue值。
(2)使用另外一个摄像机,显示特效。
(3)修改粒子特效的Shader中的RendererQueue值。
(4)结合其他设置,还可以通过3D空间中的Z轴调整

在NGUI中可以通过以下方式解决

(1)修改Ngui中的UIPanel脚本中的默认的RenderQueue, 调整到3000以下,这样就不会遮挡住粒子特效了,当有的窗口需要显示在特效上面时,在检视面板中把该窗口的Renderer Q选项调整为Start At,值为3000以上,就可以解决,不过我的NGUI版本为3.1.6,所以可以直接调整。

(2)使用另外一个摄像机,显示特效。但是在UI窗口相互切换时,不太好控制。

(3)修改粒子特效的Shader中的RendererQueue值。
ngui的话 最好是把粒子都添加自定义 粒子层,新建一个相机 只做渲染粒子层,在其他相机渲染层前面 (方便脑洞大开的策划更改粒子需求)
ugui 原理也可以同上 ,或者把摄像机改成World Space 粒子调节z轴
canvas的RenderMode选择ScreenSpace-Camera,添加一个sorting Layer如hehe,粒子系统的ParticleSystem组件的最后一个Render选项里选择Sorting Layer为hehe
UGUI的Canvas使用World Space或Screen Space - Camera模式,通过改变位置让粒子更接近摄像机
UGUI,把canvas的Render mode值设置成screen space - camera,然后把camera拖进去,摆好粒子位置在UI前边即可
UGUI: 把画布(Canvas)里的Canvas的RenderMode参数改成 World Space ,再调整粒子的Z值就可以了

6,当一个细小的高速物体撞向另一个较大的物体时,会出现什么情况?如何避免?

答:会发生穿透(碰撞检测失败)

解决方法:
(1)增大细小物体的碰撞体
(2)使用射线检测,检测距离
(3)FixedUpdate频率修改,可以physics time减小,不建议这样做
(4)改变物体的速度,确保rigidbody不超过一定的速度,来达到减速目的,这个也不实用
(5)将检测方式改为连续检测,rigifdbody.collisionDetectionMode = CollisionDetectionMode.Continuous;  或者动态连续检测(
 CollisionDetectionMode.ContinuousDynamic)
(6)代码限制,加大计算量提前计算好下一个位置。

7,Update(),Awake(),Start()的执行顺序是?游戏开始后,分别在何时执行?
Awake()-> Start()-> Update();
脚本自带函数执行顺序如下:将下面脚本挂在任意物体运行即可得到

Awake ->OnEable-> Start -> FixedUpdate-> Update  -> LateUpdate ->OnGUI ->Reset -> OnDisable ->OnDestroy

Awake:用于在游戏开始之前初始化变量或游戏状态。在脚本整个生命周期内它仅被调用一次.Awake在所有对象被初始化之后调用,所以你可以安全的与其他对象对话或用诸如GameObject.FindWithTag()这样的函数搜索它们。每个游戏物体上的Awake以随机的顺序被调用。因此,你应该用Awake来设置脚本间的引用,并用Start来传递信息,Awake总是在Start之前被调用。它不能用来执行协同程序。
Start:仅在Update函数第一次被调用前调用。Start在behaviour的生命周期中只被调用一次。它和Awake的不同是Start只在脚本实例被启用时调用。你可以按需调整延迟初始化代码。Awake总是在Start之前执行。这允许你协调初始化顺序。在所有脚本实例中,Start函数总是在Awake函数之后调用。

Update:正常帧更新,用于更新逻辑。每一帧都执行,Update是在每次渲染新的一帧的时候才会调用,也就是说,这个函数的更新频率和设备的性能有关以及被渲染的物体(可以认为是三角形的数量)。在性能好的机器上可能fps 30,差的可能小些。这会导致同一个游戏在不同的机器上效果不一致,有的快有的慢。因为Update的执行间隔不一样了。FixedUpdate比较适用于物理引擎的计算,Update就比较适合做控制。

FixedUpdate:而FixedUpdate,是在固定的时间间隔执行,不受游戏帧率的影响。有点想Tick。所以处理Rigidbody的时候最好用FixedUpdate。

//调用时刻:

(1)Awake() : 脚本加载的时候调用,而脚本加载的时候意思为:对象(脚本所在的gameObject)第一次enable,即对象被加载的时候,脚本未启用(启用就是enable状态)也会执行。awake函数受游戏对象初始状态的影响, 当状态关闭,不调用;状态开启,调用;开启后关闭再重新开启,不调用.与与之绑定的脚本实例启用状态无关。

 (2)Start()  : 脚本运行时调用,在对象enable的情况下,脚本第一次enable,就是脚本运行的时刻。start函数受游戏对象上绑定的脚本实例启用状态相关, 脚本实例启用,调用; 关闭,不调用;开启后关闭再重新开启,不调用

 (3)Update()在Start()之后每帧调用一次时间不是固定的,用于游戏更新场景和状态。


8,数列 1,1,2,3,5,8,13... 第 n 位数是多少 ? 用 C# 递归算法实现

Func(n)
{
   if (n==1) return 1;
   if (n==2) return 1;
   return Func(n-1)+Func(n-2);
}

9,当游戏中需要频繁创建一个物体对象时,我们需要怎么做来节省内存?

答:

(1)保存成prefab,物体对象从prefab里拖拽生成,或者代码生成。

(2)使用AssetBundle也可以降低一定内存。

(3)采用对象池,使用对象池,将要重复创建的对象先创建一定的数量,然后隐藏起来,重置参数和位置,以便下一次利用;当要使用的时候在显示出来(setactive),插件pool manager也可以。切换场景之后可以进行回收。理想状态下自己管理所有的对象,CG机制只起辅助作用。参考代码如下:

//key为T类型子弹,value为创建的所有的T类型子弹
private Dictionary<System.Type,List<BulletBase>> pool;

//从子弹池中取出一个子弹
protected BulletBase GetBullet<T>() 
{
        BulletBase temp = null;//子弹父类
        System.Type type = typeof(T);//子弹T类型
        
        bool needCreate = false;//是否需要重新创建
        
        if(pool == null)//对象池为空
        {
                needCreate = true;
                
                pool = new Dictionary<System.Type, List<BulletBase>>();
                
        }else if(pool.Count == 0)//对象池已创建但没有数据
        {
                needCreate = true;
                
        }else
        {
                if(pool.ContainsKey (type))//对象池包含T类型子弹
                {
                        temp = pool[type].Find (o=>!o.IsBusy);//对象池查找不在使用的T类型子弹
                        
                        if(temp ==null){
                                needCreate = true;
                        }
                        
                }else
                {
                        needCreate = true;
                }
        }
        
        if(needCreate)//需要重新创建T类型子弹
        {
                
                BulletBase tempMemery = Resources.Load<BulletBase>("BulletAI/"+bulletOrginalName);
                
                if(tempMemery!=null){
                        
                        temp = GameObject.Instantiate<BulletBase>(tempMemery);
                        
                        tempMemery = null;
                        
                }
                
                Resources.UnloadUnusedAssets ();
                
                if(!pool.ContainsKey (type))//没有T类型子弹
                {
                        pool.Add (type, new List<BulletBase>());
                }
                
                pool[type].Add (temp);
                
        }
        return temp;
        
}<span style="font-family:Helvetica Neue, Helvetica, Arial, Hiragino Sans GB, Microsoft YaHei, WenQuanYi Micro Hei, sans-serif;color:#0000ff;"><span style="font-size: 14px; line-height: 21px;"><strong>
</strong></span></span>

10,Unity动态加载资源有几种方法,分别是什么?
法一:Resources.load,资源必须放在Resources文件夹下
法二:资源打成Assetbundle,www下载,得到bundle再load

法三:AssetDatabase.loadasset,只在编辑器模式下有效

具体的来说:

通过Resources模块,调用它的load函数:可以直接load并返回某个类型的Object,前提是要把这个资源放在Resource命名的文件夹下,Unity不管有没有场景引用,都会将其全部打入到安装包中。

通过bundle的形式:即将资源打成 asset bundle 放在服务器或本地磁盘,然后使用WWW模块get 下来,然后从这个bundle中load某个object。

通过AssetDatabase.loadasset :这种方式只在editor范围内有效,游戏运行时没有这个函数,它通常是在开发中调试用的

Resources.Load()和Assetbundle的区别

Resources资源的加载是动态加载内部的,AssetBundle 是动态加载外部的 .
Resources在编辑环境下是project窗口的一个文件夹,调用里面的资源,可以用Resources类,比如Resources.Load,打包后这个文件夹是不存在的,会统一生成assets资源,AssetBundle 是外部调用,要用AssetBundle 首先要先把资源打包为.assetbundle文件,再动态的去加载这个文件,本地或者网络服务器都可以。 



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值