LoginSignup
0
0

More than 1 year has passed since last update.

Unity TopDownEngineのAchievementsのドキュメントとコードを読んだ

Last updated at Posted at 2022-02-26

筆者のステータス

ゲームを作りたくなってTopDownEngineを衝動買いしたけどUnityまったく未経験につき一瞬で挫折。デモ(MinimalSandbox3D)の起動で止まっているので、とりあえずTopDownEngineのドキュメントとコードを読もうかなと思いました。という状態です。(したがって想定読者層は私と同じようなUnity未経験者です。)
Achievements
Unityのバージョンは2020.3.30f1
TopDownEngineのバージョンは2.3.1

Achievementsとは

よくゲームで、本筋とは別に「敵を○○体撃破した!」みたいな実績が解除されていくアレです。たとえば、MinimalSandbox3Dでは10回ジャンプしたら画面の右下に"Jump Around"と書かれた四角いやつが出てきて、実績が解除されます。
もし手元の環境で10回ジャンプしても何も出てこない場合は、既に実績が解除されてしまっている可能性があるので、メニューバーからTools > More Mountains > Reset all achievementsを選択してリセットしてみてください。

AchievementList.asset

まずは↓を読みました。

ProjectビューからCommon/Resources/Achievementsの中にAchievementListっていうassetがあって、それを選ぶとInspectorビューにAchievementsが表示されます。
Achievement List
リストはResourcesフォルダ内にないとUnityがリストをロードできないから注意なんだそうです。

リストにあるAchievementsのうち、"SteppingStone"というのを開いてみました。ここで表示される実績のタイトルや説明を変更できそうです。Achievement TypeにはSimpleとProgressの2種類があって、Progressを使用する場合はProgressTargetを必ず指定する必要があるそうです。実績を解除できるのは1回までで、リセットするまで保持されます。 実績解除はコードのどこでも実装できるけど、AchievementRuleクラスに書くのがお勧めとのことです。

AchievementsRules.cs

HierarchyビューのMinimalSandbox3D/Managers/AchievementRulesから、あるいは直接Common/Scripts/Achievements/AchievementsRules.csからコードを見ることができます。

AchievementRules

具体的なことはドキュメントには記載がなかったですが、リファレンスの方に載ってました。

AchievementRules.csに書かれているAchievementRulesクラスの定義を見ると、MMAchievementRulesクラス(これがbase classらしい)と複数のイベントリスナーを継承していました。リファレンスに書いてあるとおりです(doxygenだから当たり前か)。

AchievementRules.csより
/// <summary>
/// This class describes how the Top Down Engine demo achievements are triggered.
/// It extends the base class MMAchievementRules
/// It listens for different event types
/// </summary>
public class AchievementRules : MMAchievementRules, 
								MMEventListener<MMGameEvent>, 
								MMEventListener<MMCharacterEvent>, 
								MMEventListener<TopDownEngineEvent>,
								MMEventListener<MMStateChangeEvent<CharacterStates.MovementStates>>,
								MMEventListener<MMStateChangeEvent<CharacterStates.CharacterConditions>>,
                                MMEventListener<PickableItemEvent>,
                                MMEventListener<CheckPointEvent>,
                                MMEventListener<MMInventoryEvent>
{
...<後略>

引き続きAchievementRules.csの中を読んでいくと、理解できる所を見つけられました。

AchievementRules.csより
public virtual void OnMMEvent(MMCharacterEvent characterEvent)
{
	if (characterEvent.TargetCharacter.CharacterType == Character.CharacterTypes.Player)
	{
		switch (characterEvent.EventType)
		{
			case MMCharacterEventTypes.Jump:
				MMAchievementManager.AddProgress ("JumpAround", 1);
				break;
		}	
	}
}

上のコードは、characterEventをトリガにして、EventTypeがJumpなら"JumpAround"のProgressを1進める。という処理のようです。ためしにMMAchievementManager.AddProgress ("JumpAround", 2);に書き換えると、キャラクターが1回ジャンプするごとに"JumpAround"のProgressが2加算され、その結果5回ジャンプしただけで実績が解除されました。
ちなみにJumpというイベントトリガは、Common/Scripts/Characters/Core/CharacterEvents.csに定義らしきものがありましたが、今は深追いしないことにします。

AchievementRules.csより
public virtual void OnMMEvent(CheckPointEvent checkPointEvent)
{
    if (checkPointEvent.Order > 0)
    {
        MMAchievementManager.UnlockAchievement("SteppingStone");
    }
}

上のコードでは、checkPointEventをトリガにして、Orderが0より大きければ実績が解除されるみたいです。ためしにチェックポイントを追加してみました。(コアラ2DのDemoを見てマネしました)。

  1. Levelの下にCreate EmptyでCheckPointAという空のオブジェクトを作成(一応Create Empty ParentでCheckPointsも作成)
  2. CheckPointAにAdd ComponentでBox Colliderを追加
  3. Is Triggerにチェック
  4. Box Colliderのサイズを3×3×3に変更
  5. Scene上で見やすいようにアイコンを選択(多分必須ではない操作)
  6. さらにAdd ComponentでCheckpointを追加
  7. Check Point Orderを1に変更

Adding check point
これで、キャラクターがCheckPointAに行くと"SteppingStone"の実績が解除されました。これが正しい手順なのかはまだ不明ですが、今は深追いしないことにします。

AchievementDisplay

ドキュメントには細かい説明がなく、コード見たり色々触って徐々にわかりはじめました。AchievementDisplayは3つのファイル(もっとあるかも)で構成されています。

AchievementDisplay.prefab

実績解除時に画面に表示される四角いやつはThirdParty/MoreMountains/MMTools/Tools/MMAchievements/Prefabsの中にAchievementDisplayというprefabで位置や寸法やレイアウトが定義されています。
AchievementDisplay

MMAchievementDisplayItem.cs

さっきのAchievementDisplay.prefabのInspectorビューに、MMAchievementDisplayItemというComponentがあったかと思います。そこには

  1. Background Locked
  2. Background Unlocked
  3. Icon
  4. Title
  5. Description
  6. Progress Bar Display

という項目があって、prefabの各要素と対応して紐づけられています。
後述のMMAchievementDisplayer.csの中で、解除された実績に応じた画像や文字列をメンバに格納することで、解除した実績を動的に表示することができています。

MMAchievementDisplayer.cs

コードはThirdParty/MoreMountains/MMTools/ToolsForMMFeedbacks/Tools/Achievementsの中にあります。見た感じ、OnMMEvent()でMMAchievementUnlockedEventを引っかけて、DisplayAchievement()の中でinstanceからachievementDisplayを生成して、しかるべき画像やメッセージをAchievementItemの各メンバに格納する仕組みになっているようです。

MMAchievementDisplayer.csより
// we instantiate our achievement display prefab, and add it to the group that will automatically handle its position
GameObject instance = (GameObject)Instantiate(AchievementDisplayPrefab.gameObject);
instance.transform.SetParent(this.transform,false);

// we get the achievement displayer
MMAchievementDisplayItem achievementDisplay = instance.GetComponent<MMAchievementDisplayItem> ();
if (achievementDisplay == null)
{
	yield break;
}

// we fill our achievement
achievementDisplay.Title.text = achievement.Title;
achievementDisplay.Description.text = achievement.Description;
achievementDisplay.Icon.sprite = achievement.UnlockedImage;
...<後略>

そして同じくinstanceからachievementCanvasGroupを生成して、画像のフェードイン・フェードアウトを実行しているようです。

MMAchievementDisplayer.csより
// we fade it in and out
CanvasGroup achievementCanvasGroup = instance.GetComponent<CanvasGroup> ();
if (achievementCanvasGroup != null)
{
	achievementCanvasGroup.alpha = 0;
	StartCoroutine(MMFade.FadeCanvasGroup(achievementCanvasGroup, AchievementFadeDuration, 1));
	yield return _achievementFadeOutWFS;
	StartCoroutine(MMFade.FadeCanvasGroup(achievementCanvasGroup, AchievementFadeDuration, 0));
}

次の記事

以上で大まかな構造や仕組みが理解できたところで、次の記事では実際にAchievementの機能を使ってみようと思います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0