敵が画面外に出たら自動的にインスタンスを破棄するようにしてみます。
ゲームパーツの抽象クラスであるTaskクラスには
bool update() = 0;
が純粋仮装関数として存在します。
私が勝手に独自で定義している方法ですが、
このboolの返り値は、trueならまだ維持していてほしい、falseならもう不要であることを示します。
ですので、画面外に出て、もう自分のインスタンスは不要だと思ったらupdateでfalseを返せばいいです。
管理部であるManagerクラスではupdateの返り値がfalseならリストから削除するようにしてみます。
EnemyManager.cpp
#include "EnemyManager.h" #include "Define.h" #include "SmallEnemy.h" #include "NormalEnemy.h" #include "BigEnemy.h" #include <DxLib.h> using namespace std; EnemyManager::EnemyManager() { _list.emplace_back(make_shared<SmallEnemy >(Define::CENTER_X, 100)); _list.emplace_back(make_shared<NormalEnemy>(Define::CENTER_X-200, 150)); _list.emplace_back(make_shared<BigEnemy> (Define::CENTER_X+200, 200)); _list.emplace_back(make_shared<SmallEnemy >(Define::CENTER_X, 250)); _list.emplace_back(make_shared<NormalEnemy>(Define::CENTER_X-200, 300)); _list.emplace_back(make_shared<BigEnemy> (Define::CENTER_X+200, 350)); for (auto enemy : _list) { enemy->initialize(); } } bool EnemyManager::update() { for (auto it = _list.begin(); it != _list.end();) { if ((*it)->update() == false) { it = _list.erase(it); } else { it++; } } return true; } void EnemyManager::draw() const { DrawFormatString(0, 20, GetColor(255, 255, 255), "敵の数 = %d", _list.size()); for (const auto enemy : _list) { enemy->draw(); } }
コンストラクタで敵をちょっと沢山配置してみました。
updateの中身を少し変えました。リストの中をiteratorで一つずつアクセスしていき、updateの返り値がfalseならリストから削除します。
draw()内ではリストの要素数をリアルタイムに確認できるようにしました。
ではこれに従ってAbstractEnemyも変更します。
AbstractEnemy.h
#pragma once #include "Task.h" class AbstractEnemy : public Task { public: AbstractEnemy(float x, float y); virtual ~AbstractEnemy() = default; void initialize(); bool update() override; protected: virtual void setSize() = 0; bool isInside() const; float _x, _y;//座標 float _speed;//速さ float _angle;//角度 int _counter;//カウンタ int _width; //幅 int _height;//高さ };
AbstractEnemy.cpp
#include "AbstractEnemy.h" #include <DxLib.h> #include "Image.h" #include "Define.h" AbstractEnemy::AbstractEnemy(float x, float y) : _x(x), _y(y), _speed(0), _angle(0), _counter(0), _width(0), _height(0) { } void AbstractEnemy::initialize() { setSize(); } bool AbstractEnemy::update() { _counter++; _x += cos(_angle)*_speed; _y += sin(_angle)*_speed; return isInside(); } /*! @brief 現在の位置が画面内か? */ bool AbstractEnemy::isInside() const { if (_counter < 60) {//最初の1秒は判定しない return true; } if (_x < -_width/2 || Define::OUT_W + _width/2 < _x || _y < -_height/2 || Define::OUT_H + _height/2 < _y) { return false; } return true; }
updateの返り値をisInside()の返り値にしています。
isInside()は自分が今画面内にいるか?を返すメソッドです。
ここで前の章で設定した画像サイズを利用します。
単純に「_x < 0 なら画面外」という判定をしてしまうと、敵の中心点は画面外でも、画像サイズ÷2分ほどまだ画面内にいるため、途中でパッと消えたように見えてしまいます。
よって画像サイズ分が画面外に出て初めて画面外に出たという判定をする必要があります。
また、if(_counter < 60)は最初の1秒間は画面外に出たかどうかの判定をしないようにしています。
これは画面外からINしてくる演出をする敵もいるため、これを入れていないと画面外から入ってくる敵がすぐに消されてしまうのです。
今後のためにこの処理を入れて置きます。
実行結果では、敵が画面外に出るたびに敵の数が減っていることを確認してください。
実行結果