box-、cocos-、pizza- 2d

この記事では、私たちの会社で最初のiOSゲームを作成したストーリーを共有し、2Dグラフィックエンジンcocos2dを使用した経験についてお話したいと思います。 ストーリーでは、ゲームの開発中に直面しなければならなかったいくつかの技術的な問題を検討し、ゲームプレイの最初から最後までの進化について説明します。



画像



午前中、同僚のArseniyとValentinに会い、社内で毎月開催される社内企業ハッカソンのアイデアに取り組みました。 私たちはだれもゲームの真剣な経験をしていませんでしたが、ゲームを開発することはクールだと思いました。



当初、私たちが選んだアイデアは次のとおりでした。プレーヤーの前にはジューシーなケーキがあり、短期間で素早く小さなピースにカットする必要がありました。 ゲームにダイナミズムを与えるために、カットされたピースを何らかの物理エンジンを使用してアニメーション化する必要がありました。 短い検索の後、cocos2dエンジン(IとArsenyはiOS開発者であるため)およびbox2d(無料でcocos2dで正常に動作するため)でゲームを作成することが最も生産的であると判断し、1つのiOSプラットフォームのみに限定しました。



このプロジェクトの中核は、 Allen Tanの優れたチュートリアルで見つかりました。そのため、切断および三角測量アルゴリズムの実装に飛び込む必要はありませんでした。 このチュートリアルは、凸面のテクスチャポリゴンを描画できるPRKitライブラリに基づいていました。 また、便利なクラスPRFilledPolygonがあり、そのサブクラスはポリゴンの物理的表現をその表示にリンクしていました。 このサブクラスを将来のケーキのスライスのベースとして使用することにしました。



最も面倒な部分が私たちのために書かれたという事実に触発され、私たちは安ofのため息をついたが、長くは続かなかった-最初の困難はすぐに現れた。 最初のプロトタイプを立ち上げた後、よく知られているbox2dの制限-形状ごとに頂点が8個以下であることを思い出しました。 チュートリアルと前述のライブラリに基づいて、box2dは円形のセグメント(丸いケーキをカットすることで得られる)の操作方法を知らないため、カットケーキの形状を多角形にする必要がありました。 したがって、box2dの制限とケーキが実際の形状に近いはずであるという事実を考慮して、八角形の配列で構成することを決定しました。 このソリューションは、チュートリアルで1つの図だけで構成されるボディについて話していたように、テクスチャリングに問題を引き起こしました。 この問題は、図の外側の境界のみを形成する頂点の配列をPRFilledPolygonコンストラクターに渡すことで解決しました。 結果:



画像



オリジナルの切断アルゴリズムも、多くの形状で構成されるボディに合うように修正する必要がありました。 短い議論の後、図の頂点の最大数を8から24に増やし(box2d設定で対応するパラメーターを編集して)、1つの図だけで構成されるボディに戻ることを決定しました(プロジェクトによっては、このソリューションは受け入れられませんが、非常に適していました)。 プロファイリングにより、8つのピークと24の速度に重大な違いはないことが示されました。 ただし、画面上のピースの数を200以上に増やした後、FPSは10に急激に低下し、ゲームをプレイすることはほとんど不可能になりました。 プロセッサ時間の約20%が衝突の計算に費やされ、残りはピースとそのアニメーションのレンダリングに費やされました。



決定はすぐに来ました。 ピースが十分に小さくなったらすぐに、そのための衝突計算をオフにしました。 しかし、それでもゲームの速度は望まれていなかったため、ゲームプレイをわずかに変更することにしました。画面から小さなピースを削除して、プレーヤーのプログレスバーに追加する必要があります。 破壊された表面の面積が、レベルの通過の質を決定しました。 ピースに線形/角度の減衰が適用されたため、スクリーンの周りをランダムに飛び回ることができませんでした。



画像



このときまでに、バレンタインはケーキモデルを作成しました。



画像



レンダリングされたケーキは本当に印象的でしたが、このような単純化された切断プロセスには現実的すぎたため、単純なピザの写真に置き換えることにしました。



画像



しかし、単純化されたゲームプレイでは、ピザも調和がとれていないように見えたため、抽象的な幾何学的プリミティブをグラフィックベースとして使用することにしました。 これに必要な再設計は非常に簡単であり、そのアイデアはPRFilledPolygonで使用されている技術に完全に適合するため、すぐに計画を実現しました。 CCDrawNodeを使用して実装した各ピースにストロークが追加され、多角形の頂点の配列とストロークの色をパラメーターとして渡します。 これによりゲームが少し遅くなりましたが、FPSはまだ十分に高かったです。 同時に、得られた形状の輪郭は、従来のccDrawメソッドを使用して描画された輪郭よりもはるかに良く見えました。



画像



ゲームは多かれ少なかれ完全な形を取り始めましたが、ゲームプレイはまだ初期段階にありました。 確かに、競争力のある要素が欠落していました。 この問題を解決するために、単純な敵を追加しました-レベルを正常に完了するために必要なポイントを失うことなくカットできなかった赤い点。 素晴らしいが、より良い。 レーザーの移動はどうですか? できた! 実装は非常に単純で、指のタッチポイントの位置から敵までの距離の計算ミスに基づいていました。



画像



敵とメインのゲームプレイの準備ができました。 その後、私たちはそれぞれがいくつかのレベルに分割された世界のシステムを実装することにしました。 すべてのレベルは、元の図の説明、敵の位置、レベルの持続時間、およびその他のパラメーターを含む個別の.plistファイルに保存されました。 ゲームオブジェクトのツリーは、標準のObjective-C KVCを使用して構築されました。 例:



//...... - (void)setValue:(id)value forKey:(NSString *)key{ if([key isEqualToString:@"position"] && [value isKindOfClass:[NSString class]]){ CGPoint pos = CGPointFromString(value); self.position = pos; } else if([key isEqualToString:@"laserConditions"]){ NSMutableArray *conditions = [NSMutableArray array]; for(NSDictionary *conditionDescription in value){ LaserObstacleCondition *condition = [[[LaserObstacleCondition alloc] init] autorelease]; [condition setValuesForKeysWithDictionary:conditionDescription]; [conditions addObject:condition]; } [super setValue:conditions forKey:key]; } else{ [super setValue:value forKey:key]; } } //...... //Afterawrds the values got set with the dictionary read from the plist file: [self setValuesForKeysWithDictionary: dictionary];
      
      







ワールドとレベルを選択するためのメニューを表示するために、CCMenuといくつかの拡張機能を使用しました。CCMenu+ Layout (グリッド上にメニュー項目を配置できます)およびCCMenuAdvanced (スクロールを追加します)。 Valentinはレベルの設計を開始し、Arsenyと私はエフェクトを実装し始めました。



視覚効果には、ユーザーのタッチをアニメーション化するライブラリCCBladeを使用しました 。 さらに、図の各カットは、スターウォーズのレーザー剣の音のような効果によって表明されました。 追加した別の効果は、小さな破片の消失です。 効果のないカットはかなり退屈に見えたので、透明度を滑らかに変更してスライスを削除し、消えているシェイプに「+」を追加することにしました。



透明度変更部分は、CCLayerRGBAプロトコルをPRFilledPolygonに追加することにより実装されました。 これを行うために、PRFilledPolygonで使用される標準シェーダープログラムをkCCShader_PositionTexture_uColorに変更しました。



 -(id) initWithPoints:(NSArray *)polygonPoints andTexture:(CCTexture2D *)fillTexture usingTriangulator: (id<PRTriangulator>) polygonTriangulator{ if( (self=[super init])) { //Changing the default shader program to kCCShader_PositionTexture_uColor self.shaderProgram = [[CCShaderCache sharedShaderCache] programForKey:kCCShader_PositionTexture_uColor]; } return self; }
      
      







そして彼女に色のユニフォームを手渡しました



 //first we configure the color in the color setter: colors[4] = {_displayedColor.r/255., _displayedColor.b/255., _displayedColor.g/255., _displayedOpacity/255.}; //then we pass this color as a uniform to the shader program, where colorLocation = glGetUniformLocation( _shaderProgram.program, "u_color") -(void) draw { //... [_shaderProgram setUniformLocation:colorLocation with4fv:colors count:1]; //... }
      
      







見た目はきれいでしたが、ストロークと新しい効果により、FPSは特にユーザーが一度に多くのピースを小さなピースにカットした場合、再生不可能なマークになりました。 グーグルでは、解決策が見つからず、削除されたピースの最小面積を単純に増やしました。 これによりFPSが向上しました。 また、消失エフェクトを削除し、CCSpriteBatchNodeにプラスを追加しました(これをすぐに行わなかったのは奇妙です)。



画像



サウンドエフェクトについては、Simpleオーディオエンジンの小さなラッパーを作成しました。 ただし、いくつかの問題がありました。サポートされていない.wavファイル形式に遭遇しましたが、幸いなことに、ファイルをサポートされている8ビットまたは16ビットPCM形式に変換するだけで決定されました。 他のケースでは、エフェクトがまったく再生されないか、スピーカーからパチパチという音が聞こえました。



結局、ゲームにストアを追加して、ユーザーが行方不明の星を購入して新しいレベルまたは世界を開くことができるようにしました。



画像



彼はまた、良い合格レベルで無料で入手したり、ソーシャルネットワークでゲームのプロモーション画像を共有したりすることもできます。



画像



この時点で、開発に割り当てられた時間は終わり、ゲームをAppStoreに送信する時間になりました。 最後に見つかったバグをすばやく修正し、バイナリをアップロードして、最初にレビューを通過することを期待しています。 そして、後で判明したように、彼らは問題なく合格しました。



All Articles