상품 설명
■ クエストシステムの実装は、なぜ毎回こんなに大変なのか
「敵を10体倒す」だけなら簡単です。
ですが実際に作り始めると、こうなります。
・「ステージ1のボスに2回勝利かつ 金貨を300集める」という複合条件が欲しい
・敵を1種類追加するたびに、クエスト側の判定コードも書き足すことになった
・デイリー任務を実装したら、アプリを閉じている間に日付が変わってリセットされない
・前のクエストをクリアすると次が解放される「任務ツリー」を後から足したくなった
・進捗をセーブに乗せたいが、クエスト用に別のセーブファイルは増やしたくない
・クエストログUIは自分のゲームのデザインで作りたい
このアセットは、その全部を引き受けます。
ゲーム側が書くのは 1 行だけです。
quests.Report("enemy.defeated", "slime");
どのクエストがこれを数えるかは、クエストアセット側の条件が決めます。
つまり クエストを100件追加しても、この通知コードは1行も増えません。
同梱の実演シーンは、メニュー1クリックで構築 → 再生ボタンを押すだけで、
全機能が18ステップの字幕付きで自動再生されます。
画面内で時計を進めるので、デイリー任務が翌日リセットされるところまでその場で見られます。
■ 作れるクエスト(すべてインスペクタ入力・コード不要)
【達成条件】
・スライムを3体倒す … 対象IDで指定
・アンデッドを5体倒す … タグ指定(敵IDを列挙しなくてよい)
・アンデッド以外を5体倒す … 除外タグ
・金貨を合計300枚集める … 数量の合計
・最大コンボ25に到達する … 最大値の到達
・1-4 をボス戦かつS勝利で2回 … ランク下限+状況フラグ
【条件の結合】
・All … 全条件を満たすと達成(AND)
・Any … いずれか1つで達成(OR)
・AtLeast … 3つのうち2つ以上で達成
【周回とリセット】
・1度限り/無限周回/1日3回まで(回数上限つき周回)
・デイリー(毎日5時更新)/ウィークリー(月曜更新)/マンスリー/6時間ごと
・ローカル時間基準・UTC基準(世界同時更新)を選択可能
【解放ツリー】
・前提クエストをクリアすると解放。分岐ルート(どちらかをクリアで解放)も可
・未解放クエストは進捗を積まないので、先の任務が勝手に進むことがない
・隠しクエスト(解放されるまで一覧に出ない)
【編成条件】
・「主人公をリーダーに、回復役と魔法使いを入れたちょうど3人編成」
・1人が2枠を兼任しないよう解決するので、指名キャラが汎用枠に吸われる事故が起きません
■ リセットは「タイマー」ではありません
デイリー任務でよくある実装ミスが、経過時間タイマーです。
アプリを閉じている間は時間が進まないため、日付が変わってもリセットされません。
本アセットは「今が属する周期の開始時刻」を求め、セーブされた値と違えばリセットする方式です。
3か月ぶりに起動しても、デイリーは1回だけ・ウィークリーも1回だけ、正しくリセットされます。
■ セーブもUIも、既存のものをそのまま使えます
購入をためらう最大の理由は「今あるセーブ機構やUIを作り直すことになるのでは」だと思います。
そうはなりません。
【セーブ】
保存先は差し替え式です。PlayerPrefs・JSONファイルの実装を同梱していますが、
最も多いのは「自分のセーブデータに埋め込む」形です。
// セーブ時
mySaveData.questJson = store.ToJson();
// ロード時
store.LoadFromJson(mySaveData.questJson);
進捗データは public フィールドのみで構成しているので、JsonUtility でも自作シリアライザでも扱えます。
一度も進捗が動いていないクエストはレコードを作らないため、数百件追加してもセーブは太りません。
【UI】
UIプレハブは同梱していません。クエストログの見た目はゲームの個性そのもので、
既製UIはほぼ確実に作り直しになるからです。
代わりに、UIが欲しがる値を全て計算して返します。
var s = quests.GetSnapshot(quest);
gauge.fillAmount = s.Ratio; // 0〜1
countText.text = QuestProgressFormatter.FormatProgress(s); // "3 / 5"
claimButton.SetActive(s.IsClaimable);
resetText.text = QuestProgressFormatter.FormatTimeUntilReset(s); // "5h 12m"
任務ツリー画面も、座標計算だけを提供しています(描画方法は自由です)。
var graph = QuestTreeLayout.Build(quests.GetQuests("story", includeLocked: true));
foreach (var node in graph.Nodes)
Instantiate(nodePrefab, content).anchoredPosition = node.Position;
【独自ルール】
データで表現しきれない条件は、アセットを改造せずに差し込めます。
quests.EventFilter = (quest, evt) => !IsDuplicateKill(evt) && IsEventPeriod();
サーバー時刻を正にしたい場合は IQuestClock を実装するだけです(端末時計を進める不正対策)。
■ 導入は3ステップ
1) Project → Create → UnitForge → Quest でクエストを作る(インスペクタ入力のみ)
2) メニューからレジストリを作成する(以後クエストは自動収集。手作業のドラッグは不要)
3) 初期化して通知する
var quests = new QuestService(QuestRegistry.LoadDefault(),
new PlayerPrefsQuestProgressStore());
quests.RewardHandler = myInventory; // 報酬の付与先(あなたのインベントリ)
quests.Report("enemy.defeated", "slime");
■ 動作確認メニューを同梱しています
Tools → UnitForge → Quests → Run Self-Test (動作確認)
あなたのUnityバージョン・プラットフォーム設定で正しく動くかを、その場で検証して結果を出力します。
検証はすべてメモリ上で行われ、プロジェクトにアセットもセーブデータも作りません。
導入直後、Unityのバージョン更新後、自分で拡張したあとの確認にお使いください。
■ 動作環境
・Unity 2022.3 LTS 以降
・追加パッケージ不要(純粋なUnityのみ/DOTween等のプラグイン不要)
・Input System はどちらの設定でも動作します(入力を一切使いません)
・2D/3D、URP/HDRP/ビルトイン、いずれでも動作します(描画に関与しないため)
■ 収録内容
・Runtime 一式(フルソース・アセンブリ定義で分離)
・エディタ拡張(クエスト用インスペクタ/条件の折りたたみ表示/行動キーのドロップダウン/
レジストリ自動収集とビルド直前の自動焼き込み)
・実演シーン(メニュー1クリックで構築・18ステップ自動再生・削除可)
・最小構成のサンプル4種(初期化/報酬付与/クエストログUI/編成通知)
・動作確認メニュー(自己診断)
・日本語+英語のドキュメント(README・XMLコメント・インスペクタのツールチップすべて日英併記)
■ FAQ・制限事項(正直に記載します)
Q. UIプレハブは入っていますか?
A. 入っていません(上記の理由)。表示に必要な値は全てAPIから取得できます。
実演シーンのクエストログは動く実装例として読めます。
Q. オンラインゲームで使えますか?
A. 進捗の正当性検証はサーバー側の責任になります。
IQuestClock と IQuestProgressStore を差し替えることで組み込めます。
Q. ローカライズは?
A. ローカライズ機構は含みません。クエスト名・説明は文字列なので、
既存の手法(Unity Localization 等)で差し替えてください。
Q. 編成条件は複数部隊にまたがって判定できますか?
A. 1回の判定は1つのパーティが対象です。部隊ごとに通知を呼び分けてください。
Q. 既存のクエストシステムから移行できますか?
A. 進捗データの構造が単純(クエストID・条件別カウント・状態)なので、
旧データからの変換スクリプトを書く形で移行できます。
■ ライセンス
購入者本人および購入者が所属する組織での、商用・非商用を問わないゲーム開発にご利用いただけます。
ソースコードの改変は自由です。アセット自体の再配布・再販売はご遠慮ください。
모든 리뷰
더보기리뷰 등록
리뷰를 작성하려면 로그인이 필요합니다.
로그인하고 리뷰 쓰기