C++OpenSiv3D入門講座 Vol. 08 GameManagerクラス
実際ゲームを作る時、PlayerやEnemyの配列、Bulletの配列、Effectの配列等をメンバに持ち、それらを管理するManagerクラスを作ると便利である。
今回は、PlayerとEnemyを持つManagerクラスの実体をグローバル変数にすることで、EnemyとPlayerが相互にアクセスする例を示す。 (前回は、EnemyクラスがPlayerへのポインタを持つことで、Playerクラスにアクセスすることができたが、今回はEnemyクラスがPlayerクラスへのポインタを持つ必要はない)
PlayerがEnemyの情報に、EnemyがPlayerの情報に相互にアクセス出来るようにするため、上手くファイルをインクルードしなければならない。
以下の例では、PlayerはshowEnemyX関数でEnemyのxにアクセスし、EnemyはshowPlayerX関数でPlayerのxにアクセスしている。
#pragma once #include <iostream> #include "Manager.h" class Player { public: int x; Player(int _x); void update(); void showEnemyX(); };
#include "Manager.h" Player::Player(int _x) : x{ _x } { } void Player::update() { std::cout << "Player内のupdateが呼ばれました。xは:" << x << std::endl; } void Player::showEnemyX() { std::cout << "Player内のshowEnemyXが呼ばれました。" << std::endl; std::cout << "Enemyのxは:" << manager.enemy.x << std::endl; }
#pragma once #include <iostream> #include "Manager.h" class Enemy { public: int x; Enemy(int _x); void update(); void showPlayerX(); };
#include "Manager.h" Enemy::Enemy(int _x) : x{ _x } { } void Enemy::update() { std::cout << "Enemy内のupdateが呼ばれました。xは:" << x << std::endl; } void Enemy::showPlayerX() { std::cout << "Enemy内のshowPlayerXが呼ばれました。" << std::endl; std::cout << "Playerのxは:" << manager.player.x << std::endl; }
#pragma once #include "Player.h" #include "Enemy.h" class Manager { public: Player player; Enemy enemy; Manager(); }; extern Manager manager;
#include "Manager.h" Manager::Manager() : player{ 100 }, enemy{ 200 } { }; Manager manager;
#include <iostream> #include "Manager.h" int main() { manager.player.update(); manager.enemy.update(); manager.player.showEnemyX(); manager.enemy.showPlayerX(); return 0; }
上記の例では、Manager.cppでManager型のグローバル変数を作成している。
Manager manager;
また、Manager.hで
extern Manager manager;
とすることで、Manager.h内及びManager.hをインクルードした場所で他のファイルにあるグローバル変数managerを使うことが可能になる。
演習問題(OpenSiv3D)
- GameManagerクラスを作れ。
- GameManagerクラスは、PlayerやEnemyManager(Enemyのvectorを管理するクラス)をメンバに持ち、それらを管理するクラスである。
- GameManagerのインスタンスをグローバル変数にすることで、GameManagerを介してPlayerやEnemyの情報にアクセスできるようにせよ。
- GameManagerクラスのupdateを呼べば、PlayerとすべてのEnemyのupdateが呼ばれるようにせよ。
- EnemyクラスがPlayerクラスへのポインタを持っていた場合、それを消して、Playerクラスへのアクセスはグローバル空間に存在するGameManagerクラスのインスタンスを介して行うようにせよ。
- Enemyが自機を追うようにせよ。
-
Enemyクラス内にint型のkind変数を作り、kind変数によって敵が多様な動きをするようにせよ。
(例:kind==1なら自機に直進、kind==2ならsin軌道、kind==3なら出た位置で円運動) - kindによって敵の色が変わるようにせよ。
- kindをenum型にせよ。クラス内で定義されたenumは、クラス外部からは(クラス名)::(要素の名前)で enumを指定できる。
ヒント
#include <iostream> class Hoge { public: enum Kind { A, B, C, }; Kind kind; //コンストラクタ kindを指定 Hoge(Kind _kind) : kind{ _kind } { } }; int main() { // コンストラクタでkindを指定 Hoge ins(Hoge::B); // 出力。整数が出力される(0から始まる) std::cout << ins.kind << std::endl; return 0; }