OpenSiv3D
では std::vector
の代わりに Array
を使います。Array
にはさまざまな便利なメンバ関数が用意されていますが、その中でも知っていると便利な Array::remove_if(f)
の使い方を紹介します。
Array::remove_if(f)
は、Array
の個々の要素 x
に対して f(x) == true
となる要素を Array
から削除します。C++ 標準ライブラリの v.erase(std::remove_if(v.begin(), v.end(), f), v.end())
と同じ働きです。
例 1
Array<int32>
から、10 未満の要素を削除する。
# include <Siv3D.hpp>
void Main()
{
Array<int32> v = { 3, 9, 10, 12, 8, 6, 11 };
Print << v;
v.remove_if([](int32 n){ return n < 10; });
Print << v;
while (System::Update())
{
}
}
{3, 9, 10, 12, 8, 6, 11}
{10, 12, 11}
▼ 上級者向けのテクニックですが、OpenSiv3D の LessThan
オブジェクトを使ってこのようにも書けます。
# include <Siv3D.hpp>
void Main()
{
Array<int32> v = { 3, 9, 10, 12, 8, 6, 11 };
Print << v;
v.remove_if(LessThan(10));
Print << v;
while (System::Update())
{
}
}
{3, 9, 10, 12, 8, 6, 11}
{10, 12, 11}
例 2
Array<int32>
から偶数を削除する。
# include <Siv3D.hpp>
void Main()
{
Array<int32> v = { 3, 9, 10, 12, 8, 6, 11 };
Print << v;
v.remove_if([](int32 n){ return n % 2 == 0; });
Print << v;
while (System::Update())
{
}
}
{3, 9, 10, 12, 8, 6, 11}
{3, 9, 11}
▼ 要素と同じ型の値を引数に取り bool
を返すような関数があれば、それを使うこともできます。
IsEven(x)
は整数 x
が偶数なら true
, そうでなければ false
を返す関数で、 OpenSiv3D に実装されています。
# include <Siv3D.hpp>
void Main()
{
Array<int32> v = { 3, 9, 10, 12, 8, 6, 11 };
Print << v;
v.remove_if(IsEven);
Print << v;
while (System::Update())
{
}
}
{3, 9, 10, 12, 8, 6, 11}
{3, 9, 11}
例 3
Array<Vec2>
で表される点群から、指定した Rect
上にある点を削除する。
# include <Siv3D.hpp>
void Main()
{
Array<Vec2> points;
for (int32 i = 0; i < 300; ++i)
{
points << RandomVec2(Scene::Rect());
}
constexpr Rect rect(200, 200, 400, 200);
// [rect] で rect をコピーキャプチャし、ラムダ式の中で使えるようにする
points.remove_if([rect](const Vec2& point){ return point.intersects(rect); });
while (System::Update())
{
rect.drawFrame(1, 0, ColorF(0.3));
for (const auto& point : points)
{
Circle(point, 4).draw();
}
}
}
例 4
モンスターの配列 Array<Monster>
(Monster
はユーザが作ったクラス) から、残り寿命が尽きたモンスター (Monster::isAlive()
が false
を返す) を削除する。
# include <Siv3D.hpp>
class Monster
{
private:
// 位置
Vec2 m_pos;
// 残り寿命(秒)
double m_lifeTimeSec = 0.0;
public:
Monster() = default;
Monster(const Vec2& pos, double lifeTimeSec)
: m_pos(pos)
, m_lifeTimeSec(lifeTimeSec) {}
// モンスターの更新(残り寿命を減らす)
void update(double timeDeltaSec)
{
m_lifeTimeSec -= timeDeltaSec;
}
const Vec2& getPos() const
{
return m_pos;
}
// まだ残り寿命があれば true
bool isAlive() const
{
return (m_lifeTimeSec > 0.0);
}
};
void Main()
{
// モンスター描画用の絵文字
const Texture monsterTexture(Emoji(U"👾"));
Array<Monster> monsters;
for (int32 i = 0; i < 30; ++i)
{
// 画面上のランダムな場所にランダムな寿命のモンスターを作成
monsters << Monster(RandomVec2(Scene::Rect()), Random(1.0, 8.0));
}
while (System::Update())
{
// 前のフレームからの経過時間
const double timeDeltaSec = Scene::DeltaTime();
for (auto& monster : monsters)
{
monster.update(timeDeltaSec);
}
// 寿命が尽きたモンスターを Array から削除
monsters.remove_if([](const Monster& m){ return !m.isAlive(); });
// モンスターを描画
for (const auto& monster : monsters)
{
monsterTexture.scaled(0.5).drawAt(monster.getPos());
}
}
}
似た名前の関数に注意
Array::removed_if(f)
という関数もありますが、これは削除した結果の新しい Array
を返す関数で、自分自身は変更しません。
# include <Siv3D.hpp>
void Main()
{
Array<int32> v = { 3, 9, 10, 12, 8, 6, 11 };
Print << v.removed_if(IsEven);
Print << v;
while (System::Update())
{
}
}
{3, 9, 11}
{3, 9, 10, 12, 8, 6, 11}