C++とは?
C言語の拡張として開発された言語です。
初期の名称は『C With Classes』だったそうです(Wiki情報)。
C言語は1972年にデニス・リッチーさんがB言語を改良して開発したプログラム言語です。
それからUNIXの共同開発者であった事もあり、開発後にUNIXの殆どはC言語に書き換えられました。
これによりUNIX上で動作するユーティリティもC言語で開発されるようになっていきました。
C言語で開発されるメリットとして、コンパイラを通してビルドされるのでハードの仕様が変わっても対応するコンパイラさえ開発してしまえば互換が確保されることがあります。
これは現在でもC言語が使用され続けている要因の一つだと思います。
ただC言語だけでは大規模な開発で管理やコードの可読性が問題になってきました。
そこでクラスという概念を取り入れることをしたのがC++です。
俗にオブジェクト指向プログラミングと言われるものです。
当時はSimulaと呼ばれるクラスを使用したプログラム言語がありました。
それが大規模な開発でも耐えうる機能を有していることに気付いたビャーネ・ストロヴストルップさんが開発しました。
何故そのままSimulaを使用しないのかと言うとインタプリタ言語だったので速度面が遅かった事が原因のようです。
そして1983年にC++が開発されました。
C言語の拡張なのでC++もコンパイルして機械語に変換されるのでインタプリタ言語と比べて高速になっています。
又、現在でも多く使用されているので、数年に一度は規格の更新が行われており、次回は2020年に規格が更新される予定です。
ゲーム業界での開発
現在の開発は下記のようなパターンが多いです。
C++を使った開発
C++を使って各プラットフォームに応じたコンパイラを使って開発します。
『C++とは?』の項目にも書きましたがコンパイラさえ変えればある程度は互換性があります。
ただ各プラットフォーム毎に用意されたハードウェア的な機能は異なる事が基本なので、それぞれのプラットフォーム向けに実装してくことになります。
iOSではObjective-Cと呼ばれる言語が使用されていますが、C++でもプログラムが出来るようになっています。
比較的に動作の高速なプログラムが書けますが、パフォーマンスは開発者の能力に大きく左右されます。
ゲームエンジンを利用した開発
有名なのはUnity、UnrealEngineです。
ゲームエンジンを使うことで個々でシステムの開発を行う必要が無くなるので、開発の効率化が図れます。
ただし、ゲームエンジンの使用方法を習得する必要や売り上げに応じたお金の支払いが生じます。
Unityはネット上に情報も多く、無償で使える機能も豊富なので個人開発者も利用している方は多いです。
プログラムを書かなくてもゲームを作れてしまう可能性すらありますが、規模が大きくなると大体プログラムが必要になってきます。
UnityはC#でスクリプトを書いて実装していきます。
※Unity自体はC++で作られています。
UnrealEngineはC++でプログラムを書いて実装していきます。
他にもパターンは色々ありますが、現在の開発で多いのはこの2パターンだと思います。
Unityはスマートフォンでの開発に利用されることが多いので、コンシューマーでゲームを開発する際は大体C++が必要になってきます。
実際にプログラムを作ってみよう
C++を使うとどんな書き方になるのか簡単にプログラムで書いてみましょう。
今回は時間を計測するストップウォッチをC言語とC++の両方で書いてみましょう。
先ずはC言語でストップウォッチを作ります。
Stopwatch.h
#pragma once #include <windows.h> // ストップウォッチ情報 struct StopwatchData { LARGE_INTEGER Freq; // 周波数 LARGE_INTEGER Start; // 開始時間 }; // ストップウォッチの初期化 void InitStopwatch(StopwatchData* pStopwatchData); // ストップウォッチのリセット void ResetStopwatch(StopwatchData* pStopwatchData); // ストップウォッチの経過時間取得 double GetElapsedTime(StopwatchData* pStopwatchData);
Stopwatch.cpp
#include "Stopwatch.h" // ストップウォッチの初期化 void InitStopwatch(StopwatchData* pStopwatchData) { QueryPerformanceFrequency(&pStopwatchData->Freq); ResetStopwatch(pStopwatchData); } // ストップウォッチのリセット void ResetStopwatch(StopwatchData* pStopwatchData) { QueryPerformanceCounter(&pStopwatchData->Start); } // ストップウォッチの経過時間の取得 double GetElapsedTime(StopwatchData* pStopwatchData) { LARGE_INTEGER End; QueryPerformanceCounter(&End); const LONGLONG TICK_DELTA = 1000000000; const double INV_TICK_DELTA = 1.0 / (double)TICK_DELTA; LONGLONG elapsed = (End.QuadPart - pStopwatchData->Start.QuadPart); return (double)((elapsed * TICK_DELTA) / pStopwatchData->Freq.QuadPart) * INV_TICK_DELTA; }
これで実際に計測をしてみます。
main.cppなど適当な箇所で下記を記載します。
#include <windows.h> #include <stdio.h> #include "Stopwatch.h" int APIENTRY WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { StopwatchData stopwatchData; InitStopwatch(&stopwatchData); ResetStopwatch(&stopwatchData); // 120msの待ちを入れる Sleep(120); double elapsed = GetElapsedTime(&stopwatchData); char temp[64]; sprintf_s(temp, "time:%f\n", elapsed); OutputDebugStringA(temp); }
・結果
time:0.120951
実行してみると出力ウィンドウに上記のような結果に大体120msの結果が出るかと思います。
この結果ならちゃんと計測できてますね。
次にC++の場合です。
C++ではストップウォッチをクラスかして作ってみます。
Stopwatch.h
#pragma once #include <windows.h> // ストップウォッチクラス class Stopwatch { public: // コンストラクタ Stopwatch(void); // デストラクタ ~Stopwatch(void); // ストップウォッチのリセット void Reset(void); // ストップウォッチの経過時間の取得 double GetElapsedTime(void); private: LARGE_INTEGER m_Freq; // 周波数 LARGE_INTEGER m_Start; // 開始時間 };
Stopwatch.cpp
#include "Stopwatch.h" // コンストラクタ Stopwatch::Stopwatch(void) { QueryPerformanceFrequency(&m_Freq); Reset(); } // デストラクタ Stopwatch::~Stopwatch(void) {} // ストップウォッチのリセット void Stopwatch::Reset(void) { QueryPerformanceCounter(&m_Start); } // ストップウォッチの経過時間の取得 double Stopwatch::GetElapsedTime(void) { LARGE_INTEGER End; QueryPerformanceCounter(&End); const LONGLONG TICK_DELTA = 1000000000; const double INV_TICK_DELTA = 1.0 / (double)TICK_DELTA; LONGLONG elapsed = (End.QuadPart - m_Start.QuadPart); return (double)((elapsed * TICK_DELTA) / m_Freq.QuadPart) * INV_TICK_DELTA; }
これで実際に計測をしてみます。
main.cppなど適当な箇所で下記を記載します。
#include <windows.h> #include <stdio.h> int APIENTRY WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { Stopwatch stopwatch; stopwatch.Reset(); Sleep(120); double elapsed = stopwatch.GetElapsedTime(); char temp[64]; sprintf_s(temp, "time:%f\n", elapsed); OutputDebugStringA(temp); }
・結果
time:0.120526
似たような結果が出ましたね!
C++のクラスは構造体に似ていますが、メンバ変数の他にメンバ関数と呼ばれる関数を持つことができます。
他にpublicやprivateと書いている部分がありますが、外部から参照してほしくない値をクラス内部に隠ぺいすることができます。
構造体だと触られてしまう可能性がある値を外部から変更されないと保証することができます。
自分一人ならC言語でも管理していけるかもしれませんが、大規模な数十人が関わるプロジェクトになってくるとこの安全性が重要になってきます。
今回はこのぐらいにしておきますが、他にもC++には便利な機能が沢山あります。
なのでC言語から始めた人も怖がらずにC++に挑戦してみましょう!