-
-
Save Reputeless/e143b30d0926e402ed287df838e43de8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# include <Siv3D.hpp> | |
/// @brief ガチャを行うクラス | |
class GachaMachine | |
{ | |
public: | |
GachaMachine() = default; | |
/// @brief ガチャを行うクラスを作成します。 | |
/// @param items アイテムとその出現比率のペアの配列 | |
/// @param cooldownTime ガチャのクールダウン時間(デフォルト: 0.5 秒) | |
explicit GachaMachine(const Array<std::pair<String, double>>& items, const Duration& cooldownTime = 0.5s) | |
: m_distribution{ items.map([](const auto& item) { return item.second; }) } | |
, m_probabilities{ m_distribution.probabilities() } | |
, m_itemNames{ items.map([](const auto& item) { return item.first; }) } | |
, m_cooldownTimer{ cooldownTime } {} | |
/// @brief ガチャのアイテム数を返します。 | |
/// @return ガチャのアイテム数 | |
[[nodiscard]] | |
size_t num_items() const | |
{ | |
return m_probabilities.size(); | |
} | |
/// @brief ガチャのアイテムの出現確率を返します。 | |
/// @param index アイテムのインデックス | |
/// @return アイテムの出現確率 | |
[[nodiscard]] | |
double getProbability(size_t index) const | |
{ | |
return m_probabilities[index]; | |
} | |
/// @brief ガチャのアイテムの出現確率の一覧を返します。 | |
/// @return アイテムの出現確率の一覧 | |
[[nodiscard]] | |
const Array<double>& getProbabilities() const | |
{ | |
return m_probabilities; | |
} | |
/// @brief ガチャのアイテムの名前を返します。 | |
/// @param index アイテムのインデックス | |
/// @return アイテムの名前 | |
[[nodiscard]] | |
const String& getItemName(size_t index) const | |
{ | |
return m_itemNames[index]; | |
} | |
/// @brief ガチャのアイテムの名前の一覧を返します。 | |
/// @return アイテムの名前の一覧 | |
[[nodiscard]] | |
const Array<String>& getItemNames() const | |
{ | |
return m_itemNames; | |
} | |
/// @brief ガチャを行い、結果を返します。 | |
/// @return ガチャの結果 | |
[[nodiscard]] | |
int32 getResult() const | |
{ | |
m_cooldownTimer.restart(); | |
return static_cast<int32>(m_distribution(GetDefaultRNG())); | |
} | |
/// @brief ガチャを複数回行い、結果を返します。 | |
/// @param n ガチャを行う回数 | |
/// @return ガチャの結果の配列 | |
[[nodiscard]] | |
Array<int32> getResults(size_t n) const | |
{ | |
return Array<int32>::Generate(n, [this]() { return getResult(); }); | |
} | |
/// @brief ガチャがクールダウン中であるかを返します。 | |
/// @return クールダウン中の場合 true, それ以外の場合は false | |
[[nodiscard]] | |
bool isCoolingDown() const | |
{ | |
return m_cooldownTimer.isRunning(); | |
} | |
/// @brief クールダウンの進捗を [0.0, 1.0] の範囲で返します。 | |
/// @return クールダウンの進捗 | |
[[nodiscard]] | |
double getCoolDownProgress() const | |
{ | |
return m_cooldownTimer.progress0_1(); | |
} | |
private: | |
mutable DiscreteDistribution m_distribution; | |
Array<double> m_probabilities; | |
Array<String> m_itemNames; | |
mutable Timer m_cooldownTimer; | |
}; | |
void Main() | |
{ | |
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 }); | |
// フォント | |
const Font font{ FontMethod::MSDF, 48, Typeface::Heavy }; | |
// ガチャのアイテムと出現比率、クールダウン時間を設定する | |
const GachaMachine gachaMachine{ { | |
{ U"はずれ", 1000 }, | |
{ U"ブロンズ", 100 }, | |
{ U"シルバー", 10 }, | |
{ U"ゴールド", 1 }}, | |
0.4s }; | |
// アイテムの確率を表示する | |
for (size_t i = 0; i < gachaMachine.num_items(); ++i) | |
{ | |
Print << U"「{}」の確率: {:.2f}%"_fmt(gachaMachine.getItemName(i), (gachaMachine.getProbability(i) * 100)); | |
} | |
// ダイヤの数 | |
int32 diamonds = 35; | |
// 直前のガチャの結果を格納する配列 | |
Array<int32> lastResults; | |
while (System::Update()) | |
{ | |
if (SimpleGUI::Button(U"\U000F01C8 {}"_fmt(diamonds), Vec2{ 300, 40 }, 100, (not gachaMachine.isCoolingDown()))) | |
{ | |
// ダイヤを購入する処理など | |
diamonds += 100; | |
} | |
if (SimpleGUI::Button(U"1 回ガチャ \U000F01C8 × 1", Vec2{ 300, 80 }, 200, (lastResults.isEmpty() && (1 <= diamonds)))) | |
{ | |
--diamonds; | |
lastResults = gachaMachine.getResults(1); // 引いた瞬間に結果を取得する | |
} | |
if (SimpleGUI::Button(U"5 回ガチャ \U000F01C8 × 5", Vec2{ 520, 80 }, 200, (lastResults.isEmpty() && (5 <= diamonds)))) | |
{ | |
diamonds -= 5; | |
lastResults = gachaMachine.getResults(5); // 引いた瞬間に結果を取得する | |
} | |
// 各ガチャ結果について | |
for (int32 i = 0; i < static_cast<int32>(lastResults.size()); ++i) | |
{ | |
const RectF rect{ 300, (160 + i * 50), (gachaMachine.getCoolDownProgress() * 300), 45 }; | |
// そのアイテムの出現率を取得する | |
const double probability = gachaMachine.getProbability(lastResults[i]); | |
// 出現率に応じて背景色を変える | |
if (probability < 0.1) // 10% 未満 | |
{ | |
rect.draw(ColorF{ 1.0, 0.8, 0.6 }); | |
} | |
else | |
{ | |
rect.draw(ColorF{ 0.9 }); | |
} | |
// クールダウン完了後に | |
if (not gachaMachine.isCoolingDown()) | |
{ | |
// アイテム名を表示する | |
font(gachaMachine.getItemName(lastResults[i])).drawAt(30, rect.center(), ColorF{ 0.11 }); | |
} | |
} | |
if (lastResults && (not gachaMachine.isCoolingDown())) | |
{ | |
if (SimpleGUI::Button(U"アイテムを受け取る", Vec2{ 300, 440 }, 300)) | |
{ | |
// ガチャ結果のアイテムを受け取る処理など | |
lastResults.clear(); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment