勉強会 8 コマ目(配列と図形の交差)
1. 配列を使う
1.1 配列の使い方
Siv3D
では std::vector<T>
の代わりに Array<T>
を使います。
Array
は、v.push_back(x);
の代わりに v << x;
と記述できるなど、便利な機能がいくつか追加されています。
#include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.8, 0.9, 1.0 });
const Font font{ FontMethod::MSDF, 48 };
// std::vector<int> に相当する
Array<int32> v = { 10, 20, 30, 40 };
// v.push_back(50) と同じ
v << 50;
// v.push_back(60) と同じ
v << 60;
while (System::Update())
{
font(U"v: {}"_fmt(v)).draw(30, 20, 20, Palette::Black);
}
}
1.2 配列の要素数
- 配列の要素数を調べる場合は
.size()
を使います。
#include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.8, 0.9, 1.0 });
const Font font{ FontMethod::MSDF, 48 };
Array<int32> v;
while (System::Update())
{
font(U"v: {}"_fmt(v)).draw(30, 20, 20, Palette::Black);
font(U"要素数: {}"_fmt(v.size())).draw(30, 20, 60, Palette::Black);
// もし左クリックされたら
if (MouseL.down())
{
// 0 以上 100 以下のランダムな整数を追加する
v << Random(0, 100);
}
}
}
1.3 すべての値を調べる
for (const auto& elem : v)
による繰り返しで各要素にアクセスします。
#include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.8, 0.9, 1.0 });
const Font font{ FontMethod::MSDF, 48 };
Array<double> xs = { 100, 200, 300, 500 };
while (System::Update())
{
font(U"xs: {}"_fmt(xs)).draw(30, 20, 20, Palette::Black);
for (const auto& x : xs)
{
Circle{ x, 300, 30 }.draw();
}
}
}
1.4 すべての値を変更する
for (auto& elem : v)
による繰り返しで各要素にアクセスしつつ、要素を変更できます。
#include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.8, 0.9, 1.0 });
const Font font{ FontMethod::MSDF, 48 };
Array<double> xs = { 100, 200, 300, 500 };
while (System::Update())
{
font(U"xs: {}"_fmt(xs)).draw(30, 20, 20, Palette::Black);
for (const auto& x : xs)
{
Circle{ x, 300, 30 }.draw();
}
for (auto& x : xs) // 配列の各要素を変更する場合 const を付けない
{
x += 1.0;
}
}
}
2. クラスを配列に追加する
2.1 Circle の配列 (1)
#include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.8, 0.9, 1.0 });
Array<Circle> circles;
while (System::Update())
{
if (MouseL.down())
{
circles << Circle{ Cursor::Pos(), Random(10, 30) };
}
for (const auto& circle : circles)
{
circle.draw();
}
}
}
2.2 Circle の配列 (2)
#include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.8, 0.9, 1.0 });
Array<Circle> circles;
// 蓄積された時間(秒)
double accumulatedTime = 0.0;
while (System::Update())
{
double deltaTime = Scene::DeltaTime();
accumulatedTime += deltaTime;
// 蓄積時間が一定時間を超えたら
if (0.5 <= accumulatedTime)
{
circles << Circle{ Cursor::Pos(), Random(10, 30) };
// 蓄積時間からマイナス
accumulatedTime -= 0.5;
}
for (const auto& circle : circles)
{
circle.draw();
}
}
}
2.3 Circle の配列 (3)
- スペースキーを押したとき、円を配列に追加するサンプルです。
#include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.8, 0.9, 1.0 });
const Texture emoji{ U"🤠"_emoji };
Array<Circle> circles;
// プレイヤーの X 座標
double playerPosX = 400;
while (System::Update())
{
// ← キーを押したら
if (KeyLeft.pressed())
{
// 左へ移動
playerPosX -= 3.0;
}
// → キーを押したら
if (KeyRight.pressed())
{
// 右へ移動
playerPosX += 3.0;
}
// スペースキーを押したら
if (KeySpace.down())
{
// 配列に円を追加
circles << Circle{ playerPosX, 420, 10 };
}
// すべての円を移動させる
for (auto& circle : circles)
{
circle.y -= 4.0;
}
// すべての円を描く
for (const auto& circle : circles)
{
circle.draw(Palette::Gray);
}
// 絵文字を描く
emoji.drawAt(playerPosX, 500);
}
}
3. 配列から要素を削除する
3.1 配列から要素を削除する
Array
は、.remove_if(チェック関数)
を使うことで、チェックに引っかかる要素を配列から削除できます。
- チェック関数の戻り値は
bool
型、引数は配列の要素と同じ型にします。
#include <Siv3D.hpp>
// 偶数であるかをチェックする関数
bool CheckInt(int32 n)
{
return (n % 2 == 0);
}
void Main()
{
Scene::SetBackground(ColorF{ 0.8, 0.9, 1.0 });
Array<int32> v = { 1, 2, 3, 4, 5, 6 };
Print << v;
// チェックに引っかかる要素を配列から削除する
v.remove_if(CheckInt);
Print << v;
while (System::Update())
{
}
}
3.2 配列からチェックに引っかかる円を削除する
#include <Siv3D.hpp>
// 円の Y 座標が 100 未満であるかをチェックする関数
bool CheckCircle(const Circle& circle)
{
return circle.y < 100;
}
void Main()
{
Scene::SetBackground(ColorF{ 0.8, 0.9, 1.0 });
const Texture emoji{ U"🤠"_emoji };
Array<Circle> circles;
// プレイヤーの X 座標
double playerPosX = 400;
while (System::Update())
{
// ← キーを押したら
if (KeyLeft.pressed())
{
// 左へ移動
playerPosX -= 3.0;
}
// → キーを押したら
if (KeyRight.pressed())
{
// 右へ移動
playerPosX += 3.0;
}
// スペースキーを押したら
if (KeySpace.down())
{
// 配列に円を追加
circles << Circle{ playerPosX, 420, 10 };
}
// すべての円を移動させる
for (auto& circle : circles)
{
circle.y -= 4.0;
}
// チェックに引っかかる要素を配列から削除する
circles.remove_if(CheckCircle);
// すべての円を描く
for (const auto& circle : circles)
{
circle.draw(Palette::Gray);
}
// 絵文字を描く
emoji.drawAt(playerPosX, 500);
}
}
4. 図形同士の交差を調べる
4.1 図形同士の交差
- 図形 A と 図形 B が重なっているかは
if (A.intersects(B))
で調べられます。
#include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.8, 0.9, 1.0 });
const Font font{ FontMethod::MSDF, 48 };
Circle enemyCircle{ 400, 200, 100 };
while (System::Update())
{
const Circle bulletCircle{ Cursor::Pos(), 20};
enemyCircle.draw();
bulletCircle.draw(Palette::Gray);
// もし 2 つの Circle が交差している場合
if (enemyCircle.intersects(bulletCircle))
{
font(U"交差").draw(30, 20, 20, Palette::Black);
}
}
}
4.2 複数の図形との交差判定 (1)
#include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.8, 0.9, 1.0 });
const Font font{ FontMethod::MSDF, 48 };
Array<Circle> enemyCircles = {
Circle{ 200, 200, 60 },
Circle{ 400, 200, 60 },
Circle{ 600, 200, 60 },
};
while (System::Update())
{
const Circle bulletCircle{ Cursor::Pos(), 20};
// 各 enemyCircle について
for (auto& enemyCircle : enemyCircles)
{
// もし 2 つの Circle が交差している場合
if (enemyCircle.intersects(bulletCircle))
{
font(U"交差").draw(30, 20, 20, Palette::Black);
}
}
for (const auto& enemyCircle : enemyCircles)
{
enemyCircle.draw();
}
bulletCircle.draw(Palette::Gray);
}
}
4.3 複数の図形との交差判定 (2)
- 複数の図形と交差判定をし、交差した円を削除するサンプルです。
- 交差した円の Y 座標を
-999
に変更することで、その後のチェックに引っかかるようにし、配列から削除します。
#include <Siv3D.hpp>
// 円の Y 座標が 100 未満であるかをチェックする関数
bool CheckCircle(const Circle& circle)
{
return circle.y < 100;
}
void Main()
{
Scene::SetBackground(ColorF{ 0.8, 0.9, 1.0 });
const Font font{ FontMethod::MSDF, 48 };
Array<Circle> enemyCircles = {
Circle{ 200, 200, 60 },
Circle{ 400, 200, 60 },
Circle{ 600, 200, 60 },
};
while (System::Update())
{
font(U"enemyCircles: {}"_fmt(enemyCircles)).draw(15, 20, 20, Palette::Black);
const Circle bulletCircle{ Cursor::Pos(), 20};
// 各 enemyCircle について
for (auto& enemyCircle : enemyCircles)
{
// もし 2 つの Circle が交差している場合
if (enemyCircle.intersects(bulletCircle))
{
// その enemyCircle の Y 座標を -999 に変更する
enemyCircle.y = -999;
}
}
// チェックに引っかかる要素を配列から削除する
enemyCircles.remove_if(CheckCircle);
for (const auto& enemyCircle : enemyCircles)
{
enemyCircle.draw();
}
bulletCircle.draw(Palette::Gray);
}
}