コンテンツにスキップ

2. Siv3D の基本

Siv3D のプログラムの基本的な構成について学びます。

2.1 インクルードするヘッダ

Siv3D のプログラムを書くときは <Siv3D.hpp> ヘッダをインクルードします。
これだけで、Siv3D の関数やクラスを使ったプログラムを書けるようになります。

# include <Siv3D.hpp>

経験のある C++ プログラマの場合、<iostream><vector> などの C++ 標準ライブラリをインクルードしたくなるでしょうが、それは不要です。すでに <Siv3D.hpp> の中で、Siv3D プログラミングでよく使われる主要な C++ 標準ヘッダがインクルードされているためです。

また、Siv3D の関数やクラスは、標準ライブラリ機能(std::vectorstd::string など)の多くを置き換え、不要にします。Siv3D の学習の序盤で C++ 標準ライブラリを使うことはめったにありません。

C++ の文法復習「include」

# include <ファイルパス> または # include "ファイルパス" で、ヘッダ パス をインクルードします。前者の書き方では、標準ライブラリや、プロジェクトの設定でインクルードパスに設定されているフォルダのファイルが対象になり、後者では相対パスまたは絶対パスでファイルを検索します。Siv3D のプロジェクトでは、Siv3D のヘッダがあるディレクトリがインクルードパスに設定されているため、# include <Siv3D.hpp> で Siv3D のヘッダをインクルードできます。Siv3D 以外のプロジェクトで同じように書いても Siv3D.hpp を見つけられずコンパイルエラーになります。

インクルードが不要なヘッダの例

<string>

Siv3D.hpp 内ですでにインクルードされています。
std::string の置き換えとして String があります。

<vector>

Siv3D.hpp 内ですでにインクルードされています。
std::vector の置き換えとして Array があります。

<fstream>

std::ofstream の置き換えとして TextWriterBinaryWriter があります。
std::ifstream の置き換えとして TextReaderBinaryReader があります。

<cmath>

Siv3D.hpp 内ですでにインクルードされています。
Math:: 名前空間に主要な数学関数が用意されています。

<filesystem>

ファイルシステムに関する機能が FileSystem:: 名前空間に用意されています。

2.2 エントリーポイント

通常の C++ のエントリーポイントは int main() ですが、Siv3D のプログラムでは main() 関数は Siv3D のライブラリ内に既に実装されています。

Siv3D ライブラリ内部のコード(説明のために簡略化しています)
int main()
{
	Siv3D初期化(); // サブシステムの初期化処理

	Main(); // この関数をユーザがプログラムする

	Siv3D終了処理(); // サブシステムの終了処理
}

まずウィンドウやグラフィックスなどのサブシステムの初期化処理を行うプログラムが実行され、次に、ユーザが書いた Main() 関数が呼び出されます。この仕組みにより、Main() 関数では初期化処理などの準備を行わず直ちに Siv3D の機能を使うことができます。

Main() 関数の実行が終了すると、再び Siv3D の内部のコードが、ウィンドウの後片付けなどサブシステムの終了処理を自動的に行います。

2.3 最小のプログラム

手元のエディタで Siv3D のプログラムをゼロから書いてみましょう。これが Siv3D の最小のプログラムです。

# include <Siv3D.hpp>

void Main()
{

}
この Main() 関数は何もすることがないため、一瞬で終了してしまいます。このプログラムを実行してもウィンドウは表示されず、何も起こっていないように見えるでしょう。

C++ の文法復習「関数の定義」

これは関数を定義するプログラムです。Main は関数の名前を、void はこの関数が結果の値を返さないことを表します。{ } 内には、この関数で実行したいプログラムを上から順に記述します。途中で return するか、終端までたどり着くと関数の実行は終了します。

2.4 ウィンドウを表示し続ける

プログラムがすぐに終了してしまっては、ユーザとインタラクションをするアプリケーションを作れません。Main() がずっと続くように メインループ を実装します。次のコードではウィンドウが表示され続けます。

# include <Siv3D.hpp>

void Main()
{
	while (System::Update())
	{

	}
}

while 文によって、ハイライト部分のプログラムが半永久的に繰り返されます。

繰り返しのたびに System::Update() がウィンドウの表示や音楽の再生、マウスやキーボードの入力情報などを更新することで、グラフィックスの表示やユーザの入力の取得などを継続的に処理できるようになります。

C++ の文法復習「while ループ」

while (条件)
{
	
}
は、条件が真である間、{ } の文を繰り返します。

2.5 アプリケーションの終了

2.5.1 メインループの終了

# include <Siv3D.hpp>

void Main()
{
	while (System::Update()) // System::Update() が false を返すまで繰り返す
	{

	}
}

System::Update() 関数は普段は true を返すため、半永久的にメインループが続きますが、特定の操作をすると、それ以降は false を返すことでメインループを終了させ、そのまま Main() 関数の終端まで到達するとプログラムが終了します。

System::Update()false を返すようになる(アプリケーションを終了させる)操作は、デフォルトでは次の 3 つです。

  • ウィンドウを閉じる
  • Esc を押す
  • プログラムで System::Exit() を呼ぶ

2.5.2 Main() からの return

Main() の中で return; して Main() を終了することも、アプリケーションの終了手段として有効です。とくに、System::Update() を待たず、直ちにプログラムを終了したい場合には return; が役に立つでしょう。

どちらを選択するかは、プログラムの目的によって異なります。下記のタブを切り替えて、それぞれの違いを確認してみましょう。

System::Exit(); の呼び出し後、処理 A処理 B が実行されてから Main() が終了します。

# include <Siv3D.hpp>

void Main()
{
	while (System::Update())
	{
		// 実行時間が 3 秒以上経過したら
		if (3.0 <= Scene::Time())
		{
			System::Exit(); // 次の System::Update() が false を返すようにする
		}

		処理A();
	}

	処理B();
} // ここで Main() が終了

return; すると、処理 A処理 B は実行されずに Main() が終了します。

# include <Siv3D.hpp>

void Main()
{
	while (System::Update())
	{
		// 実行時間が 3 秒以上経過したら
		if (3.0 <= Scene::Time())
		{
			return; // ここで直ちに Main() が終了する
		}

		処理A();
	}

	処理B();
}

2.6 System::Exit() は必須ではない

System::Exit() は、その後の System::Update()false を返すよう設定するだけの関数です。明示的に System::Exit() を呼び出さなくても、ウィンドウを閉じたり Esc を押すことで System::Update()false を返させて、アプリケーションを終了できます。したがって、System::Exit() の呼び出しは必須ではありません。

振り返りチェックリスト

  • Siv3D の基本的なプログラムでは <Siv3D.hpp> のみをインクルードすることを学んだ
  • Siv3D プログラムのメイン関数が int main() ではなく void Main() であることを学んだ
  • ウィンドウを表示し続ける方法を学んだ
  • ウィンドウを閉じるか Esc を押すとアプリケーションが終了することを学んだ
  • System::Update() の戻り値が false になるとアプリケーションが終了することを学んだ
  • System::Exit()System::Update() の戻り値を false に設定できることを学んた
  • return; を使うことでも Main() を終了できることを学んだ
  • System::Exit() の呼び出しは必須ではないことを学んだ