マウスで円をつかんで動かす - Siv3D/Reference-JP GitHub Wiki

1. 基本

# include <Siv3D.hpp>

void Main()
{
	Circle circle(200, 200, 50);

	// つかんでいたら true, そうでない場合は false
	bool grabbed = false;

	while (System::Update())
	{
		if (circle.leftClicked)
		{
			// 円をクリックしたらつかむ
			grabbed = true;
		}
		else if (Input::MouseL.released)
		{
			// マウスの左クリックが離されたら離す
			grabbed = false;
		}
		else if (grabbed)
		{
			// つかんでいる間はマウスの移動量分だけ円を動かす
			circle.moveBy(Mouse::Delta());
		}

		circle.draw(Palette::Skyblue);
	}
}

2. つかめる場合はカーソルを手の形にする

# include <Siv3D.hpp>

void Main()
{
	Circle circle(200, 200, 50);

	bool grabbed = false;

	while (System::Update())
	{
		if (circle.leftClicked)
		{
			grabbed = true;
		}
		else if (Input::MouseL.released)
		{
			grabbed = false;
		}
		else if (grabbed)
		{
			circle.moveBy(Mouse::Delta());
		}

		// カーソルのアイコンを手の形にするなら true, そうでない場合は false
		const bool handCursor = circle.mouseOver;

		Cursor::SetStyle(handCursor ? CursorStyle::Hand : CursorStyle::Default);

		circle.draw(Palette::Skyblue);
	}
}

3. つかんでいる間は影を付ける

# include <Siv3D.hpp>

void Main()
{
	// 背景色を白に
	Graphics::SetBackground(Palette::White);

	Circle circle(200, 200, 50);

	bool grabbed = false;

	while (System::Update())
	{
		if (circle.leftClicked)
		{
			grabbed = true;
		}
		else if (Input::MouseL.released)
		{
			grabbed = false;
		}
		else if (grabbed)
		{
			circle.moveBy(Mouse::Delta());
		}

		const bool handCursor = circle.mouseOver;

		Cursor::SetStyle(handCursor ? CursorStyle::Hand : CursorStyle::Default);

		if (grabbed)
		{
			// つかんでいる場合、円の影を描く
			circle.drawShadow({ 0,2 }, 12, 3);
		}

		circle.draw(Palette::Skyblue);
	}
}

4. クラスにまとめる

# include <Siv3D.hpp>

class GrabCircle
{
private:

	Circle m_circle;

	Color m_color;

	bool m_grabbed = false;

public:

	GrabCircle() = default;

	explicit GrabCircle(const Circle& circle)
		: m_circle(circle)
		, m_color(RandomColor()) {}

	const Circle& getCircle() const
	{
		return m_circle;
	}

	void update()
	{
		if (m_circle.leftClicked)
		{
			m_grabbed = true;
		}
		else if (Input::MouseL.released)
		{
			m_grabbed = false;
		}
		else if (m_grabbed)
		{
			m_circle.moveBy(Mouse::Delta());
		}
	}

	void draw() const
	{
		if (m_grabbed)
		{
			m_circle.drawShadow({ 0,2 }, 12, 3);
		}

		m_circle.draw(m_color);
	}
};

void Main()
{
	Graphics::SetBackground(Palette::White);

	GrabCircle circle(Circle(200, 200, 50));

	while (System::Update())
	{
		circle.update();

		circle.draw();

		const bool handCursor = circle.getCircle().mouseOver;

		Cursor::SetStyle(handCursor ? CursorStyle::Hand : CursorStyle::Default);
	}
}

5. 複数の円を扱う

# include <Siv3D.hpp>

class GrabCircle
{
private:

	Circle m_circle;

	Color m_color;

	bool m_grabbed = false;

public:

	GrabCircle() = default;

	explicit GrabCircle(const Circle& circle)
		: m_circle(circle)
		, m_color(RandomColor()) {}

	const Circle& getCircle() const
	{
		return m_circle;
	}

	void update()
	{
		if (m_circle.leftClicked)
		{
			m_grabbed = true;
		}
		else if (Input::MouseL.released)
		{
			m_grabbed = false;
		}
		else if (m_grabbed)
		{
			m_circle.moveBy(Mouse::Delta());
		}
	}

	void draw() const
	{
		if (m_grabbed)
		{
			m_circle.drawShadow({ 0,2 }, 12, 3);
		}

		m_circle.draw(m_color);
	}
};

void Main()
{
	Graphics::SetBackground(Palette::White);

	Array<GrabCircle> circles = 
	{
		GrabCircle(Circle(100, 100, 50)),
		GrabCircle(Circle(300, 100, 50)),
		GrabCircle(Circle(500, 100, 50)),
		GrabCircle(Circle(300, 300, 50)),
	};

	while (System::Update())
	{
		for (auto& circle : circles)
		{
			circle.update();
		}

		for (const auto& circle : circles)
		{
			circle.draw();
		}

		bool handCursor = false;

		for (const auto& circle : circles)
		{
			if (circle.getCircle().mouseOver)
			{
				handCursor = true;
				break;
			}
		}

		Cursor::SetStyle(handCursor ? CursorStyle::Hand : CursorStyle::Default);
	}
}

6. 重なり順を考慮する

# include <Siv3D.hpp>

class GrabCircle
{
private:

	Circle m_circle;

	Color m_color;

	// 最後につかまれた時刻(ミリ秒)
	uint32 m_lastUpdateTimeSec = 0;

	bool m_grabbed = false;

public:

	GrabCircle() = default;

	explicit GrabCircle(const Circle& circle)
		: m_circle(circle)
		, m_color(RandomColor()) {}

	const Circle& getCircle() const
	{
		return m_circle;
	}

	bool update()
	{
		if (m_circle.leftClicked)
		{
			m_grabbed = true;

			m_lastUpdateTimeSec = Time::GetMillisec();

			return true;
		}
		else if (Input::MouseL.released)
		{
			m_grabbed = false;
		}
		else if (m_grabbed)
		{
			m_circle.moveBy(Mouse::Delta());
		}

		return false;
	}

	void draw() const
	{
		if (m_grabbed)
		{
			m_circle.drawShadow({ 0,2 }, 12, 3);
		}

		m_circle.draw(m_color);
	}

	uint32 getLastUpdateTime() const
	{
		return m_lastUpdateTimeSec;
	}
};

void Main()
{
	Graphics::SetBackground(Palette::White);

	Array<GrabCircle> circles = 
	{
		GrabCircle(Circle(100, 100, 50)),
		GrabCircle(Circle(300, 100, 50)),
		GrabCircle(Circle(500, 100, 50)),
		GrabCircle(Circle(300, 300, 50)),
	};

	while (System::Update())
	{
		for (auto& circle : circles)
		{
			// 1 つの円がつかまれたら、それ以外の円は処理しない
			if (circle.update())
			{
				break;
			}
		}

		// 最後につかんだ円が配列の先頭にくるようにソートする
		std::sort(circles.begin(), circles.end(),[](const GrabCircle& a, const GrabCircle& b)
		{
			return a.getLastUpdateTime() > b.getLastUpdateTime();
		});

		// 下の円から順に描く
		for (auto it = circles.rbegin(); it != circles.rend(); ++it)
		{
			it->draw();
		}

		bool handCursor = false;

		for (const auto& circle : circles)
		{
			if (circle.getCircle().mouseOver)
			{
				handCursor = true;
				break;
			}
		}

		Cursor::SetStyle(handCursor ? CursorStyle::Hand : CursorStyle::Default);
	}
}
⚠️ **GitHub.com Fallback** ⚠️