C++OpenSiv3D入門講座 Vol. 08 GameManagerクラス

C++OpenSiv3D入門講座

実際ゲームを作る時、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)

  1. GameManagerクラスを作れ。
    • GameManagerクラスは、PlayerやEnemyManager(Enemyのvectorを管理するクラス)をメンバに持ち、それらを管理するクラスである。
    • GameManagerのインスタンスグローバル変数にすることで、GameManagerを介してPlayerやEnemyの情報にアクセスできるようにせよ。
    • GameManagerクラスのupdateを呼べば、PlayerとすべてのEnemyのupdateが呼ばれるようにせよ。
    • EnemyクラスがPlayerクラスへのポインタを持っていた場合、それを消して、Playerクラスへのアクセスはグローバル空間に存在するGameManagerクラスのインスタンスを介して行うようにせよ。
  2. Enemyが自機を追うようにせよ。
  3. Enemyクラス内にint型のkind変数を作り、kind変数によって敵が多様な動きをするようにせよ。
    (例:kind==1なら自機に直進、kind==2ならsin軌道、kind==3なら出た位置で円運動)
  4. kindによって敵の色が変わるようにせよ。
  5. kindをenum型にせよ。クラス内で定義された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;
}

C++OpenSiv3D入門講座