版权声明:本文为博主原创文章,未经博主允许不得转载。
最近开始研究unity,准备将之前自己业余时间做的一款游戏(金庸群侠传X)发行移动端版本(我不是游戏公司从业人员,业余时间自己做着玩,大神轻喷)。由于之前使用silverlight(C#)做的,所以移植unity有天然的语言优势。
看了一下unity的更新公告,4.6出的UGUI我比较喜欢,因为之前也用过NGUI,总感觉不是很顺畅。那么,即使有坑,我们也来趟趟吧。
到现在陆陆续续大概已经趟了一个月的坑了,总的感觉是,对于unity还是比较满意的:非常简单容易上手,功能还算齐全——现在DEMO版本已经能够在android、ios上较好的运行。上两张截图吧
现在总结一下我在开发中碰到的几个“坑”——当然,话说在前头,因为我也是刚开始学习unity,目前我自己认为的坑也可能是我自己的理解不够,如果大家有更好的解决方法,欢迎指正!楼主写这篇博客的时候是2015年1月13日,使用的是当前最新的unity 4.6f1版本。
1、scroll rect的各种问题
(2015年02月9日:这个是我自己搞错了,unity有提供方法,只是我之前用错了,请移步这篇博文,这一条下面写的大家就当看个笑话吧 :D)
很多界面需要用到滚屏,unity提供scroll rect控件。具体的组织方式为:
每个ScrollRect对应一个scrollcontent,ScrollContent定义内容的排版组织方式,如Grid Layout Group或者Vertical Layout Group。(这里比较像silverlight中的StackPanel和GridPanel)
我使用以后发现一个最大的问题是,scroll content无法根据其包含的内容自动伸缩。也就是说,scroll content的宽和高需要手动指定,如果其中内容超出了它的范围,那么超出的内容将无法滚屏过去。
这一点实在是把我恶心到爆了,于是出现了诸如以下的代码
- if (Mode == SelectMenuMode.Vertical)
- {
- selectContent.GetComponent<VerticalLayoutGroup>().enabled = true;
- selectContent.GetComponent<GridLayoutGroup>().enabled = false;
- float spacing = selectContent.GetComponent<VerticalLayoutGroup>().spacing;
- //by cg:
- //unity每次需要手动设置scroll content的大小
- float height = spacing;
- foreach (Transform s in selectContent)
- {
- height += s.GetComponent<RectTransform>().rect.height - spacing;
- }
- float width = selectContent.GetComponent<RectTransform>().rect.width;
- selectContent.GetComponent<RectTransform>().sizeDelta = new Vector2(width, height);
- }
- else if (Mode == SelectMenuMode.Grid)
- {
- selectContent.GetComponent<VerticalLayoutGroup>().enabled = false;
- selectContent.GetComponent<GridLayoutGroup>().enabled = true;
- float cellX = selectContent.GetComponent<GridLayoutGroup>().cellSize.x;
- float cellY = selectContent.GetComponent<GridLayoutGroup>().cellSize.y;
- float spacingX = selectContent.GetComponent<GridLayoutGroup>().spacing.x;
- float spacingY = selectContent.GetComponent<GridLayoutGroup>().spacing.y;
- float width = selectContent.GetComponent<RectTransform>().rect.width;
- float height = Mathf.CeilToInt(selectContent.childCount / (width / (cellX + spacingX))) * (cellY + spacingY);
- selectContent.GetComponent<RectTransform>().sizeDelta = new Vector2(width, height);
- }
每次需要手动去设置scroll Content的RectTranform的sizeDelta属性。这样代码很丑陋且极其不灵活。如果对于内容的宽高和排列可以预期,那还好。假如内容是一个文本,那岂不是还要算字体所占宽高、行间距等等……
其次的一个问题是:scroll content的position设置貌似是有BUG。
为了实现大地图滑动滚屏的效果,我将大地图放到一个scroll content中,然后可以由玩家手指滑动来进行拖拽,这个unity实现都没有问题。问题是,我需要由代码实现“滚屏”到某个点,则问题来了——
我手动在unity editor的运行时态设置的scoll content的x,y都是OK的,放到代码里去设置transform.localPosition,就完全错位了。
最后经过反复尝试,代码写成了这样……
- <span style="white-space:pre"> </span>//大地图卷屏
- if(location.name.Equals(RuntimeData.Instance.GetLocation(RuntimeData.Instance.CurrentBigMap)))
- {
- float x = -location.X + 640; //减去半个屏幕宽度,居中
- float y = -location.Y - 320; //减去半个屏幕高度,居中
- if (x < -1140) x = -1140; //边界限制
- if (y > 640) y = 640;
- if (x > 0) x = 0;
- if (y < 0) y = 0;
- //by cg: 这里对齐的逻辑有点奇怪,应该是unity的BUG,没处理好对齐锚点。先手动修正。
- BigMap.transform.localPosition = new Vector3(-570f + x, 320f + y, 0);
- }
原因应该是我将scroll content的Anchor Pivot设置成了(0,1),但unity设置localPosition却没有写参考这个锚点的逻辑,需要手动修正。
还有比较大的一个问题,ScrollRect所在的GameObject的Image组件,alpha设置有个BUG
按道理来说,这个Image只是scrollRect的一个背景,不影响其内容。但在把alpha设置到特别小的时候,不管是在editor上还是在运行环境中,scroll content都将显示不出来。我试了大概是设到4-8以下就会完蛋。。所以我们需要获得一个背景透明的scroll content,还不能把背景设置得太过于透明了……
2、LINQ不能在IOS上使用
在PC、EDITOR、MAC、ANDROID都没有问题的代码,放到IOS真机(IPHONE、IPAD)上出问题。原因搜了一下大概意思应该是苹果不允许出现动态代码。
这个是unity一直的问题了,貌似有办法通过第三方的LINQ实现来保证。总之我是放弃使用LINQ了。
3、unity新版动画系统Mecanim使用中碰到的问题
我的游戏中人物分几种动画,如 站立、移动、攻击。我使用Mecanim的状态机来实现,动画之间使用SetTrigger来实现切换。
我发现一个动画在切换后如果没有播放完毕,再调用SetTrigger的话,有时就会出现动画状态错乱。我的状态机是这样的:
所以我代码里现在是每次需要等待一段时间后,再进行切换。。
4、sprite editor中的BUG
在sprite editor中通过鼠标调整锚点为custom,第一次保存(这时候unity已经自动将类型切换为custom了)会失败!需要保存两次——但是第二次必须又和第一次不是同一个锚点,否则保存按钮点不下去!
或者先手动将锚点类型改为custom,然后再保存才可以。
好了,吐槽了这么多问题,总之unity新版本我还是很支持的。毕竟原生态的GUI系统还是比NGUI等硬往上“套”的UI系统要好很多。对于unity3d使用C#编程语言也是更加好顶赞。我不是一个喜欢讨论哪个编程语言好的人,就我来说,我至少使用过10多种语言编写过代码,目前来说感觉比较酸爽的还是C#。