異なる種類の図形同士のあたり判定をチェックする
Siv3D では異なる種類の図形同士の当たり判定チェックが実装されている
コンパイル時に図形の型が決まっている場合は次のようにすることができる:
code:cpp
bool IsColliding(const auto& shape1, const auto& shape2)
{
return shape1.intersects(shape2);
}
// ...
RectF shape1;
Circle shape2;
// ...
if (IsColliding(shape1, shape2))
{
// ...
code:cpp
using ShapesVariant = std::variant<RectF, Circle, Quad>;
bool IsColliding(const ShapesVariant& shapeVariant1, const ShapesVariant& shapeVariant2)
{
return std::visit(&(const auto& shape1) -> bool { return std::visit(&(const auto& shape2) -> bool { return shape1.intersects(shape2);
}, shapeVariant2);
}, shapeVariant1);
}
// ...
ShapesVariant shape1 = RectF{};
ShapesVariant shape2 = Circle{};
// ...
if (IsColliding(shape1, shape2))
{
// ...
Array に格納した様々な図形 (std::variant) のあたり判定をチェックするサンプル:
https://gyazo.com/2f5039a6dbcd13c67f526bfdc3c28698
https://scrapbox.io/files/66e808ac59db2c001db8a5f2.mp4
code:collision_various_shapes.cpp
# include <Siv3D.hpp> // Siv3D v0.6.15
// 図形は RectF, Circle, Quad のどれか
using ShapesVariant = std::variant<RectF, Circle, Quad>;
// 適当に図形を動かす
struct MotionVisitor
{
MotionVisitor(size_t shapeIndex_)
: shapeIndex{ shapeIndex_ }
{
}
Vec2 positionMoveTo() const
{
const SecondsF periodX{ 1.5 + 1.5 * shapeIndex };
const SecondsF periodY{ 2.0 + 1.2 * shapeIndex };
return Scene::CenterF() + Vec2{
Periodic::Sine1_1(periodX) * (120.0 + 70 * shapeIndex),
Periodic::Sine1_1(periodY) * (100.0 + 50 * shapeIndex) };
}
void operator()(Quad& quad) const
{
quad = quad.rotatedAt(quad.boundingRect().center(), 30_deg * Scene::DeltaTime());
quad.moveBy(positionMoveTo() - quad.boundingRect().center());
}
void operator()(auto& shape) const
{
shape.setCenter(positionMoveTo());
}
size_t shapeIndex;
};
// 図形同士が重なっているか
bool IsColliding(const ShapesVariant& shapeVariant1, const ShapesVariant& shapeVariant2)
{
return std::visit(&(const auto& shape1) -> bool { return std::visit(&(const auto& shape2) -> bool { return shape1.intersects(shape2);
}, shapeVariant2);
}, shapeVariant1);
}
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
Array<ShapesVariant> shapes;
shapes.emplace_back(RectF{ 90.0 });
shapes.emplace_back(Circle{ 55.0 });
shapes.emplace_back(RectF{ 120.0 }.rotated(45_deg));
Array<bool> colliding(shapes.size(), false);
while (System::Update())
{
// 適当に図形を動かす
{
std::visit(MotionVisitor{ index }, shapeVariant);
}
// お互いに重なっているか
colliding.fill(false);
for (int iShape1 = 0; iShape1 < shapes.size(); ++iShape1)
{
for (int iShape2 = iShape1 + 1; iShape2 < shapes.size(); ++iShape2)
{
{
}
}
}
// 描画
{
std::visit(&(const auto& shape) { shape.draw(collidingindex ? Palette::Seagreen : Palette::White); }, shapeVariant);
}
}
}