如何在iOS上构建无限Runner(Cocos2D,自动化等)

本文概述

  • 精灵和物理对象
  • 关于Cocos2D iOS游戏开发的简短教程
  • 将Cocos2D与情节提要一起使用
  • 游戏和(简短)项目说明
  • 自动化作业。使用工具。冷静点。
  • 应用内结算
  • 游戏中心的多人游戏
  • 有待改进
  • 总结
在个人和财务增长方面, 开发iOS游戏可以成为丰富的体验。今年早些时候, 我在App Store中部署了基于Cocos2D的游戏Bee Race。它的玩法很简单:一个无限的跑步者, 玩家(在这种情况下为蜜蜂)收集积分并避开障碍物。看到这里的演示。
在本教程中, 我将解释从Cocos2D到发布的iOS游戏开发背后的过程。供参考, 这是一个简短的目录:
  • 精灵和物理对象
  • Cocos2D简介
  • 将Cocos2D与情节提要一起使用
  • 游戏和(简短)项目说明
  • 自动化作业。使用工具。冷静点。
  • 应用内结算
  • 游戏中心的多人游戏
  • 有待改进
  • 总结
精灵和物理对象 在深入了解具体细节之前, 了解精灵与物理对象之间的区别将非常有帮助。
对于出现在无尽亚军游戏屏幕上的任何给定实体, 该实体的图形表示称为子画面, 而在物理引擎中该实体的多边形表示称为物理对象。
因此, 精灵将在屏幕上绘制, 并带有其相应的物理对象, 然后由你的物理引擎处理。可以在此处可视化该设置, 其中精灵显示在屏幕上, 其物理多边形对应物以绿色勾勒出轮廓:
如何在iOS上构建无限Runner(Cocos2D,自动化等)

文章图片
默认情况下, 物理对象未连接到其各自的Sprite, 这意味着你作为iOS开发人员可以选择要使用的物理引擎以及如何连接Sprite和实体。最常见的方法是将默认精灵归为一类, 并为其添加一个具体的实体。
考虑到这一点…
关于Cocos2D iOS游戏开发的简短教程 Cocos2D-iphone是iOS的开源框架, 该框架使用OpenGL进行硬件图形加速, 并支持Chipmunk和Box2D物理引擎。
首先, 为什么我们需要这样一个框架?好吧, 对于初学者来说, 框架实现了游戏开发中经常使用的组件。例如, Cocos2D可以加载精灵(特别是精灵表(为什么?)), 启动或停止物理引擎以及正确处理时间和动画。而这一切都需要经过广泛审查和测试的代码才能完成?为什么要花自己的时间来重写劣等代码?
但是, 也许最重要的是-Cocos2D游戏开发使用图形硬件加速。如果没有这种加速, 则即使具有中等数量的Sprite的任何iOS无限亚军游戏也将以明显差的性能运行。如果我们尝试制作一个更复杂的应用程序, 那么我们可能会开始在屏幕上看到” 子弹时间” 效果, 即, 每个精灵在尝试进行动画制作时都具有多个副本。
最后, 由于Cocos2D可以缓存精灵, 因此可以优化内存使用。因此, 任何重复的精灵都需要最少的额外内存, 这显然对游戏很有用。
将Cocos2D与情节提要一起使用 在获得我对Cocos2D的赞誉之后, 建议使用Storyboards似乎不合逻辑。为什么不只使用Cocos2D等操作你的对象?好吧, 老实说, 对于静态窗口, 使用Xcode的Interface Builder及其Storyboard机制通常更方便。
首先, 它允许我使用鼠标拖动和放置所有图形元素, 以进行无尽的亚军游戏。其次, Storyboard API非常非常有用。 (是的, 我知道Cocos Builder)。
这是我的情节提要的快速浏览:
如何在iOS上构建无限Runner(Cocos2D,自动化等)

文章图片
游戏的主视图控制器仅包含一个Cocos2D场景, 顶部带有一些HUD元素:
如何在iOS上构建无限Runner(Cocos2D,自动化等)

文章图片
请注意白色背景:这是Cocos2D场景, 它将在运行时加载所有必要的图形元素。其他视图(实时指示器, 蒲公英, 按钮等)都是标准的Cocoa视图, 已使用Interface Builder添加到了屏幕中。
我不会详细介绍它-如果你有兴趣, 可以在GitHub上找到示例。
游戏和(简短)项目说明 (为提供更多动力, 我想更详细地描述我无尽的亚军游戏。如果你要进行技术讨论, 请随时跳过本节。)
在现场游戏中, 蜜蜂是一动不动的, 田地本身实际上在奔波, 带来各种危险(蜘蛛和有毒的花朵)和特权(蒲公英及其种子)。
Cocos2D具有旨在跟随角色的相机对象;实际上, 操作包含游戏世界的CCLayer并不那么复杂。
控件很简单:点击屏幕将蜜蜂向上移动, 另一次点击将蜜蜂向下移动。
世界层本身实际上具有两个子层。游戏开始时, 第一个子层从0填充到BUF_LEN, 并最初显示。预先从BUF_LEN到2 * BUF_LEN填充第二个子层。当蜜蜂到达BUF_LEN时, 清洁第一子层并立即从2 * BUF_LEN填充到3 * BUF_LEN, 然后显示第二个子层。这样, 我们在各层之间交替, 从不保留过时的对象, 这是避免内存泄漏的重要部分。
如何在iOS上构建无限Runner(Cocos2D,自动化等)

文章图片
在物理引擎方面, 我使用花栗鼠有两个原因:
  1. 它是用纯Objective-C编写的。
  2. 我以前使用过Box2D, 所以我想将两者进行比较。
物理引擎实际上仅用于碰撞检测。有时, 我被问到:” 为什么不编写自己的碰撞检测?” 。实际上, 这没有太多意义。物理引擎就是为此目的而设计的:它们可以检测复杂形状的物体之间的碰撞并优化该过程。例如, 物理引擎经常将世界分割成多个单元, 并且仅对相同或相邻单元中的物体执行碰撞检查。
自动化作业。使用工具。冷静点。 独立无限亚军游戏开发的关键组成部分是避免绊倒小问题。在开发应用程序时, 时间是至关重要的资源, 自动化可以节省大量时间。
但是有时候, 自动化也可以是完美主义和完成最后期限之间的折衷方案。从这个意义上讲, 完美主义可以成为愤怒的小鸟的杀手。
例如, 在我当前正在开发的另一个iOS游戏中, 我建立了一个框架来使用特殊工具(在GitHub上可用)创建布局。这个框架有其局限性(例如, 场景之间没有很好的过渡), 但是使用它可以使我在十分之一的时间内制作场景。
因此, 尽管你无法使用特殊的超级工具来构建自己的超框架, 但你仍然可以而且应该尽可能多地自动化这些小任务。
完美主义可以成为愤怒的小鸟的杀手。时间是iOS游戏开发中的重要资源。
鸣叫
在构建此无限流道时, 自动化再次成为关键。例如, 我的艺术家会通过特殊的Dropbox文件夹向我发送高分辨率的图形。为了节省时间, 我编写了一些脚本来自动构建App Store所需的各种目标分辨率的文件集, 同时还添加了-hd或@ 2x(上述脚本基于ImageMagick)。
在其他工具方面, 我发现TexturePacker非常有用-它可以将Sprite打包到Sprite表中, 这样你的应用程序将消耗更少的内存并更快地加载, 因为所有Sprite都可以从一个文件中读取。它也可以几乎所有可能的框架格式导出纹理。 (请注意, TexturePacker不是免费工具, 但我认为这是值得的。你还可以查看ShoeBox等免费替代产品。)
与游戏物理学相关的主要困难是为每个精灵创建合适的多边形。换句话说, 创建一些形状不明显的蜜蜂或花朵的多边形表示。甚至不要尝试手动执行此操作-总是使用特殊的应用程序, 其中有很多。有些甚至非常…充满异国情调, 例如使用Inkspace创建矢量蒙版, 然后将其导入到游戏中。
对于我自己无休止的亚军游戏开发, 我创建了一个工具来自动执行此过程(请参阅此处以了解正确用法), 我将其称为Andengine Vertex Helper。顾名思义, 它最初是为Andengine框架设计的, 尽管如今它可以使用多种格式正常工作。
在我们的例子中, 我们需要使用plist模式:
< real> %.5f< /real> < real> %.5f< /real>

接下来, 我们创建一个带有对象描述的plist文件:
< ?xml version="1.0" encoding="UTF-8"?> < !DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> < plist version="1.0"> < dict> < key> jet_ant< /key> < dict> < key> vertices< /key> < array> < real> -0.18262< /real> < real> 0.08277< /real> < real> -0.14786< /real> < real> -0.22326< /real> < real> 0.20242< /real> < real> -0.55282< /real> < real> 0.47047< /real> < real> 0.41234< /real> < real> 0.03823< /real> < real> 0.41234< /real> < /array> < /dict> < /dict> < /plist>

还有一个对象加载器:
- (void)createBodyAtLocation:(CGPoint)location{ float mass = 1.0; body = cpBodyNew(mass, cpMomentForBox(mass, self.sprite.contentSize.width*self.sprite.scale, self.sprite.contentSize.height*self.sprite.scale)); body-> p = location; cpSpaceAddBody(space, body); NSString *path =[[NSBundle mainBundle] pathForResource:@"obj _descriptions" ofType:@"plist"]; // < - load plist NSDictionary *objConfigs = [[[NSDictionary alloc] initWithContentsOfFile:path] autorelease]; NSArray *vertices = [[objConfigs objectForKey:namePrefix] objectForKey:@"vertices"]; shape = [ChipmunkUtil polyShapeWithVertArray:vertices withBody:body width:self.sprite.contentSize.width height:self.sprite.contentSize.height]; shape-> e = 0.7; shape-> u = 1.0; shape-> collision_type = OBJ_COLLISION_TYPE; cpSpaceAddShape(space, shape); }

要测试精灵与实体的对应关系, 请参见此处。
好多了吧?
总而言之, 在可能的情况下始终要自动化。即使是简单的脚本也可以节省大量时间。重要的是, 该时间可用于编程, 而无需单击鼠标。 (为获得更多动力, 这里是令牌XKCD。)
应用内结算 游戏中收集的吹毛球充当应用内货币, 使用户可以为蜜蜂购买新皮。但是, 也可以用真钱购买该货币。关于应用内结算的重要注意事项是你是否需要对购买有效性进行服务器端检查。由于所有可购买的商品在游戏玩法上基本上是相等的(只是改变蜜蜂的外观), 因此无需执行服务器检查以确认购买的有效性。但是, 在很多情况下, 你肯定需要这样做。
有关更多信息, Ray Wenderlich提供了完善的应用内结算教程。
游戏中心的多人游戏 在移动游戏中, 社交不仅仅是添加Facebook的” 赞” 按钮或设置排行榜。为了使游戏更加精彩, 我实现了多人游戏版本。
它是如何工作的?首先, 使用iOS Game Center的实时比赛对接两个玩家。由于玩家实际上在玩相同的无限亚军游戏, 因此只需要一组游戏对象即可。这意味着一个玩家的实例需要生成对象, 而其他游戏的对象将读取它们。换句话说, 如果两个玩家的设备都在生成游戏对象, 那么同步体验就很难了。
考虑到这一点, 在建立连接后, 两个玩家都会互相发送一个随机数。具有较高编号的玩家充当” 服务器” , 创建游戏对象。
你还记得关于世界分裂的讨论吗?在哪里有两个子层, 一个从0到BUF_LEN, 另一个从BUF_LEN到2 * BUF_LEN?这种架构并不是偶然使用的, 而是必须在延迟的网络上提供平滑的图形。当生成一部分对象时, 它将打包到一个plist中并发送给其他玩家。缓冲区足够大, 即使在网络延迟的情况下, 第二个播放器也可以播放。双方都在半秒内互相发送当前位置, 也立即发送上下动作。为了使体验更加流畅, 位置和速度会通过平滑的动画每0.5秒进行校正, 因此在实践中, 看起来其他玩家正在逐渐移动或加速。
对于多人无尽的连续运行游戏, 当然还有更多考虑因素, 但是希望这可以使你对所涉及的挑战类型有所了解。
有待改进 游戏永远不会结束。诚然, 我想在几个方面进行自我完善:
控制问题:对于喜欢滑动的玩家来说, 轻击通常是一种不直观的手势。
使用CCMoveBy动作移动世界图层。当世界层的速度恒定时, 这很好, 因为CCMoveBy动作是通过CCRepeatForever循环执行的:
-(void) infiniteMove{ id actionBy = [CCMoveBy actionWithDuration: BUFFER_DURATION position: ccp(-BUFFER_LENGTH, 0)]; id actionCallFunc = [CCCallFunc actionWithTarget:selfselector:@selector(requestFillingNextBuffer)]; id actionSequence = [CCSequence actions: actionBy, actionCallFunc, nil]; id repeateForever = [CCRepeatForever actionWithAction:actionSequence]; [self.bufferContainer runAction:repeateForever]; }

但是后来, 我增加了世界速度增加, 以使游戏变得更困难:
-(void) infiniteMoveWithAccel { float duration = BUFFER_DURATION-BUFFER_ACCEL*self.lastBufferNumber; duration = max(duration, MIN_BUFFER_DURATION); id actionBy = [CCMoveBy actionWithDuration: duration position: ccp(-BUFFER_LENGTH, 0)]; id restartMove = [CCCallFunc actionWithTarget:self selector:@selector(infiniteMoveWithAccel)]; id fillBuffer = [CCCallFunc actionWithTarget:selfselector:@selector(requestFillingNextBuffer)]; id actionSequence = [CCSequence actions: actionBy, restartMove, fillBuffer, nil]; [self.bufferContainer runAction:actionSequence]; }

此更改导致动画在每次重新启动动作时都会破碎。我试图解决此问题, 但无济于事。但是, 我的Beta测试人员没有注意到该行为, 因此我推迟了此修复程序。
一方面, 在使用Game Center或运行自己的游戏服务器时, 无需为多人游戏编写我自己的授权。另一方面, 它使创建机器人变得不可能, 这是我想更改的事情。
总结 创建自己的独立无限跑步游戏可能会是很棒的体验。一旦进入流程的发布步骤, 当你将自己的创作发布到野外时, 就会有一种美妙的感觉。
审核过程可能从几天到几周不等。有关更多信息, 这里有一个有用的网站, 该网站使用众包数据估算当前的评论时间。
此外, 我建议使用AppAnnie来检查有关App Store中所有应用程序的各种信息, 并且向Flurry Analytics等某些分析服务进行注册也可能会有所帮助。
【如何在iOS上构建无限Runner(Cocos2D,自动化等)】如果这个游戏吸引了你, 请务必在商店中查看Bee Race。

    推荐阅读