疯狂吃豆人

下面是这篇博客的内容,其实挺简单的,有兴趣的继续看往下看吧。

预览

什么鬼

最近没什么事干,想做点什么,又没有好的想法,其实是做不出来啦。在开始这个吃豆人之前,我想扯扯淡,来点前戏,这段 纯属吐槽 ,所以 想要直奔主题的同学可以跳过这一段

说来也是尴尬,学 iOS 整整一年了,基础知识学了不少,就是不知道怎么提高了。之前打算暑假出去找个实习,感受一下真实的开发流程。可是计划赶不上变化,我在学校的一个创业团队做iOS开发,我们在暑假要做一个项目,所以实习的事儿就泡汤了。可能有人会说在学校的创业团队也可以感受到真实的开发流程呀,可是坑爹的是学校搞 iOS 的我就没见过其他人,整个团队就我一个做 iOS 客户端的,Android 项目组七八个人。我之前在学校的贴吧发帖子问有没有学 iOS 的,大家一起学习。妈蛋,没一个回复的。

之前学校要做教务系统客户端,在大二大三当中招人,算是实习,还给报酬,但是都直接不要 iOS 的。我当时自己找过去跟他说我想来做 iOS 端的,不要报酬,他还一脸不愿意的答应了,说就算我做出来了,以后也不好找人维护。我算是加进去了,整个项目还不算很难,但是做了一半我才想起来我没有开发者帐号,没有信用卡注册不了,不用想学校也没有,然后跟他一说,他就开心地把我踢出群了,做了一半的项目也就不了了之了。

还有一次就比较近了,这个项目是我们接的一个外包项目。我们的头给他们谈的,当时双方都没有谈价钱,觉得我们是学生,先做个大概看看效果,我们的头也觉得没问题,把东西做好了,价钱自然好谈。然后就他妈坑爹了,他们要求在他们那里办公,这样好交流。我们只管做客户端,他们自己做后台。然后每天流转与他们办公室和教室之间,他们的产品经理一直给我们讲架构,虽然很烦,不过挺有收获的,呵呵。然后持续了半个月,这个时候我们的头觉得可以和他们谈价钱了。对方觉得我们是学生,便宜。我们的头觉得我们是商业团队,专业。于是,崩了。我当时的心情是逼了狗的!

现在我们要做自己的产品,希望这次不要再夭折了。我只想安静地敲几行代码而已。好吧,暑假太无聊,没人说话,我只能把它们写出来了。不过看到这里的也是够无聊的了。下面开始进入主题。

吃豆人

好吧,这个吃豆人确实太单一了,没啥值得说的,我都不好意思继续写了。大家就当我无聊随便写的,不要当真哦。代码在这里,大家顺便给点Star吧😭

分析

这个吃豆人就两个重点,一个是主体的张嘴闭嘴,一个是豆子的移动。

张嘴闭嘴部分

  • 一看就会发现主体是一个扇形,这里可以用 UIBeizerPath + CAShapeLayer 的方法。

  • 因为这个扇形在变化,所以在 ViewdrawRect 方法中设置 Path,并使用 CADisplayLink 触发此方法。

  • UIBeizerPath 有一个画扇形的方法:

    func addArcWithCenter(center: CGPoint, 
                          radius: CGFloat, 
                      startAngle: CGFloat, 
                        endAngle: CGFloat, 
                       clockwise: Bool)
    

这个方法传入4个参数:圆心、半径、开始角度、结束角度、是否顺时针。再看下面的分析图,吃豆人的主体是上下对称的扇形,嘴巴最大为 90° ,所以开始角度和结束角度都是介于 0° ~ 45° ,而且角度变化是 从 0° 到 45°, 然后再从 45° 到 0° 。所以重点是需要一个可以来回变化的参数!仔细想想!

angle.png
  • 想到了吗?这个参数可以用 三角函数 实现。我们需要一个全局变量作为自变量 x ,每次 drawRect 的时候累加。

    startAngle = abs(cos(x)) * M_PI_4
    endAngle   = -abs(cos(x)) * M_PI_4
    
    • 为什么使用 绝对值abs() ?

      因为 cos 函数的值是介于 -1 到 1 的,我们需要的是 0 到 1,所以取绝对值就可以解决。

    • 为什么使用 cos() 而不是 sin()?

      因为使用 sin 时,一开始当 x = 0 的时候,sin(0) = 0。这个扇形从 0° 到 0°,UIBeizerPath 的那个画扇形的函数就会什么都不做,所以得不到扇形。

    • 经过实验,这个 x 每次累加 0.1 比较合适,大家可以自己试试。

豆子的移动部分

豆子的移动部分虽然很简单,但也有几点需要注意:

  • 初始需要都多少个豆子?

    最好的算法是,用 吃豆人主体右边缘父视图的右边缘 的距离 除以 吃豆人主体的半径。所以每个豆子的间距就是 吃豆人的半径

  • 豆子什么时候删除?豆子的移动速度是多少?

    看下图,豆子在第二张图中被删除,这是吃豆人第一次闭嘴。当吃豆人嘴巴完全张开时,第二个豆子到达初始化的位置,完成了一次循环。

    豆子移动过程

    再看下一张图,看一下解题思路:

    • 因为:吃豆人在完成 张嘴 -> 闭嘴 -> 张嘴 一个循环时,需要 x 从 0 到 π

    • 所以:也就是说豆子移动一个间距时,x 从 0 到 π 。

    • 因为:执行 drawRect 时,x 累加 0.1 。

    • 所以:所以 x 从 0 到 π 需要执行 drawRect (π / 0.1) 次。

    • 所以:豆子移动一个间距时,需要执行 drawRect (π / 0.1) 次。

    • 所以:每次执行 drawRect,豆子需要移动的距离是 (一个间距 / (π / 0.1))

cos函数
  • 什么时候添加新的豆子?

    当最后一个豆子出现在父视图内时,需要添加一个新的豆子,位置是 最后一个豆子右边 一个间距。

总结

到此,这个吃豆人所有的重点都讲完了,代码很简单,主要是思路问题。思路有了,代码就是小事儿,所以讲解的时候没有贴代码。我感觉说的有点麻烦,可能还有病句,希望我没有让大家变得更糊涂。代码在这里,大家顺便给点Star吧😭

推荐阅读更多精彩内容