authors are vetted experts in their fields 和 write on topics in which they have demonstrated experience. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.
Alexey Zankevich
验证专家 在工程
16 的经验

Alexey是一名全栈开发人员和架构师. 他有Python的专业知识,并且擅长Java和Objective-C.

专业知识

分享

开发iOS游戏对于个人和开发者来说都是一种丰富的体验 金融 增长. 今年早些时候,我部署了一款基于cocos2d的游戏, 蜜蜂比赛到App Store. 它的玩法很简单:无限奔跑,玩家(在这种情况下), 蜜蜂)收集点数并避开障碍物. 看到 在这里 为了演示.

在本教程中, 我将解释iOS游戏开发背后的过程, 从Cocos2D到发行. 作为参考,这里有一个简短的目录:

精灵和物理对象

Before we get into the gritty details, it’ll be helpful to underst和 the distinction between 精灵 还有实物.

对于出现在无尽奔跑游戏屏幕上的任何给定实体, 该实体的图形表示称为a 雪碧, while the polygonal representation of that entity in the physics engine is referred to as a 物理对象.

所以精灵被绘制在屏幕上, 由其相应的物理对象支持的, 然后由你的物理引擎处理. 这个过程可以在这里可视化, 在屏幕上显示精灵的位置, 它们的物理多边形对应体用绿色标出:

在iOS无限奔跑游戏中,精灵和实体对象是共存的.

默认情况下,物理对象不会连接到它们各自的精灵, 也就是说你是 iOS开发者 可以选择使用哪个物理引擎,以及如何连接精灵和身体. The most common way is to subclass the default 雪碧 和 add a concrete physical body to it.

考虑到这一点……

关于Cocos2D iOS游戏开发的简短教程

Cocos2D-iphone is an open source framework for iOS that uses OpenGL for hardware graphics acceleration 和 supports the 花栗鼠Box2D 物理引擎.

首先,我们为什么需要这样一个框架? 首先,框架执行游戏开发中常用的组件. 例如,Cocos2D可以加载精灵(特别是, 雪碧表 (为什么?),启动或停止物理引擎,并正确处理时间和动画. And it does all this with code that’s been reviewed 和 tested extensively—为什么 devote your own time to re-writing likely-inferior code?

然而,也许最重要的是Cocos2D游戏开发使用图形硬件加速. 没有这样的加速度, any iOS infinite runner game with even a moderate number of 精灵 will run with notably poor performance. 如果我们想做一个更复杂的应用, 然后我们可能会开始在屏幕上看到“子弹时间”效果, i.e.,每个精灵在尝试动画时都要复制多个副本.

最后,Cocos2D优化内存使用,因为它 缓存精灵. Thus, any duplicated 精灵 require minimal additional memory, which is obviously useful for games.

使用Cocos2D和故事板

在我对《欧博体育app下载》所获得的所有赞誉之后,这似乎是不合逻辑的 建议使用故事板. 为什么不直接使用Cocos2D等操作你的对象呢.? 好吧, 说实话, for static windows it is often more convenient to use Xcode’s Interface Builder 和 its Storyboard mechanism.

首先, it allows me to drag 和 position all my graphical elements for my endless runner game with my mouse. 其次,Storyboard API非常非常有用. (是的,我知道 可可建设者).

下面是我的故事板的快速浏览:

要学习如何制作一款无尽的跑步游戏,可以从一个好的故事板开始.

The game’s main view controller just contains a Cocos2D scene with some HUD elements on top:

我们的Cocos2D教程是从视图控制器开始的.

注意白色背景:这是一个Cocos2D场景, 哪个将在运行时加载所有必要的图形元素. 其他视图(动态指示器、蒲公英、按钮等.)都是标准的可可视图,使用Interface Builder添加到屏幕上.

我不会详述细节—如果您感兴趣,可以在GitHub上找到示例.

玩法和(简短)项目描述

(为了提供更多的动力, 我想更详细地描述我的无尽奔跑游戏. 如果您想继续进行技术讨论,可以跳过本节.)

在实时游戏中, 蜜蜂一动不动, 这个领域本身也在飞速发展, bringing with it various dangers (spiders 和 poisonous flowers) 和 perks (d和elions 和 their seeds).

Cocos2D has camera object which was designed to follow the character; in practice, 操纵包含游戏世界的CCLayer就不那么复杂了.

The controls are simple: tapping the screen moves the bee up, 和 another tap moves it down.

世界层本身实际上有两个子层. When the game starts, the first sublayer is populated from 0 to BUF_LEN 和 displayed initially. 第二个子层提前从BUF_LEN填充到2*BUF_LEN. 当蜜蜂到达BUF_LEN时, 第一个子层被清理并立即从2*BUF_LEN重新填充到3*BUF_LEN, 提出了第二个子层. 以这种方式, 我们在图层之间交替, 从不保留过时的对象, 这是避免内存泄漏的重要部分.

我的无限奔跑游戏是由多层世界组成的.

在物理引擎方面,我使用《欧博体育app下载》有两个原因:

  1. 它是用纯Objective-C编写的.
  2. 我之前使用过Box2D,所以我想比较一下两者.

物理引擎实际上只用于碰撞检测. 有时候,有人问我:“你为什么不自己编写碰撞检测程序?”. 在现实中,这并没有多大意义. Physics engines were designed for that very purposes: they can detect collisions between bodies of complicated shapes 和 optimize that process. 例如, 物理引擎 often split the world into cells 和 perform collision checks only for bodies in the same or adjacent cells.

自动化工作. 使用工具. 很酷.

A key component of indie infinite runner game development is to avoid stumbling over small issues. Time is a crucial resource when developing an app, 和 automation can be incredibly time-saving.

But sometimes, automation can also be a compromise between perfectionism 和 meeting your deadline. 从这个意义上说,完美主义可能是《欧博体育app下载》的杀手.

例如, 在我正在开发的另一款iOS游戏中, 我建立了一个框架,使用一个特殊的工具来创建布局 GitHub). 这个框架有它的局限性(例如, 它在场景之间没有很好的过渡), 但是使用它可以让我在十分之一的时间内完成我的场景.

因此,虽然您无法使用特殊的超级工具构建自己的超级框架, 您仍然可以并且应该尽可能地自动化这些小任务.

完美主义可能是《欧博体育app下载》的杀手. 时间是iOS游戏开发的重要资源.

在建造这个无限奔跑者的过程中,自动化再次成为关键. 例如, my artist would send me high resolution graphics through a special Dropbox folder. 为了节省时间, I wrote some scripts to automatically build file sets for the various target resolutions required by the App Store, 添加-hd或@2x以及(上述脚本是基于 ImageMagick).

在额外的工具方面,我发现 TexturePacker to be very useful—it can pack 精灵 into 雪碧表 so that your app will consume less memory 和 load faster, 因为所有的精灵都是从一个文件中读取的. 它还可以导出几乎所有可能的框架格式的纹理. (注意,TexturePacker不是一个免费的工具,但我认为它物有所值. 你也可以看看免费的替代品,比如 鞋盒.)

The main difficulty associated with game physics is to create suitable polygons for each 雪碧. 换句话说, creating a polygonal representation of some obscurely-shaped bee or flower. Don’t even try to do this by h和—always use special applications, of which t在这里 are many. Some are even quite… exotic—like creating vector masks with Inkspace 和 then importing them into to game.

For my own endless runner game development, I created a tool to automate this process, which I call Andengine顶点助手. 顾名思义, 它最初是为Andengine框架设计的, 尽管现在它可以适用于许多格式.

在我们的例子中,我们需要使用plist模式:

%.5f%.5f

接下来,我们创建一个带有对象描述的plist文件:

  
 
 
    jet_ant 
    
        vertices 
        
-0.182620.08277
-0.14786-0.22326
0.20242-0.55282
0.470470.41234
0.038230.41234
         
    


还有一个对象加载器:

- (void) createBodyAtLocation: (CGPoint)位置{
    浮子质量= 1.0;
    body = cpBodyNew(mass, cpMomentForBox(mass, self。.雪碧.contentSize.宽度*自我.雪碧.规模、自我.雪碧.contentSize.*高度自我.雪碧.规模);
    body->p = location; 
    cpSpaceAddBody(空间、身体);
    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 = [花栗鼠Util] polyhapewithvertarray:顶点
        withBody:身体
        宽度:自我.雪碧.contentSize.宽度
        高度:自我.雪碧.contentSize.高度);
    shape->e = 0.7; 
    shape->u = 1.0; 
    shape->collision_type = OBJ_COLLISION_TYPE;
    cpSpaceAddShape(空间、形状); 
}

要测试精灵如何与他们的身体相对应,请参阅 在这里.

好多了,对吧??

总而言之,尽可能自动化. 即使是简单的脚本也可以节省大量的时间. 重要的是,这些时间可以用来编程,而不是点击鼠标. (为了获得更多的动力,这里有一个 令牌XKCD.)

应用内计费

在游戏中收集的气球就像一种应用内货币, 允许用户为蜜蜂购买新皮肤. 然而,这种货币也可以用真钱购买. An important point to note with respect to in-app billing is whether or not you need to perform server-side checks for purchase validity. Since all of the purchasable goods are essentially equal in terms of gameplay (just altering the bee’s appearance), 不需要对购买有效性执行服务器检查. 然而,在许多情况下,您肯定需要这样做.

更多,雷·温德里奇有完美的 应用内计费教程.

多人游戏与游戏中心

在手机游戏中, 社交活动 不只是在Facebook上添加“喜欢”按钮或设置排行榜. 为了让游戏更有趣,我执行了多人游戏版本.

它是如何工作的?? 首先,两名玩家通过iOS 游戏 Center的实时配对连接在一起. 因为玩家实际上是在玩同样的无限奔跑游戏, 这里只需要一组游戏对象. 这意味着一个玩家的实例需要生成对象, 其他的剧本会把它们念出来. 换句话说, 如果两个玩家的设备都在生成游戏对象, 很难让体验同步.

With that in mind, after the connection is established, both players send each other a r和om number. 拥有较高数值的玩家充当“服务器”,创造游戏对象.

你还记得关于世界世代分配的讨论吗? W在这里 we had two sublayers, one from 0 to BUF_LEN 和 the other from BUF_LEN to 2*BUF_LEN? This architecture wasn’t used by accident—it was necessary to provide smooth graphics over delayed networks. When a portion of objects is generated, it gets packed into a plist 和 sent to the other player. 缓冲区足够大,即使有网络延迟,也可以让第二个玩家玩. 两名玩家以半秒为周期发送对方当前位置, 也立即发出它们的上下运动. 为了使体验更平滑,位置和速度每0修正一次.5秒,动画流畅, 所以在实际操作中,其他玩家似乎在逐渐移动或加速.

T在这里 are certainly more considerations to be made with regards to multiplayer endless running gameplay, 但希望这能让你对所涉及的挑战类型有所了解.

改进的空间

游戏永远不会结束. 诚然,我有几个方面需要改进,即:

  1. 控制问题:对于喜欢滑动的玩家来说,轻击通常是一种不直观的动作.
  2. 使用CCMoveBy动作移动世界层. 当世界层的速度是恒定的时候,这是没问题的, 因为CCMoveBy动作是用CCRepeatForever循环的:

    - (void) infiniteMove { 
        id actionBy = [CCMoveBy actionWithDuration: BUFFER_DURATION]位置:ccp(-BUFFER_LENGTH . length), 0)];  id actionCallFunc = [CCCallFunc actionWithTarget:self               selector:@selector(requestFillingNextBuffer)];
        id actionSequence = [CCSequence actions: actionBy, actionCallFunc, nil];
        id repeateForever = [CCRepeatForever actionWithAction:actionSequence];
        (自我.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:self           selector:@selector(requestFillingNextBuffer)];
        id actionSequence = [CCSequence actions: actionBy, restartMove, fillBuffer, nil];   (自我.bufferContainer runAction actionSequence):;
    }
    

    这一改变导致动画在每次动作重启时都不连贯. 我试图解决这个问题,但无济于事. 然而,我的测试者没有注意到这个行为,所以我推迟了修复.

  3. 一方面,一方面, t在这里’s been no need to write my own authorization for multiplayer when using 游戏 Center or running my own game server. On the other h和, it’s made it impossible to create bots, which is something I might like to change.

Conclusion

创造自己的独立无限奔跑游戏是一种很棒的体验. 一旦你到了出版的阶段, 当你把自己的创造物释放到野外时,这是一种美妙的感觉.

审查过程从几天到几周不等. 更多信息,有一个有用的网站 在这里 它使用众包数据来估计当前的审查时间.

另外,我建议使用 AppAnnie 查看App Store中所有应用的各种信息, 注册一些分析服务,比如 Flurry分析 也会有帮助.

如果你对这个游戏感兴趣,一定要去看看 蜜蜂比赛 在商店里.

聘请Toptal这方面的专家.
现在雇佣
Alexey Zankevich

Alexey Zankevich

验证专家 在工程
16 的经验

美国新泽西州哈林顿公园

2012年7月11日成为会员

作者简介

Alexey是一名全栈开发人员和架构师. 他有Python的专业知识,并且擅长Java和Objective-C.

authors are vetted experts in their fields 和 write on topics in which they have demonstrated experience. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.

专业知识

世界级的文章,每周发一次.

订阅意味着同意我们的 隐私政策

世界级的文章,每周发一次.

订阅意味着同意我们的 隐私政策

Toptal开发者

加入总冠军® 社区.

" class="hidden">学术不端网