どこでも動くゲームを作るための   ベタープラクティス       西山信行      5mingame2
C++初心者で~ゲームを作るのが大好き☆プログラマ続きはWebで (「でらうま」で検索)
「こないだサターンでゲーム作ったんだけどさ…」「オレ持ってんのプレステなんだよね」
ハイドライド(1984)        テグザー(1985)PC-8801             PC-8001mkIISRX1/turbo            PC-8801FM7/77/77AV         X1MZ-2000/22...
Unity! WebGL! etc,etc…
Unity! WebGL! etc,etc…今はやりの技術を使えばボクにも実現可能!どうやら結論が出たようですね…
違います!
違います!そういう正攻法じゃ満足できないんです…今日集まってくれたみなさんも、もうちょっとマゾいと信じています
OpenGL + OpenAL + C++
OpenGL + OpenAL + C++• OpenGLは今やもっとも幅広く使える描画実装    Windows/OSX/iOS/Linux/Android/ゲーム専用機…•   OpenALもそれに近い    Windows/OSX/iOS...
OpenGL + OpenAL + C++• そして…OpenGLはMESAというソースの公開さ  れた実装が存在する
予告内容• 用意するもの~• 実装のコツ~• ハマった点時間があれば…• デバッグ手法• 最適化
じゃあ始めましょうか!• Windows  VisualStudio2010• OSX/iOS  Xcode最新版• Linux  ターミナルどの環境でもC++の標準ライブラリが使えます
じゃあ始めましょうか!あと、こんだけ準備して。•   glut•   OpenAL•   zlib•   libpng•   Freetype•   FTGL•   FTGLES•   picojson
じゃあ始めましょうか!•   Xcodeではデバッグビルド設定の「プリプロセッ    サ」に「_DEBUG」を追加しておく    #ifdef _DEBUG    /* デバッグ時の実装 */    #endif•   iOSでのビルド設定「C...
コード書くよ。•   ソースの文字コードはUTF-8 BOMあり•   しかもVS2010では    printf(“ほげほげ”); がcp932に勝手に変換され    る(怒) ので #pragma    execution_characte...
今回決めたたったひとつのルール• ゲーム本体を.cppに書  かないで全てヘッダフ  ァイルに書く• 僕はコード編集は専ら  emacsなので問題な  いです• ファイルを追加しても  プロジェクトを触らな  くてイイ!
こんな感じになってます#include “app.hpp“    // 芋づる式に18000行程度読み込まれるApp *app;int main(int argc, char **argv){  glutInit(&argc, argv);  ...
表示のコールバックvoid displayCallback(){  glClear(GL_COLOR_BUFFER_BIT);    app->update();    glutSwapBuffers();}
入力のコールバックvoid mouseCallBack(const int button, const int state, constint x, const int y){  app->mouse.input(/* 引数いろいろ */);}...
それがiOSだと?#include "app.hpp"App *app;- (void)awakeFromNib{  /* いろいろ初期化 */  app = new App(/*引数いろいろ */);}ちなみにソースのファイル名をViewCo...
- (void)drawFrame{  [(EAGLView *)self.view setFramebuffer];    glClear(GL_COLOR_BUFFER_BIT);    app->update();    [(EAGLVi...
タッチ入力はこうします- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent*)event{  app->mouse.input(/* 引数いろいろ */);}
OpenGL → OpenGL ES 1.1#if (TARGET_OS_IPHONE)typedef GLfloat GLdouble;#define glFrustum(left, right, bottom, top, znear, zf...
OpenGL → OpenGL ES 1.1さすがに gluUnProject() とか gluProject()とか… glu系は実装されてない…MESAの出番!ソースが公開されているのでそれを見ながら自分で実装
いったんまとめ• 文字コード問題はだいたい収束• ゲーム本体を1つのクラスと見立て、その内  部をだいたいどんなコンパイラでも通るよう  にお上品に書く。• そのクラスを操作する箇所で入力とかセーブ  とか画面の回転とか…環境依存な処理を行え ...
バラバラな解像度をひとつにまとめる
バラバラな解像度をひとつにまとめる• Windows/OSX/Linuxでは、「縦横非固定モー  ド」を実装• 初期サイズを960x640と決め、それより狭  かった場合には起動時に調整するみたいな。
バラバラな解像度をひとつにまとめる• iOSは320x480~1536x2048と、多種多様な解  像度が存在するので「見た目固定モード」を  実装
バラバラな解像度をひとつにまとめる• カメラは2つ用意3DglMatrixMode(GL_PROJECTION);glLoadIdentity();glFrustum(width, -width, -height, height, nearZ,...
バラバラな解像度をひとつにまとめる• iPhone3GSは2Dのスケーリングを調整して見  た目をiPhone4とあわせる• 新しいiPadも同じように調整すれば対応でき  るwidth *= 0.5;height *= 0.5;glOrtho...
結局UIViewiOSの画面回転でメニューの表示が崩れるのは、UIViewみたく「画面端基準」を自力で実装して切り抜けた
そろそろ音周りも聞きたい!
そろそろ音周りも聞きたい!• OpenALのサンプル通りに書いたら問題ないで  す• 自分はwav形式のデータを自力で読み込み、  OpenALに渡してます• ストリーミング関連よくわかんない
可搬性≒テキストファイル
可搬性≒テキストファイル• GEOSPOTのセーブデータはすべての動作環境  で互換性がある• バイナリデータだと、とにかく環境依存に  なってしまう。たとえばlong型。OSXのx64は  8バイト。それ以外だと4バイト。• 人間が読み書きで...
可搬性≒テキストファイル• XML…ちょっと自分には読み書きできない• JSON…素晴らしい!
可搬性≒テキストファイルリプレイデータもプレイ内容をテキストで書き出しているだけ-21.16 13334666110.017 0.156676 -0.807913 -0.247557 0.511317 1955.81 0 0 0 00.0503...
ファイルはどこから読み込むの?
ファイルはどこから読み込むの?Windows/Linuxの場合実行ファイルがある場所がカレントstd::string path = “”;read(path + “devdata/hoge.png”);
ファイルはどこから読み込むの?OSXの場合起動時に場所を取得CFBundleRef mainBundle = CFBundleGetMainBundle();CFURLRef resourcesURL =CFBundleCopyResource...
ファイルはどこから読み込むの?iOSの場合起動時に場所を取得std::string path = [[[NSBundle mainBundle] resourcePath]UTF8String] + std::string("/");read(...
ファイルに関してのまとめ• プログラムの開始時、OS別に読み込み時のパ  スと書き出し時のパスを取得しておく• iOSも、C++の標準ライブラリ関数を使った  ファイルの読み書きができる  fstream >> value;  こういうファイル...
まさかの:乱数でハマった
まさかの:乱数でハマったGEOSPOTではクイズの出題順序をランダムにシャッフルしているのだが…デモプレイが環境によって違う!どうも、Widnowsとその他でrand()の実装が違うっぽい?
まさかの:乱数でハマったこれは std::tr1::random を使う事で解決!ただし…初期化時の引数はこうしとくunsigned long seed = time(0) & 0x7fffffff;OSXのx64はlongが8バイト、その他は...
タイマー処理60FPSで動かない場合でも、ゲーム内の時間経過を正確に行うためにタイマーを使って時間を計測してますWindows•   timeGetTime() ←精度が悪い(T T)それ以外• gettimeofday() ←最高!
ここまでのまとめ• ファイルパスや型のサイズなど、実行環境の  違いを吸収する必要のあるもの、必要ないも  のを切り分けておけば怖くない!• 週一くらいの間隔でよいので他の環境でもビ  ルドが通るかの確認は怠らない。
もしかして:時間切れ?デバッグ手法と最適化に関してはまた次の機会にでも~
いまその瞬間のCPU
いまその瞬間のCPU• VisualStudioもXcodeもデバッガが非常によ  くできているので困る事はない。• でもやっぱりプログラムからコンソールに文  字を出力するのは手軽で便利
いまその瞬間のCPUC++だとこう書きますcout << “ほげほげ” << endl;
いまその瞬間のCPUだがしかしWindowsでは出力されないのであった…!class DbgStreambuf : public std::streambuf {   std::vector<char> str_;public:   int_t...
いまその瞬間のCPUだがしかしWindowsでは出力されないのであった…!Class Os {   DbgStreambuf dbgStream_;   std::streambuf *stream_;public:   Os() {     ...
いまその瞬間のCPUだがしかしWindowsでは出力されないのであった…!int main() {  Os os;    cout << “ほげほげ” << endl;    return 0;}
いまその瞬間のCPUリリースビルドでcoutを一網打尽#ifdef _DEBUGDOUT std::cout#elseDOUT 0 && std::cout#endifDOUT << “ほげぴよ” << endl;
最適化は機械任せ☆
最適化は機械任せ☆XcodeのInstrumentsやOpenGL ES PerformanceDevectiveで計測すれば処理負荷の大きい場所が特定できる。
最適化は機械任せ☆GEOSPOTではCPUのコードは3GSでも120FPS超えてるので、まったく最適化作業を行ってないてへぺろ。OpenGL ESは分析結果に「VBOとPVRTCテクスチャを使えばいいよ」と出たのでそうしたら、だいたい60FPS...
終わりですこの場を与えてくださった岸川さんを始めお手伝いの方々、今日ここに来てくださった皆さん、聞いてくださったすべての人たちに感謝!
Upcoming SlideShare
Loading in …5
×

どこでも動くゲームを作るためのベタープラクティス

11,852 views

Published on

先日iphone_dev_jp 東京iPhone/Mac勉強会で発表してきた時の資料です。
Win/OSX/iOSで動かすために、色々揃っているライブラリをすべて無視してC++の標準ライブラリ+αでアプリを作る『マゾプログラミング的制作手法』についてうんたらかんたら。

0 Comments
11 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
11,852
On SlideShare
0
From Embeds
0
Number of Embeds
6,226
Actions
Shares
0
Downloads
25
Comments
0
Likes
11
Embeds 0
No embeds

No notes for slide

どこでも動くゲームを作るためのベタープラクティス

  1. 1. どこでも動くゲームを作るための ベタープラクティス 西山信行 5mingame2
  2. 2. C++初心者で~ゲームを作るのが大好き☆プログラマ続きはWebで (「でらうま」で検索)
  3. 3. 「こないだサターンでゲーム作ったんだけどさ…」「オレ持ってんのプレステなんだよね」
  4. 4. ハイドライド(1984) テグザー(1985)PC-8801 PC-8001mkIISRX1/turbo PC-8801FM7/77/77AV X1MZ-2000/2200/2500 FM-7/77/77AVMSX MSX2 ファミリーコンピュータPC-6001MkII MZ-2500PC-9801U/F PC-9801ファミリーコンピュータ MSX PC/AT(PC-DOS) AppleIIGS Macintosh
  5. 5. Unity! WebGL! etc,etc…
  6. 6. Unity! WebGL! etc,etc…今はやりの技術を使えばボクにも実現可能!どうやら結論が出たようですね…
  7. 7. 違います!
  8. 8. 違います!そういう正攻法じゃ満足できないんです…今日集まってくれたみなさんも、もうちょっとマゾいと信じています
  9. 9. OpenGL + OpenAL + C++
  10. 10. OpenGL + OpenAL + C++• OpenGLは今やもっとも幅広く使える描画実装 Windows/OSX/iOS/Linux/Android/ゲーム専用機…• OpenALもそれに近い Windows/OSX/iOS/Linux/Android…• C++はCPUに近い言語なので実行速度的に有利 (と思う)• C、C++にもオープンソースの優秀なライブラ リが多数存在する
  11. 11. OpenGL + OpenAL + C++• そして…OpenGLはMESAというソースの公開さ れた実装が存在する
  12. 12. 予告内容• 用意するもの~• 実装のコツ~• ハマった点時間があれば…• デバッグ手法• 最適化
  13. 13. じゃあ始めましょうか!• Windows VisualStudio2010• OSX/iOS Xcode最新版• Linux ターミナルどの環境でもC++の標準ライブラリが使えます
  14. 14. じゃあ始めましょうか!あと、こんだけ準備して。• glut• OpenAL• zlib• libpng• Freetype• FTGL• FTGLES• picojson
  15. 15. じゃあ始めましょうか!• Xcodeではデバッグビルド設定の「プリプロセッ サ」に「_DEBUG」を追加しておく #ifdef _DEBUG /* デバッグ時の実装 */ #endif• iOSでのビルド設定「Compress PNG Files」はオ フっておいてね!ぜったいだよ!
  16. 16. コード書くよ。• ソースの文字コードはUTF-8 BOMあり• しかもVS2010では printf(“ほげほげ”); がcp932に勝手に変換され る(怒) ので #pragma execution_character_set(“utf-8”) で回避• プログラムからテキストデータを読み込む場合は UTF-8で用意
  17. 17. 今回決めたたったひとつのルール• ゲーム本体を.cppに書 かないで全てヘッダフ ァイルに書く• 僕はコード編集は専ら emacsなので問題な いです• ファイルを追加しても プロジェクトを触らな くてイイ!
  18. 18. こんな感じになってます#include “app.hpp“ // 芋づる式に18000行程度読み込まれるApp *app;int main(int argc, char **argv){ glutInit(&argc, argv); app = new App(/* 引数いろいろ */); /* 初期化いろいろ */ glutMainLoop();}
  19. 19. 表示のコールバックvoid displayCallback(){ glClear(GL_COLOR_BUFFER_BIT); app->update(); glutSwapBuffers();}
  20. 20. 入力のコールバックvoid mouseCallBack(const int button, const int state, constint x, const int y){ app->mouse.input(/* 引数いろいろ */);}void keyPushCallback(const u_char key, const int x, constint y){ app->key.input(/*引数いろいろ */);}
  21. 21. それがiOSだと?#include "app.hpp"App *app;- (void)awakeFromNib{ /* いろいろ初期化 */ app = new App(/*引数いろいろ */);}ちなみにソースのファイル名をViewController.mmにしないとC++のコードを混在させられないので注意!
  22. 22. - (void)drawFrame{ [(EAGLView *)self.view setFramebuffer]; glClear(GL_COLOR_BUFFER_BIT); app->update(); [(EAGLView *)self.view presentFramebuffer];}
  23. 23. タッチ入力はこうします- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent*)event{ app->mouse.input(/* 引数いろいろ */);}
  24. 24. OpenGL → OpenGL ES 1.1#if (TARGET_OS_IPHONE)typedef GLfloat GLdouble;#define glFrustum(left, right, bottom, top, znear, zfar)glFrustumf(left, right, bottom, top, znear, zfar)#define glOrtho(left, right, bottom, top, znear, zfar)glOrthof(left, right, bottom, top, znear, zfar)#define glFogi(pname, param) glFogx(pname, param)#endif
  25. 25. OpenGL → OpenGL ES 1.1さすがに gluUnProject() とか gluProject()とか… glu系は実装されてない…MESAの出番!ソースが公開されているのでそれを見ながら自分で実装
  26. 26. いったんまとめ• 文字コード問題はだいたい収束• ゲーム本体を1つのクラスと見立て、その内 部をだいたいどんなコンパイラでも通るよう にお上品に書く。• そのクラスを操作する箇所で入力とかセーブ とか画面の回転とか…環境依存な処理を行え ばよい。• ちょっとした工夫でOpenGLとOpenGL ESの差 異は充分吸収できる
  27. 27. バラバラな解像度をひとつにまとめる
  28. 28. バラバラな解像度をひとつにまとめる• Windows/OSX/Linuxでは、「縦横非固定モー ド」を実装• 初期サイズを960x640と決め、それより狭 かった場合には起動時に調整するみたいな。
  29. 29. バラバラな解像度をひとつにまとめる• iOSは320x480~1536x2048と、多種多様な解 像度が存在するので「見た目固定モード」を 実装
  30. 30. バラバラな解像度をひとつにまとめる• カメラは2つ用意3DglMatrixMode(GL_PROJECTION);glLoadIdentity();glFrustum(width, -width, -height, height, nearZ, farZ);2DglMatrixMode(GL_PROJECTION);glLoadIdentity();glOrtho(-width / 2.0, width / 2.0, height / 2.0, -height /2.0, -1.0, 1.0);
  31. 31. バラバラな解像度をひとつにまとめる• iPhone3GSは2Dのスケーリングを調整して見 た目をiPhone4とあわせる• 新しいiPadも同じように調整すれば対応でき るwidth *= 0.5;height *= 0.5;glOrtho(-width / 2.0, width / 2.0, height / 2.0, -height /2.0, -1.0, 1.0);
  32. 32. 結局UIViewiOSの画面回転でメニューの表示が崩れるのは、UIViewみたく「画面端基準」を自力で実装して切り抜けた
  33. 33. そろそろ音周りも聞きたい!
  34. 34. そろそろ音周りも聞きたい!• OpenALのサンプル通りに書いたら問題ないで す• 自分はwav形式のデータを自力で読み込み、 OpenALに渡してます• ストリーミング関連よくわかんない
  35. 35. 可搬性≒テキストファイル
  36. 36. 可搬性≒テキストファイル• GEOSPOTのセーブデータはすべての動作環境 で互換性がある• バイナリデータだと、とにかく環境依存に なってしまう。たとえばlong型。OSXのx64は 8バイト。それ以外だと4バイト。• 人間が読み書きできるので修正も楽
  37. 37. 可搬性≒テキストファイル• XML…ちょっと自分には読み書きできない• JSON…素晴らしい!
  38. 38. 可搬性≒テキストファイルリプレイデータもプレイ内容をテキストで書き出しているだけ-21.16 13334666110.017 0.156676 -0.807913 -0.247557 0.511317 1955.81 0 0 0 00.0503333 0.156676 -0.807913 -0.247557 0.511317 1955.81 0 00 00.0836667 0.156676 -0.807913 -0.247557 0.511317 1955.81 0 00 00.100667 0.156676 -0.807913 -0.247557 0.511317 1955.81 0 0 00
  39. 39. ファイルはどこから読み込むの?
  40. 40. ファイルはどこから読み込むの?Windows/Linuxの場合実行ファイルがある場所がカレントstd::string path = “”;read(path + “devdata/hoge.png”);
  41. 41. ファイルはどこから読み込むの?OSXの場合起動時に場所を取得CFBundleRef mainBundle = CFBundleGetMainBundle();CFURLRef resourcesURL =CFBundleCopyResourcesDirectoryURL(mainBundle);char str[PATH_MAX];CFURLGetFileSystemRepresentation(resourcesURL, TRUE, (UInt8*)str, PATH_MAX);std::string path = std::string(str) + std::string(“/”);read(path + “devdata/hoge.png”);
  42. 42. ファイルはどこから読み込むの?iOSの場合起動時に場所を取得std::string path = [[[NSBundle mainBundle] resourcePath]UTF8String] + std::string("/");read(path + “devdata/hoge.png”);
  43. 43. ファイルに関してのまとめ• プログラムの開始時、OS別に読み込み時のパ スと書き出し時のパスを取得しておく• iOSも、C++の標準ライブラリ関数を使った ファイルの読み書きができる fstream >> value; こういうファイル読み込みでいける
  44. 44. まさかの:乱数でハマった
  45. 45. まさかの:乱数でハマったGEOSPOTではクイズの出題順序をランダムにシャッフルしているのだが…デモプレイが環境によって違う!どうも、Widnowsとその他でrand()の実装が違うっぽい?
  46. 46. まさかの:乱数でハマったこれは std::tr1::random を使う事で解決!ただし…初期化時の引数はこうしとくunsigned long seed = time(0) & 0x7fffffff;OSXのx64はlongが8バイト、その他は4バイトなのが原因で初期値が変わってしまうのを防ぐ
  47. 47. タイマー処理60FPSで動かない場合でも、ゲーム内の時間経過を正確に行うためにタイマーを使って時間を計測してますWindows• timeGetTime() ←精度が悪い(T T)それ以外• gettimeofday() ←最高!
  48. 48. ここまでのまとめ• ファイルパスや型のサイズなど、実行環境の 違いを吸収する必要のあるもの、必要ないも のを切り分けておけば怖くない!• 週一くらいの間隔でよいので他の環境でもビ ルドが通るかの確認は怠らない。
  49. 49. もしかして:時間切れ?デバッグ手法と最適化に関してはまた次の機会にでも~
  50. 50. いまその瞬間のCPU
  51. 51. いまその瞬間のCPU• VisualStudioもXcodeもデバッガが非常によ くできているので困る事はない。• でもやっぱりプログラムからコンソールに文 字を出力するのは手軽で便利
  52. 52. いまその瞬間のCPUC++だとこう書きますcout << “ほげほげ” << endl;
  53. 53. いまその瞬間のCPUだがしかしWindowsでは出力されないのであった…!class DbgStreambuf : public std::streambuf { std::vector<char> str_;public: int_type overflow(int_type c = EOF) { str_.push_back(c); return c; } int sync() { str_.push_back(0); // 念のため OutputDebugString(&str_[0]); str_.clear(); return 0; }};
  54. 54. いまその瞬間のCPUだがしかしWindowsでは出力されないのであった…!Class Os { DbgStreambuf dbgStream_; std::streambuf *stream_;public: Os() { stream_ = std::cout.rdbuf(&dbgStream_); } ~Os() { std::cout.rdbuf(stream_); }};
  55. 55. いまその瞬間のCPUだがしかしWindowsでは出力されないのであった…!int main() { Os os; cout << “ほげほげ” << endl; return 0;}
  56. 56. いまその瞬間のCPUリリースビルドでcoutを一網打尽#ifdef _DEBUGDOUT std::cout#elseDOUT 0 && std::cout#endifDOUT << “ほげぴよ” << endl;
  57. 57. 最適化は機械任せ☆
  58. 58. 最適化は機械任せ☆XcodeのInstrumentsやOpenGL ES PerformanceDevectiveで計測すれば処理負荷の大きい場所が特定できる。
  59. 59. 最適化は機械任せ☆GEOSPOTではCPUのコードは3GSでも120FPS超えてるので、まったく最適化作業を行ってないてへぺろ。OpenGL ESは分析結果に「VBOとPVRTCテクスチャを使えばいいよ」と出たのでそうしたら、だいたい60FPSになったが…iPhone4が一番重い。
  60. 60. 終わりですこの場を与えてくださった岸川さんを始めお手伝いの方々、今日ここに来てくださった皆さん、聞いてくださったすべての人たちに感謝!

×