从零开始做游戏(六)写个抛硬币游戏

之前的项目暂时中断下,因为UP发现再写下去就越来越不是从零了,所以UP考虑来个更容易入门的项目,
起因是这样的,UP今天偶然的一个这样那样的需求总之就是突然说到来抛个硬币试试,正面就这样,背面就那样,然后现在都是扫码支付时代嘛,找个硬币都够折腾的,于是UP找了许多抛硬币app,不是弹窗广告就是弹网页广告,用户体验极差,感觉很不愉快,不过也是都为了挣钱嘛也能理解。
于是UP决定自己动手写一个非常干净的简单的抛硬币游戏,就把这种简单的东西分享给大家吧,或许以后有人会感谢我的,对吧。
那么我们就开始动手吧,打开我的Unity,什么居然还是用unity写,是的UP就对Unity熟悉,所以就不要折腾其他开发工具了!
主界面与素材
首先建立项目,为项目起名,创建一个2D的项目,这些都挺简单的就不再描述了,如果想了解UP可是写过这些文章的哦。
然后我们需要个素材,简单的画个线框图硬币吧,打开PS,可能你会想,搜索个图片作为素材不就可以了么,不过这样你有考虑过版权么,UP可是一直都在强调版权的,所以我们仿着1元硬币画了个,也不一样是吧,只是那个1字特别像,虽然有点丑不过是那个意思吧。

然后导出图片成PNG格式,不过这里需要注意下图片正反面的大小一定要保持一致哦。
PS的相关技术各位可以请教下PS大佬,UP根本就是画图废人,所以就不教学这方面了

总之最后我们得到了2张素材

打开UNITY,将图片拖到场景里

这个工程中,我们修改了背景颜色,至于怎么修改,仔细看上图,有什么地方显示出了蓝色的字体呢,对啦,就是调节那个修改的,自己找找吧。
为什么我想让背景颜色深一点呢,是因为考虑到不要那么瞎眼。
使用Unity代码来写按钮
如果你是UP的忠实观众,那么你应该记得UP曾教学过UGUI这个Unity里自带的可视化UI系统,当然如果不是的话也不必去查找那一期啦,不如从现在开始成为UP的忠实观众好不好呀。(这个不要脸的UP)
其实在Unity中,UGUI出现以前,还有一个官方的GUI代码模块,具体是什么参见下面的代码。
void OnGUI()
{
//这个意思就是这里面的内容会被认为是GUI模块
}
在unity中用void声明的有许多内容,比如Start,Update等等,UP在曾经的教学中也有提到过,所以大家可以回去翻....是的,谁想翻啊,所以UP只能再来一遍并补充一点。
首先需要明白的是,写Unity的代码时,要写在声明(就是void的那个大括号里面)
void Awake ():在游戏开始前就调用一次
void Start():在Awake后调用一次
void Update():在Start后调用,而且是无限循环的调用
void OnGUI():在Update后调用,在这里可以写入GUI代码,无限循环的调用
其实Unity里还有许多这样的声明,这里仅简单的说了常用的4种,一定要记得运行的先后顺序,因为未来很多报错的可能性都是先后顺序搞反了造成的,所以大家记住顺序了吗,没有?没关系,接着往下看,用多了就记住了,不必背诵,背了也没用。
我们来用代码写个按钮,可能你不太明白具体的意思,复制粘贴就好,不必深入理解。

写好后拖代码

然后运行(记得先保存一下,记得随时存档啊存档啊,如果你发现你的场景名字后面有个*,就像上图一样就是你没有存档,如果突然停电了系统崩溃了等等等情况发生你会崩溃的)

你会发现屏幕里多了个按钮,以及点击按钮后,控制台会给你一句这样的提示,这代码这个按钮是有用的
对按钮进行改造
我们成功的将按钮功能实现了,但是有些问题,比如按钮的位置好像很奇怪啊,所以我们改一下。
GUI.Button(new Rect(10, 10, 50, 50)
上面这段代码有4个数字看到了吗,其中10,10代表在屏幕的坐标X=10 Y= 10.
后两位数字50 50代表的是长X宽
所以我们要把它放在屏幕下面居中,需要什么位置呢,算一下坐标????
你会发现,不同的分辨率下按钮的位置都不一样,所以这时候我们需要一个相对固定坐标的算法。
这里有个新知识:Screen.width获取屏幕宽度,Screen.height获取屏幕高度,所以UP想怎样呢。
这里教学一个可能专业课里也学不到的算法:
通过屏幕宽绝对居中按钮:屏幕宽度分辨率/2 - 按钮长度/2
而高度,我们只希望他比屏幕最低的地方往上数10分辨率为间隙,所以直接用Screen.height - 50,为什么是50,因为我们的按钮高度是40,想一想有明白吗。

这个算法怎么来的,常年的经验,不断的摸索,有时候也可以由老司机程序员传授给你,其实并不需要你是数学家,只需要你经验丰富。

实际上按钮的大小也可以根据分辨率修改,不过UP认为这个项目没必要做那么复杂,所以就没有做这个功能了,不然就会开发时间增加增加再增加,开发项目的时候,多多思考下效率的问题,即用最少的时间将项目上线。
当然,按钮的皮肤也可以修改,不过在一个项目根本就不知道有多少人用的情况下,这些就暂时不改了,如果发现莫名的使用的人还很多,UP就会去继续增加新功能,好像UP把这么多年总结的产品制作经验也顺带告知大家了。
实现后端功能
抛硬币的功能是怎么实现的,其实是这样的:
首先硬币的正反实际上是在后端用随机2个数字来展示的,0是背面,1是正面,而硬币的图像其实是随着结果(0或1数字)所显示的部分,其中数字0、1叫后端,图片显示叫前端。
(顺带一说,实际上现在网上的抽奖都是这样的,在你点击的那么一瞬间,后端就给出了所代表奖品的数字,而那个表盘转啊转只是给你看的假象而已,只是它们的后端是在服务器里,如果不在服务器你就可以用修改器作弊了)
这个随机数生成的代码非常的简单,不过需要注意的是,大家看注释里写的是0-1这2个随机数,而我所填写的是0,2,如果这里写0,1,你永远只能抽到0了。
Random.Range(0,2)就是生成随机数0-1,如果想生成0-2需要写成什么呢:
Random.Range(0,3);
而print(目的是为了让其结果打印在控制台里,让我可以测试并看见)


前端的表现
实际上到刚才那里功能已经实现一大半了,接下来要做的就是用图像显示真反面,实现原理是这样:
通过随机数0或1生成图片,如果0生成背面,1生成正面。
首先我们需要想个办法让程序把图片记住,这个办法UP已经帮你想好了

关于命名类型实际上有许多知识,比如INT,String,Float等等,其实各位大可不必在此时了解,也不必背诵。
这里使用的GameObject就是可以存储游戏组件的类型,总之用来存素材是没问题啦。
为什么需要存素材,你暂时别想这个问题,看到UP把功能写好了后,你返回来看肯定能懂。
接下来UP把图片1,2都导入到了Unity场景中,并把它们移到了屏幕外面,这样的作用就是你看不见它了。

为了安全起见,UP把它们的坐标设置成了9999,我相信这么远的距离你用4K显示器全屏也不会露馅,然后当随机数为0的时候,我们就把图片一的坐标改成X=0 Y=0就可以了。
其实要实现出现硬币的方法有许多,如果要老老实实的写,还要写成加载图片之类的,这里UP选择了一种最懒的办法,总之用户只管用起来有没有问题,没谁管你是怎么实现的,他又不知道你是把硬币隐藏到屏幕外面了对吧。
然后我们把1和2拖入到设定的GameObject里。

这里就需要注意了,public GameObject前面的public 一定要写,否则你会找不到该拖哪,不信你照着UP的做法试验下。
接下来,我写了个代码:int i;
这个的意思是,我要用一个字母i来存储数据,为什么是i,其实你用a,b,c,d都可以,只是很多程序员都习惯用i来存储数据,大概是用爱来存储数据吧,UP初学程序的时候就发现他们都这样,于是UP也就这样了,一种习惯,如果有大佬知道原因还请告之。

至于为什么要用个i来存数据,因为不存的话你就无法用if代码来判断,看下面的代码。

上面的代码看懂了吗?
首先你需要明白一个知识,if(如果),可以说写程序100%会用到的功能
if (i == 0) 意思就是如果 i = 0,不过这里一定要记住,在程序里“等于”,要2个等号==,写一个会报错,总之记住在if里判断i是否等于0要用 == 。
上图代码里,有一段叫做: i = Random.Range(0, 2),在程序里一个等号=叫做赋值;
这里的意思就是把0-1的随机数结果赋值给i,所以用了一个等号=。
经历了这个赋值的操作后,i就变成0或者1了(这个要根据随机数随机赋予),所以下面if(i == 0)就是判断i现在等于不等于0啊。
如果等于,执行下面一行内容,如果不等于,在看看else里面的内容。
在else里,UP又写了一段if (i == 1),在i不等于0的时候再判断下i是不是等于1啊。
实际上else后面可以不用再加if (i == 1)的,因为随机数结果只有0或者1嘛,按理说else里的内容就是前面的if (i == 0) 不满足,就强行执行else后面的东西了。
在学校里,老师肯定不会讲到这个,如果代码写的专业点的话,一定要在else后面写上if (i == 1),因为你不知道程序会不会出BUG,多写一点避免BUG。
以上对于初学程序的你来说会复杂么,或者会不会没有讲的很清楚,UP也不得而知,不过UP自己能看懂就是了。
UP好好总结以及补充上面的教学:
=等号是赋值,== 双等号才叫等于
if(条件) .A. else .B. 是写代码100%会用到的一种方法,意思是 如果满足if(括号里的条件),执行A,否则执行B。
当然也可以if(条件A) .C. else if(条件B) .D,意思是如果条件A满足执行C,不满足再看看条件B满足吗,满足执行D,还不满足,这段代码不执行。
条件A可以为1行或者多行代码,1行就写在if代码的下一行,多行需要添加{大括号把多行代码括起来,
大括号中间可以回车,分号加在大括号中间;}
而代码中id1.transform.position = new Vector2(0, 0);的意思就是让id1的坐标变成X=0 Y=0,为什么要这样写,不必思考,反正你知道这样写可以实现这个功能就OK了,你把它复制过来就可以。

接下来开始测试与排除BUG,其实肯定有许多问题和优化的
首先我们运行下程序,发现原本我们把代码调整到屏幕外面去了,程序一运行正面的图片就自动进入了屏幕中间(这里就不用图展示了,相信你能懂)
实际上问题发生的原因是,程序一开始i就自动赋予的0这个值,所以我们做一些修改。
int i = -1; 我们将程序顶部的i初始赋予了-1的值,这样运行程序的时候屏幕中间什么也没有。

我们点击抛硬币按钮,会发现某个硬币在屏幕里显示了(实际上大家都知道只是修改了那个图片的坐标,把坐标改成0了而已)

接下来我们多点了几下,发现结果和上图一样,出现硬币永远都是最初出现的第一枚。
那是因为程序功能还没有写完,出现了BUG,这时候就需要找问题修改问题了,这种模式叫做DEBUG,排除BUG,好的程序员,找到BUG和排除BUG的效率绝对高。

修改了下代码,UP没有在代码里写任何注释,你试试可以读懂每一句是什么意思吗。
如果能读懂,哦恭喜你程序入门了!
你那知道之前的BUG造成的原因是什么吗,是因为UP只写了让硬币坐标变成0,忽略了再把不用的硬币扔出屏幕外的代码,所以造成图片重叠了(这个你都发现了,看来你很有写代码的天赋)
好了,这个程序写完了!

*下面内容有难度, 不建议初学者学习,否则你会懵逼甚至从开始到放弃,所以下面这段内容类似于游戏中的hard模式关卡,只要求部分有能力的玩家玩通,普通玩家看不懂也没什么问题。
这个功能就写完了,但是UP觉得有一个小问题会非常影响用户体验,即是如果连续点击“抛硬币”按钮,连续出现同一个面,你还以为按钮死机了,所以我们需要优化一下这个问题,这个不是BUG,是用户体验问题,在初次成型的项目里,这种严重影响用户体验的地方还是需要修改一下的。
我们可以用程序做一段小动画:

这段动画是通过改变图像的x轴大小来实现的,每次点击后,程序会按照0.01秒计算一次的方式将x从-2变化到2,所以UP也不再多解释这一段了,确实是初学程序时搞不定的地方。
后来UP发现了个问题,抛硬币按钮在高分辨率手机上太小,所以我们改了下按钮的大小代码,改成这样了,你能看懂意思吗,如果可以,恭喜你有天赋,加油学!
GUI.Button(new Rect(Screen.width / 2 - (Screen.width - 10) /2, Screen.height - (Screen.height * 0.15f + 10), Screen.width - 10, Screen.height * 0.15f)
后记
好了,通过一篇文章介绍了一个非常简单的游戏是如何完成的,虽然这个“游戏”某方面来说只是个工具,不过却可以通过这个简单的项目教会大家如何制作完整的项目。
unity做游戏有个最大的缺点是,打包出来的安卓比较大,这个游戏居然20多M,UP还以为500K就搞定了呢,如果大家想看一看这个项目可以访问pan.baidu.com/s/1dw1HVK下载安卓版,所以B站什么时候推出网络硬盘呢。
写完这篇文章的时候已经半夜1点多了...