C++ で ゲーム作り
なぜC++を使うのか
 動作が軽いから(諸説あり)
 GPUへの負荷が軽い。
 ゲームの実行環境はユーザーで異なるが、それぞれの環境で安定した動作ができる。
 実行ファイル形式にすると起動がとても早い。(諸説あり)
 SDL ( Simple DirectMedia Layer )
 クロスプラットフォームなゲーム開発ができる
 ウィンドウの作成、基本的な2Dグラフィックスの作成、入出力の処理、オーディオの出力などができる
 C言語で書かれているためC++で動作でき、他のライブラリと併用して色々できる
 Made with SDL ... Dota2 , factorio , TeamFortress2 , HALF-LIFE など
簡単な構成のゲーム
ピンポンゲーム
フレーム
 ゲームの流れ
「初期化 → ゲームループ → 終了」
 ゲームループの構成
 フレームを繰り返す
1. 入力の処理
2. ゲームワールドの更新
3. 出力の生成
フレームを繰り返して、ゲームループを作る。
SDLを元に自作クラスを作成する
 SDL_Windowの使い方
 C++プロジェクトにライブラリを入れる
Rubyのようにライブラリ管理ツールなどないので、主な手法はgithubから引っ
張ってきて直接置く。
 SDLを使用して実際にコーディングする。
Gameクラスを作成するためにヘッダーファイル(Game.h)でSDLを参
照
GAME.H
 Gameクラスのヘッダーファイルに必要なヘルパーメソッドやインスタンスを作成する。
 メソッド
 initialize, shutdown, loop, input, update, outputなど
 インスタンス
 window, renderer, isRunnningなど
初期化
 最低限の画面が映るまで以下の操作が必要
1. SDLを初期化する
2. 映す画面の作成
3. レンダラーに画面を移させる
終了
 初期化の逆を行う
1. レンダラー壊す
2. 画面壊す
3. SDL壊す
この辺しっかり書かないとやばい。
(家のWinPCでここを消した時、シャットダウンす
るまで消えないタスクが生まれた)
ループ
 フレームに必要な3つの要素をメソッドヘル
パーメソッドとして作成し、
ループ中に毎フレーム呼び出す。
画面表示させるだけ
 main.cでGameクラスを初期化してループさせ
ると、画面が表示されるようになる。
入力の処理
 ProcessInputメソッド
 動作環境の入力デバイスに関するイベント(マ
ウス、キーボード)や、
ウィンドウ操作のイベント(閉じる、最小化
etc..)はSDL_Eventで取得できる。
 全てのイベントに対し、処理を書くことができ
る。
キーボード入力
 SDL_GetKeybordStateメソッドで整数の配列と
して取得
予約された名前があるので、それで配列から
目的のキーが押されたか判別する。
画面出力の基礎知識①
 2次元グラフィクス(テレビやモニターなど)は、ほとんどラスターグラフィクス
 ラスターグラフィクスとは
ディスプレイにピクセルを2次元の格子状に並べて、ピクセルそれぞれに色を発させて全体を見ると1つの画像になる。
 解像度とは
ピクセルの縦、横に並んでいる数。
1080p(1920 x 1080), 4K(3840 x 2160)
 色
一般的には赤緑青(RGB)のライトを用意し、それぞれの輝度を調整して色域内で表現する。
ゲームグラフィクスでは計算の都合上、半透明度を表すアルファ値を足して、RGBAで色を計算する。
 色深度
個々のピクセルが持つ色を表現するビット数。24ビットの色深度が一般的。224色(約1600万通り)で、RGBのそれぞれに8ビットが
当てられる。
アルファ値も用いるならさらに8ビット足してカラーバッファは32ビットになる。1080pの画面の場合、1920x1080x4バイトで
7.9MB分のメモリ容量が必要になる。
画面出力の基礎知識②
 カラーバッファ
コンピュータがRGBを映すのに、メモリ内のカラーバッファに画面全体の色情報が
置かれる。
カラーバッファは2次元配列で一つのインデックス(x,y)が1ピクセルに対応する。
ゲームループの出力の生成はカラーバッファを作ることを指す。
 ティアリング
一般的なモニターのリフレッシュレートは59.94Hz、ゲームのfpsは60fpsなので、モ
ニターのリフレッシュレートはちょっと少ない。(ズレがある)
カラーバッファは一度に書き換えることはできず、ピクセル単位で更新される。
結果、ディスプレイの更新とカラーバッファの更新のタイミングがかぶる。メモ
リーの書き出しと読み出しは同時に行えないので、中途半端な画面が表示されてし
まう。画面に継ぎ目が表示されることを画面のティアリングという。
画面出力の基礎知識③
 ダブルバッファ
ティアリングを防ぐためにディスプレイ側が読み出
すためのフロントバッファ、ゲーム側が書き込む
バックバッファの二つを用意する手法
出力画面の作成とレンダラーへ出力画面を渡す工程
が必要なのはこれのせい。
(ゲームの更新が早すぎたらダブルバッファでも
ティアリングが起きるので、バッファ交換を書き込
みが終わるまで待つ垂直同期方式などもある。)
出力の生成
 まず、カラーバッファをクリアする
 SDLのメソッドを使って物体の描画(ピンボールを作る)
(FillRectは塗りつぶし)
 描きたいものを作成したら、バックバッファとフロントバッファ
を入れ替える。
ゲームの更新①
 現実世界で経過する実時間とゲームの世界のゲーム時間が対応しない問題
 プロセッサーが一定の速度で動かない。
動作環境によって8Mhzであったり16Mhzであったりして、この2つではゲームループ時間が違い、
enemy.mPosition.x += 5 などと書けば、移動速度が倍になる。
 デルタタイム
 最後のフレームから今まで経過した時間のこと。30fpsなら約0.033秒
enemy.mPosition.x += 150 * deltaTime と書くと、どのような環境でも一定の速度で動くようになる。(する。)
SDL_GetTicks()で初期化からの経過ミリ秒数を取得できる
ゲームの更新②
 物理法則を均一化
ジャンプしたりするアクションゲームではフレームレートによって異なる振る舞いをする事になる。
簡単な解決策はフレーム制限を設けてターゲットのデルタタイムが経過するまでゲームループを止める事。
 デルタタイムの最大値
デバックの時に、コードをステップ実行しているとデルタタイムがかなり大きくなる。
これではシミュレーションしていても、すべてが過ぎて行ってしまうので、デルタタイムの最大値を決めておく。
色々と仕上げ
 キー入力からパドルを動かす
 ボールの位置を更新
etc ...
余談
 C++で書いた場合
 行数: 約300行
 負荷:
 Rubyで書いた場合
 行数: 約 50行
 負荷:

Gameprog1