A Day In The Life

とあるプログラマの備忘録

ゲーム開発をはじめる前に読んでおきたい本

1年半ほど前から本格的にブラウザじゃないゲーム開発(ネイティブゲームって言うんですかね)を始めたのですが、Web の知識が全くと言っていいほど役に立たずほとんど一から勉強するみたいな感じでかなり苦労しました。自分は Cocos2d-x を使って開発していたのですが、機能を追加すればするほどどんどんゲームの動きが遅くなっていく...C++で開発すれば速いんじゃなかったっけ???みたいな状態でした。半年かけてなんとかゲーム開発できるかなぐらいになったものの、自分のやり方が正解だったのか全くわからずこれで良かったのかと悩んでいたときに出会ったのがこの本「Game Programming Patterns」です。

ゲーム開発は言語化されてなかったり、ゲーム開発経験のあるプログラマしか知らないノウハウやパターンがあり、ネットや本では見つからない情報が多いです。この本はそんな現場のノウハウ的なものがぎゅっと1冊にまとめられています。

続きを読む

6年前に開発したObjcのアプリをSwiftで書き直してみた

約6年前に LinkedWord という英英辞書アプリを開発しました。リリースからしばらく(2年ぐらい、時期的には iOS4とか5の時代)は機能アップデートやバグ修正をしていたのですが、本の執筆やら他のアプリの開発やらで忙しくなりしばらく放置してました。その間に iPhoneは5系や6系が発売され画面サイズが増えたり、iOS7で UI が刷新されたり、とわりと大きな変化がありました。本の執筆も落ち着いたし Swift を使ってアプリを1本ちゃんと開発したいと思ったので過去に開発した LinkedWord を作り直してみることにしました。以下やったことをつらつらと上げていきます。
from Objc to Swift

続きを読む

OpenGL ES入門 その2 -三角形の描画とシェーダーの仕組み-

OpenGL ES入門 その1 -描画の仕組みとバッファ-の続きです。今回は OpenGL ES を使って三角形を描画してみます。三角形を描くだけなら簡単そうな気もしますが、三角形を描くにはシェーダーを用意しきゃいけないという少し面倒くさい作業があるのでその辺の説明になります。

続きを読む

OpenGL ES入門 その1 -描画の仕組みとバッファ-

最近 Cocos2d-x を触っているとどうしても細かいところで OpenGL の知識がないと理解できないみたいなことが多いです。いままで避けてきた感がある OpenGL の勉強をそろそろ始めてみようかなと思い少しづつ日記的にまとめていこうと思います。OpenGL と言っても自分はモバイルゲームの開発に興味があるので OpenGL ES について勉強していくことにしました。参考図書として購入した本はこちらです。

わりと新しく出た本ってのと解説がものすごくわかりやすかったので選びました。第1回は OpenGL ES の基本的なところから画面を色で塗りつぶすまで解説します。

続きを読む

オフスクリーンレンダリングを使って画像を動的にアトラス化する

オフスクリーンレンダリングという手法があります。この手法をつかって動的に画像をアトラス化してスプライトフレームキャッシュ(SpriteFrameCache)に乗せることができると、必要最小限の画像をアトラス化して効率よくキャッシュできるのではないかということで試してみました。
まずはオフスクリーンレンダリングとスプライトフレームキャッシュそれぞれの使い方を説明してから、その2つを組み合わせる方法を最後に紹介します。

続きを読む

【Swift1.2対応】プロの力が身につく iPhone/iPadアプリケーション開発の教科書 Swift対応版

iOS が8.3にバージョンアップしたのに伴い Xcode が6.3に Swift が1.2にバージョンアップされました。Swift 1.2ではシンタックスエラーとなりビルドできなくなるコードがあります。本書で記載しているコードだけでなく、サンプルの自動生成コードにも変更が必要な箇所がありましたので修正しました。最新のサンプルコードはすべて Swift 1.2に対応済みです。

以降は、本書に記載されているプログラムの修正箇所になります。

続きを読む

Cocos2d-x でネイティブ連携する方法

Cocos2d-x でゲームを開発していると広告を表示させたり、ランキングを追加したり、課金を入れたり、SNSTwitter と連携したり、アクセス解析をしたり、など iOSAndroid の機能を使わないと実現できない機能があります(このようにプラットフォームと Cocos2d-x を連携させることをネイティブ連携と呼びます)。Cocos2d-x には Plugin-X というネイティブ連携のための仕組みがあるのですが、提供されている機能が少なくまた導入が複雑(特に Android)で導入するメリットがあまりないのが実情です。
どうせなら自前で実装したほうがいろいろと便利だし iOSAndroid の知識も深まるのでこの記事では Cocos2d-x 3.4 Final でネイティブ連携する方法について説明します。ネイティブ連携の仕組みは一度開発してしまえば似たようなコードを書かずに、Objective-CJava を書くだけで機能追加できるようになるので覚えておいて損はないと思います。

ネイティブ連携の仕組み

ネイティブ連携は新規にクラスを作成してヘッダファイルのみ共通にして実装ファイルを iOS 用、Android 用と分けます。iOS の場合は Objective-C++ で実装を書きます。Android の場合は実装部分に JNI の呼び出しコードを書きます。実際の処理はあらかじめ Java 側に用意しておきます。

ネイティブ連携用クラスの作成

それでは連携用の NativeLauncher クラスを作成します。以下のようにヘッダと実装ファイルを作成してください。

  • NativeLauncher.h
  • NativeLauncher.mm(iOS用)
  • NativeLauncher.cpp(Android用)

例えばネイティブ連携をしてハイスコアを登録する機能を作成する場合は以下のようにクラスにメソッドを定義します。

#include "cocos2d.h"

class NativeLauncher {
public:
  // ハイスコアを登録する
  static void postHighScore(int score);
};

Xcode の設定

開発に Xcodeを使っている場合は NativeLauncher.cpp ファイルをコンパイル対象から外す必要があります。
削除手順は Project Navigator からプロジェクトのルートを選択してプロジェクトの詳細画面を表示します。次に「TARGETS」の「プロジェクト名 iOS」を選択して「Compile Sources」から NativeLauncher.cpp を削除してください。
Xcodeの画像

NativeLauncher.mm の実装

iOS の場合は Objective-C++ が使えますのでメソッド中に直接 Objective-C のコードを書いていきます。

#include "NativeLauncher.h"

#import <GameKit/GameKit.h>

void NativeLauncher::postHighScore(int score)
{
  GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
  if([localPlayer isAuthenticated]) {
    // 処理...
  }
}

Java の実装と NativeLauncher.cpp の実装

Android の場合は少し複雑でまず Java で実装を書いてからそのコードを C++ から JNI を経由して呼び出すことになります。Android のネイティブ連携コードは基本的には proj.android にある AppActivity クラスに書きます。
AppActivity クラスの詳細はこちらの記事を参照してください。

package org.cocos2dx.cpp;

import org.cocos2dx.lib.Cocos2dxActivity;

public class AppActivity extends Cocos2dxActivity {
  // 気持ち悪いけど static メソッドから参照するときに必要
  private static AppActivity me = null;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    me = this;
  }
  // JNI から呼び出されるメソッド
  public static void postHighScore(int score) {
    // UIスレッドで実行
    me.runOnUiThread(new Runnable() {
      @Override
      public void run() {
        // 処理...
      }			
    });
  }
}

あとは C++ からJNI で postHighScore メソッドを呼び出します。

#include "NativeLauncher.h"
#include "platform/android/jni/JniHelper.h"
#include <jni.h>

#define CLASS_NAME "org/cocos2dx/cpp/AppActivity"

void NativeLauncher::postHighScore(int score)
{
  JniMethodInfo methodInfo;
  if (!JniHelper::getStaticMethodInfo(methodInfo, CLASS_NAME, "postHighScore", "(I)V")) {
    return;
  }    
  methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID, score);
  methodInfo.env->DeleteLocalRef(methodInfo.classID);
}

Cocos2d-x が JniHelper という便利なクラスを用意してくれているのでそれを使います。JniHelper クラスの getStaticMethodInfo メソッドの第4引数が暗号じみてよくわからないかもしれません。int 型の引数を取り戻り値は void という意味です。