演習 F - 脱出ゲーム¶
脱出ゲームの基本を作ります。
1. 基本¶
# include <Siv3D.hpp>
void Main()
{
Scene::SetBackground(ColorF{ 0.9, 0.85, 0.8 });
const Texture computerTexture{ U"🖥️"_emoji };
const Texture boxTexture{ U"🗃️"_emoji };
const Texture doorTexture{ U"🚪"_emoji };
const Vec2 computerPos{ 200, 300 };
const Vec2 boxPos{ 400, 300 };
const Vec2 doorPos{ 600, 300 };
while (System::Update())
{
computerTexture.drawAt(computerPos);
boxTexture.drawAt(boxPos);
doorTexture.drawAt(doorPos);
if (const Circle circle{ computerPos, 80 };
circle.mouseOver())
{
circle.draw(ColorF{ 1.0, 0.2 });
Cursor::RequestStyle(CursorStyle::Hand);
if (circle.leftClicked())
{
Print << U"パソコンだ。電源は入らない。";
}
}
if (const Circle circle{ boxPos, 80 };
circle.mouseOver())
{
circle.draw(ColorF{ 1.0, 0.2 });
Cursor::RequestStyle(CursorStyle::Hand);
if (circle.leftClicked())
{
Print << U"箱の中に何か入っている。部屋の鍵を見つけた!";
}
}
if (const Circle circle{ doorPos, 80 };
circle.mouseOver())
{
circle.draw(ColorF{ 1.0, 0.2 });
Cursor::RequestStyle(CursorStyle::Hand);
if (circle.leftClicked())
{
Print << U"ドアには鍵がかかっている。出られない。";
}
}
}
}
2. クラス化¶
# include <Siv3D.hpp>
class Item
{
public:
// クラスの初期化のためのメンバ関数(コンストラクタ)
Item(const Emoji& emoji, const Vec2& pos, bool visible)
: m_texture{ emoji }
, m_circle{ pos, 80 }
, m_visible{ visible } {}
// 可視性を変更する
void setVisibility(bool visible)
{
m_visible = visible;
}
// クリックされたかを返す
bool clicked() const
{
if (not m_visible)
{
return false;
}
return m_circle.leftClicked();
}
// 描画する
void draw() const
{
if (not m_visible)
{
return;
}
m_texture.drawAt(m_circle.center);
if (m_circle.mouseOver())
{
Cursor::RequestStyle(CursorStyle::Hand);
m_circle.draw(ColorF{ 1.0, 0.2 });
}
}
private:
Texture m_texture;
Circle m_circle;
bool m_visible;
};
void Main()
{
Scene::SetBackground(ColorF{ 0.9, 0.85, 0.8 });
Item computer{ U"🖥️"_emoji, Vec2{ 200, 300 }, true };
Item box{ U"🗃️"_emoji, Vec2{ 400, 300 }, true };
Item door{ U"🚪"_emoji, Vec2{ 600, 300 }, true };
while (System::Update())
{
computer.draw();
box.draw();
door.draw();
if (computer.clicked())
{
Print << U"パソコンだ。電源は入らない。";
}
if (box.clicked())
{
Print << U"箱の中に何か入っている。部屋の鍵を見つけた!";
}
if (door.clicked())
{
Print << U"ドアには鍵がかかっている。出られない。";
}
}
}
3. イベントの管理¶
# include <Siv3D.hpp>
class Item
{
public:
// クラスの初期化のためのメンバ関数(コンストラクタ)
Item(const Emoji& emoji, const Vec2& pos, bool visible)
: m_texture{ emoji }
, m_circle{ pos, 80 }
, m_visible{ visible } {}
// 可視性を変更する
void setVisibility(bool visible)
{
m_visible = visible;
}
// クリックされたかを返す
bool clicked() const
{
if (not m_visible)
{
return false;
}
return m_circle.leftClicked();
}
// 描画する
void draw() const
{
if (not m_visible)
{
return;
}
m_texture.drawAt(m_circle.center);
if (m_circle.mouseOver())
{
Cursor::RequestStyle(CursorStyle::Hand);
m_circle.draw(ColorF{ 1.0, 0.2 });
}
}
private:
Texture m_texture;
Circle m_circle;
bool m_visible;
};
void Main()
{
Scene::SetBackground(ColorF{ 0.9, 0.85, 0.8 });
Item computer{ U"🖥️"_emoji, Vec2{ 200, 300 }, true };
Item box{ U"🗃️"_emoji, Vec2{ 400, 300 }, true };
Item door{ U"🚪"_emoji, Vec2{ 600, 300 }, true };
Item food{ U"🍲"_emoji, Vec2{ 400, 300 }, false };
// 鍵を持っているかのフラグ
bool hasKey = false;
while (System::Update())
{
computer.draw();
box.draw();
door.draw();
food.draw();
if (computer.clicked())
{
Print << U"パソコンだ。電源は入らない。";
}
if (box.clicked())
{
if (not hasKey)
{
Print << U"箱の中に何か入っている。";
Print << U"[鍵を手に入れた!]";
hasKey = true;
}
else
{
Print << U"箱の中には重要そうなものは入っていない。";
}
}
if (door.clicked())
{
if (not hasKey)
{
Print << U"ドアには鍵がかかっている。出られない。";
}
else
{
Print << U"鍵を使ってドアを開けた!";
computer.setVisibility(false);
box.setVisibility(false);
door.setVisibility(false);
food.setVisibility(true);
}
}
if (food.clicked())
{
Print << U"おいしそうな料理が置かれている。まだ温かい。";
}
}
}
4. メッセージウィンドウの実装¶
# include <Siv3D.hpp>
class Item
{
public:
// クラスの初期化のためのメンバ関数(コンストラクタ)
Item(const Emoji& emoji, const Vec2& pos, bool visible)
: m_texture{ emoji }
, m_circle{ pos, 80 }
, m_visible{ visible } {}
// 可視性を変更する
void setVisibility(bool visible)
{
m_visible = visible;
}
// クリックされたかを返す
bool clicked() const
{
if (not m_visible)
{
return false;
}
return m_circle.leftClicked();
}
// 描画する
void draw() const
{
if (not m_visible)
{
return;
}
m_texture.drawAt(m_circle.center);
if (m_circle.mouseOver())
{
Cursor::RequestStyle(CursorStyle::Hand);
m_circle.draw(ColorF{ 1.0, 0.2 });
}
}
private:
Texture m_texture;
Circle m_circle;
bool m_visible;
};
class MessageWindow
{
public:
void setText(const String& text)
{
m_text = text;
m_stopwatch.restart(); // ストップウォッチを 0 からスタート
}
void draw() const
{
Rect{ 20, 440, 760, 140 }.draw(ColorF{ 0.5, 0.5, 0.5 });
RoundRect{ 30, 450, 740, 120, 10 }.draw();
const int32 count = (m_stopwatch.ms() / 50); // 50 ミリ秒につき 1 文字
m_font(m_text.substr(0, count)).draw(40, 460, ColorF{ 0.1 });
}
private:
Font m_font{ 25 };
String m_text;
Stopwatch m_stopwatch;
};
void Main()
{
Scene::SetBackground(ColorF{ 0.9, 0.85, 0.8 });
Item computer{ U"🖥️"_emoji, Vec2{ 200, 300 }, true };
Item box{ U"🗃️"_emoji, Vec2{ 400, 300 }, true };
Item door{ U"🚪"_emoji, Vec2{ 600, 300 }, true };
Item food{ U"🍲"_emoji, Vec2{ 400, 300 }, false };
MessageWindow messageWindow;
bool hasKey = false;
while (System::Update())
{
computer.draw();
box.draw();
door.draw();
food.draw();
if (computer.clicked())
{
messageWindow.setText(U"パソコンだ。電源は入らない。");
}
if (box.clicked())
{
if (not hasKey)
{
messageWindow.setText(U"箱の中に何か入っている。\n[鍵を手に入れた!]");
hasKey = true;
}
else
{
messageWindow.setText(U"箱の中には重要そうなものは入っていない。");
}
}
if (door.clicked())
{
if (not hasKey)
{
messageWindow.setText(U"ドアには鍵がかかっている。出られない。");
}
else
{
messageWindow.setText(U"鍵を使ってドアを開けた!");
computer.setVisibility(false);
box.setVisibility(false);
door.setVisibility(false);
food.setVisibility(true);
}
}
if (food.clicked())
{
messageWindow.setText(U"おいしそうな料理が置かれている。まだ温かい。");
}
messageWindow.draw();
}
}