最近开始研究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的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#。