FPS Microgame 代码解析——ObjectiveMessage

1. 在GameHUD上挂脚本

在这里插入图片描述

2. 画出Rect区域

在这里插入图片描述

3. 预制件ObjectivePrime

  • 整个偷走。
    在这里插入图片描述

3.1预制件的组件设计

在这里插入图片描述
在这里插入图片描述

3.2 导入两个音源

  • 作为提示出现和消失的声音
  • 位置如下:
    在这里插入图片描述

一、ObjectiveHUDManager

using System.Collections.Generic;
using UnityEngine;

namespace Unity.FPS.Game
{
    public class ObjectiveManager : MonoBehaviour
    {
        List<Objective> m_Objectives = new List<Objective>();
        bool m_ObjectivesCompleted = false;

        void Awake()
        {
            Objective.OnObjectiveCreated += RegisterObjective;
        }

        void RegisterObjective(Objective objective) => m_Objectives.Add(objective);

        void Update()
        {
            if (m_Objectives.Count == 0 || m_ObjectivesCompleted)
                return;

            for (int i = 0; i < m_Objectives.Count; i++)
            {
                // pass every objectives to check if they have been completed
                if (m_Objectives[i].IsBlocking())
                {
                    // break the loop as soon as we find one uncompleted objective
                    return;
                }
            }

            m_ObjectivesCompleted = true;
            EventManager.Broadcast(Events.AllObjectivesCompletedEvent);
        }

        void OnDestroy()
        {
            Objective.OnObjectiveCreated -= RegisterObjective;
        }
    }
}

二、ObjectiveToast

using Unity.FPS.Game;
using UnityEngine;
using UnityEngine.UI;

namespace Unity.FPS.UI
{
    public class ObjectiveToast : MonoBehaviour
    {
        [Header("References")] [Tooltip("Text content that will display the title")]
        public TMPro.TextMeshProUGUI TitleTextContent;

        [Tooltip("Text content that will display the description")]
        public TMPro.TextMeshProUGUI DescriptionTextContent;

        [Tooltip("Text content that will display the counter")]
        public TMPro.TextMeshProUGUI CounterTextContent;

        [Tooltip("Rect that will display the description")]
        public RectTransform SubTitleRect;

        [Tooltip("Canvas used to fade in and out the content")]
        public CanvasGroup CanvasGroup;

        [Tooltip("Layout group containing the objective")]
        public HorizontalOrVerticalLayoutGroup LayoutGroup;

        [Header("Transitions")] [Tooltip("Delay before moving complete")]
        public float CompletionDelay;

        [Tooltip("Duration of the fade in")] public float FadeInDuration = 0.5f;
        [Tooltip("Duration of the fade out")] public float FadeOutDuration = 2f;

        [Header("Sound")] [Tooltip("Sound that will be player on initialization")]
        public AudioClip InitSound;

        [Tooltip("Sound that will be player on completion")]
        public AudioClip CompletedSound;

        [Header("Movement")] [Tooltip("Time it takes to move in the screen")]
        public float MoveInDuration = 0.5f;

        [Tooltip("Animation curve for move in, position in x over time")]
        public AnimationCurve MoveInCurve;

        [Tooltip("Time it takes to move out of the screen")]
        public float MoveOutDuration = 2f;

        [Tooltip("Animation curve for move out, position in x over time")]
        public AnimationCurve MoveOutCurve;

        float m_StartFadeTime;
        bool m_IsFadingIn;
        bool m_IsFadingOut;
        bool m_IsMovingIn;
        bool m_IsMovingOut;
        AudioSource m_AudioSource;
        RectTransform m_RectTransform;

        public void Initialize(string titleText, string descText, string counterText, bool isOptionnal, float delay)
        {
            // set the description for the objective, and forces the content size fitter to be recalculated
            Canvas.ForceUpdateCanvases();

            TitleTextContent.text = titleText;
            DescriptionTextContent.text = descText;
            CounterTextContent.text = counterText;

            if (GetComponent<RectTransform>())
            {
                LayoutRebuilder.ForceRebuildLayoutImmediate(GetComponent<RectTransform>());
            }

            m_StartFadeTime = Time.time + delay;
            // start the fade in
            m_IsFadingIn = true;
            m_IsMovingIn = true;
        }

        public void Complete()
        {
            m_StartFadeTime = Time.time + CompletionDelay;
            m_IsFadingIn = false;
            m_IsMovingIn = false;

            // if a sound was set, play it
            PlaySound(CompletedSound);

            // start the fade out
            m_IsFadingOut = true;
            m_IsMovingOut = true;
        }

        void Update()
        {
            float timeSinceFadeStarted = Time.time - m_StartFadeTime;

            SubTitleRect.gameObject.SetActive(!string.IsNullOrEmpty(DescriptionTextContent.text));

            if (m_IsFadingIn && !m_IsFadingOut)
            {
                // fade in
                if (timeSinceFadeStarted < FadeInDuration)
                {
                    // calculate alpha ratio
                    CanvasGroup.alpha = timeSinceFadeStarted / FadeInDuration;
                }
                else
                {
                    CanvasGroup.alpha = 1f;
                    // end the fade in
                    m_IsFadingIn = false;

                    PlaySound(InitSound);
                }
            }

            if (m_IsMovingIn && !m_IsMovingOut)
            {
                // move in
                if (timeSinceFadeStarted < MoveInDuration)
                {
                    LayoutGroup.padding.left = (int) MoveInCurve.Evaluate(timeSinceFadeStarted / MoveInDuration);

                    if (GetComponent<RectTransform>())
                    {
                        LayoutRebuilder.ForceRebuildLayoutImmediate(GetComponent<RectTransform>());
                    }
                }
                else
                {
                    // making sure the position is exact
                    LayoutGroup.padding.left = 0;

                    if (GetComponent<RectTransform>())
                    {
                        LayoutRebuilder.ForceRebuildLayoutImmediate(GetComponent<RectTransform>());
                    }

                    m_IsMovingIn = false;
                }

            }

            if (m_IsFadingOut)
            {
                // fade out
                if (timeSinceFadeStarted < FadeOutDuration)
                {
                    // calculate alpha ratio
                    CanvasGroup.alpha = 1 - (timeSinceFadeStarted) / FadeOutDuration;
                }
                else
                {
                    CanvasGroup.alpha = 0f;

                    // end the fade out, then destroy the object
                    m_IsFadingOut = false;
                    Destroy(gameObject);
                }
            }

            if (m_IsMovingOut)
            {
                // move out
                if (timeSinceFadeStarted < MoveOutDuration)
                {
                    LayoutGroup.padding.left = (int) MoveOutCurve.Evaluate(timeSinceFadeStarted / MoveOutDuration);

                    if (GetComponent<RectTransform>())
                    {
                        LayoutRebuilder.ForceRebuildLayoutImmediate(GetComponent<RectTransform>());
                    }
                }
                else
                {
                    m_IsMovingOut = false;
                }
            }
        }

        void PlaySound(AudioClip sound)
        {
            if (!sound)
                return;

            if (!m_AudioSource)
            {
                m_AudioSource = gameObject.AddComponent<AudioSource>();
                m_AudioSource.outputAudioMixerGroup = AudioUtility.GetAudioGroup(AudioUtility.AudioGroups.HUDObjective);
            }

            m_AudioSource.PlayOneShot(sound);
        }
    }
}

借鉴

  • 在EnemyController里设置被击杀函数
  • 调用UnregisterEnemy函数。
  • 之前要先定义一个 EnemyManager m_EnemyManager;
EnemyManager m_EnemyManager;
void OnDie()
        {
            // spawn a particle system when dying
            var vfx = Instantiate(DeathVfx, DeathVfxSpawnPoint.position, Quaternion.identity);
            Destroy(vfx, 5f);

            // tells the game flow manager to handle the enemy destuction
            m_EnemyManager.UnregisterEnemy(this);

            // loot an object
            if (TryDropItem())
            {
                Instantiate(LootPrefab, transform.position, Quaternion.identity);
            }

            // this will call the OnDestroy function
            Destroy(gameObject, DeathDuration);
        }
  • 在挂在GameHUD的EnemyManager上:
using System.Collections.Generic;
using Unity.FPS.Game;
using UnityEngine;

namespace Unity.FPS.AI
{
    public class EnemyManager : MonoBehaviour
    {
        public List<EnemyController> Enemies { get; private set; }
        public int NumberOfEnemiesTotal { get; private set; }
        public int NumberOfEnemiesRemaining => Enemies.Count;

        void Awake()
        {
            Enemies = new List<EnemyController>();
        }

        public void RegisterEnemy(EnemyController enemy)
        {
            Enemies.Add(enemy);

            NumberOfEnemiesTotal++;
        }

        public void UnregisterEnemy(EnemyController enemyKilled)
        {
            int enemiesRemainingNotification = NumberOfEnemiesRemaining - 1;

            EnemyKillEvent evt = Events.EnemyKillEvent;
            evt.Enemy = enemyKilled.gameObject;
            evt.RemainingEnemyCount = enemiesRemainingNotification;
            EventManager.Broadcast(evt);

            // removes the enemy from the list, so that we can keep track of how many are left on the map
            Enemies.Remove(enemyKilled);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值