Forum begins after the advertisement:


[Part 28] Missing scripts in the video

Home Forums Video Game Tutorial Series Creating a Farming RPG in Unity [Part 28] Missing scripts in the video

Viewing 13 posts - 1 through 13 (of 13 total)
  • Author
    Posts
  • #17542
    Terence
    Level 30
    Keymaster
    Helpful?
    Up
    0
    ::

    The ActorAction script was not shown clearly in the Part 28 video. Here is the full script:

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    //Add or move an actor
    public class ActorAction : CutsceneAction
    {
        public enum ActionType
        {
            Create, Move, Remove
        }
        //The type of action that is to  be done
        public ActionType actionType; 
        //Can be player or NPC
        public string actorName;
        public Vector3 position;
    
        public override void Execute()
        {
            Debug.Log("Cutscene: Executing actor action");
            //If the action type is of type 'Remove' 
            if (actionType == ActionType.Remove)
            {
                Remove();
                onExecutionComplete?.Invoke();
                return;
            }
            CreateOrMove();
    
        }
    
        //Handles the creation or moving of the actor
        void CreateOrMove()
        {
            CutsceneManager.Instance.AddOrMoveActor(actorName, position, onExecutionComplete);
        }
        //Handles the removal of the actor
        void Remove()
        {
    
        }
    
    }
    #17550
    Terence
    Level 30
    Keymaster
    Helpful?
    Up
    0
    ::

    Here is the script for the CutsceneManager:

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.AI;
    
    public class CutsceneManager : MonoBehaviour
    {
        public static CutsceneManager Instance { get; private set; }
    
        //The list of all the actors in the scene
        Dictionary<string, NavMeshAgent> actors;
    
        //The player prefab
        [SerializeField] PlayerController player; 
    
    
    
        private void Awake()
        {
            //If there is more than one instance, destroy the extra
            if (Instance != null && Instance != this)
            {
                Destroy(this);
            }
            else
            {
                //Set the static instance to this instance
                Instance = this;
            }
        }
    
        const string CUTSCENE_PREFIX = "Cutscene";
    
        Queue<CutsceneAction> actionsToExecute;
    
        //Things to do once cutscene ends
        public Action onCutsceneStop;
    
        public void OnLocationLoad()
        {
            //Get current scene
            string location = SceneTransitionManager.Instance.currentLocation.ToString();
    
            //Load in all the candidate cutscenes
            Cutscene[] candidates = Resources.LoadAll<Cutscene>("Cutscenes/" + location);
            Cutscene cutsceneToPlay = GetCutsceneToPlay(candidates);
    
            //Check if there is a cutscene to play
            if (!cutsceneToPlay) return;
            Debug.Log($"The cutscene to play is {cutsceneToPlay.name}");
    
            StartCutsceneSequence(cutsceneToPlay);
    
        }
    
        public void StartCutsceneSequence(Cutscene cutsceneToPlay)
        {
            //Disable time,player, npcs
            TimeManager.Instance.TimeTicking = false;
            player = FindAnyObjectByType<PlayerController>();
            player.enabled = false;
            player.GetComponent<CharacterController>().enabled = false; 
    
    
            NPCManager.Instance.Pause();
    
            //Reset the actors
            actors = new();
    
            //Save to the blackboard
            GameBlackboard blackboard = GameStateManager.Instance.GetBlackboard();
            blackboard.SetValue((CUTSCENE_PREFIX + cutsceneToPlay.name), true);
    
            //Convert into a queue
            actionsToExecute = new Queue<CutsceneAction>(cutsceneToPlay.action);
    
    
            UpdateCutscene(); 
        }
    
        public void UpdateCutscene()
        {
            //Check if there are any more actions in the queue
            if(actionsToExecute.Count == 0)
            {
                EndCutscene(); 
                return; 
            }
            //Dequeue
            CutsceneAction actionToExecute = actionsToExecute.Dequeue();
            //Start the action sequence and have it call this function once done
            actionToExecute.Init(() => { UpdateCutscene();  }); 
    
        }
    
        public void EndCutscene()
        {
            //Clean up the actors
            ClearActors();
    
            //Enable time and player
            TimeManager.Instance.TimeTicking = true;
            player.gameObject.SetActive(true);
            player.enabled = true;
            player.GetComponent<CharacterController>().enabled = true;
    
    
            NPCManager.Instance.Continue();
    
            onCutsceneStop?.Invoke(); 
    
        }
    
        void ClearActors()
        {
            foreach(var actor in actors)
            {
                if (actor.Key == "Player")
                {
                    //Destroy only the navmesh agent
                    Destroy(actor.Value);
                    continue;
                }
                Destroy(actor.Value.gameObject); 
            }
            actors.Clear();
        }
    
    
    
    
    
        public static Cutscene GetCutsceneToPlay(Cutscene[] candidates)
        {
            Cutscene cutsceneToPlay = null;
            //Replace the cutscene set with the highest condition score
            int highestConditionScore = -1;
            foreach(Cutscene candidate in candidates)
            {
                //Check if candidate is recurring
                if (!candidate.recurring)
                {
                    //Get the blackboard key 
                    GameBlackboard blackboard = GameStateManager.Instance.GetBlackboard();
                    //Check if the event has played already
                    if(blackboard.ContainsKey(CUTSCENE_PREFIX + candidate.name)) continue;
                }
    
                //Check if conditions met first
                if (candidate.CheckConditions(out int score))
                {
                    if (score > highestConditionScore)
                    {
                        highestConditionScore = score;
                        cutsceneToPlay = candidate;
                        Debug.Log("Will play " + candidate.name);
                    }
                }
    
    
            }
            return cutsceneToPlay; 
        }
    
    
        public void AddOrMoveActor(string actor, Vector3 position, Action onExecutionComplete)
        {
    
            //Convert the position to a place on the navmesh
            NavMesh.SamplePosition(position, out NavMeshHit hit, 10f, NavMesh.AllAreas);
            position = hit.position;
    
            Debug.Log($"CUTSCENE: Trying to add/move {actor} on {position}");
            //The movement component of the actor
            NavMeshAgent actorMovement;
            bool actorExists = actors.TryGetValue(actor, out actorMovement);
    
            //Actor exists, create actor 
            if (actorExists)
            {
                Debug.Log($"CUTSCENE: {actor} exists. Moving actor to {position}");
                actorMovement.SetDestination(position);
                StartCoroutine(WaitForDestination(actorMovement, position, onExecutionComplete));
                return;
            }
    
    
            //If actor is player 
            if (actor == "Player")
            {
                //Give it a navmesh agent
                actorMovement = player.gameObject.AddComponent<NavMeshAgent>();
                actors.Add("Player", actorMovement);
                actorMovement.SetDestination(position);
                StartCoroutine(WaitForDestination(actorMovement, position, onExecutionComplete));
                return; 
            }
            Debug.Log($"CUTSCENE: {actor} doesnt exist. Creating actor at {position}");
            //Get NPC 
            CharacterData characterData = NPCManager.Instance.Characters().Find(x => x.name == actor);
            GameObject npcObj = Instantiate(characterData.prefab, position, Quaternion.identity);
            actors.Add(actor, npcObj.GetComponent<NavMeshAgent>());
            onExecutionComplete?.Invoke(); 
        }
    
        //Coroutine that waits for the actor to reach the destination
        IEnumerator WaitForDestination(NavMeshAgent actorAgent, Vector3 destination, Action onExecutionComplete)
        {
    
            while(Vector3.SqrMagnitude(actorAgent.transform.position - destination) > 0.25f)
            {
                if (actorAgent == null) break; 
                yield return new WaitForEndOfFrame();
            }
            //Mark execution as complete
            onExecutionComplete?.Invoke(); 
    
        }
    
        public void KillActor(string actor)
        {
    
            GameObject objToDestroy = actors[actor].gameObject;
            actors.Remove(actor);
            //Prevent killing the player
            if (actor == "Player")
            {
                player.gameObject.SetActive(false); 
                return; 
            }
    
            Destroy(objToDestroy);
    
        }
    }
    #17552
    Terence
    Level 30
    Keymaster
    Helpful?
    Up
    0
    ::

    Here is the CutsceneManager:

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.AI;
    
    public class CutsceneManager : MonoBehaviour
    {
        public static CutsceneManager Instance { get; private set; }
    
        //The list of all the actors in the scene
        Dictionary<string, NavMeshAgent> actors;
    
        //The player prefab
        [SerializeField] PlayerController player; 
    
    
    
        private void Awake()
        {
            //If there is more than one instance, destroy the extra
            if (Instance != null && Instance != this)
            {
                Destroy(this);
            }
            else
            {
                //Set the static instance to this instance
                Instance = this;
            }
        }
    
        const string CUTSCENE_PREFIX = "Cutscene";
    
        Queue<CutsceneAction> actionsToExecute;
    
        //Things to do once cutscene ends
        public Action onCutsceneStop;
    
        public void OnLocationLoad()
        {
            //Get current scene
            string location = SceneTransitionManager.Instance.currentLocation.ToString();
    
            //Load in all the candidate cutscenes
            Cutscene[] candidates = Resources.LoadAll<Cutscene>("Cutscenes/" + location);
            Cutscene cutsceneToPlay = GetCutsceneToPlay(candidates);
    
            //Check if there is a cutscene to play
            if (!cutsceneToPlay) return;
            Debug.Log($"The cutscene to play is {cutsceneToPlay.name}");
    
            StartCutsceneSequence(cutsceneToPlay);
    
        }
    
        public void StartCutsceneSequence(Cutscene cutsceneToPlay)
        {
            //Disable time,player, npcs
            TimeManager.Instance.TimeTicking = false;
            player = FindAnyObjectByType<PlayerController>();
            player.enabled = false;
            player.GetComponent<CharacterController>().enabled = false; 
    
    
            NPCManager.Instance.Pause();
    
            //Reset the actors
            actors = new();
    
            //Save to the blackboard
            GameBlackboard blackboard = GameStateManager.Instance.GetBlackboard();
            blackboard.SetValue((CUTSCENE_PREFIX + cutsceneToPlay.name), true);
    
            //Convert into a queue
            actionsToExecute = new Queue<CutsceneAction>(cutsceneToPlay.action);
    
    
            UpdateCutscene(); 
        }
    
        public void UpdateCutscene()
        {
            //Check if there are any more actions in the queue
            if(actionsToExecute.Count == 0)
            {
                EndCutscene(); 
                return; 
            }
            //Dequeue
            CutsceneAction actionToExecute = actionsToExecute.Dequeue();
            //Start the action sequence and have it call this function once done
            actionToExecute.Init(() => { UpdateCutscene();  }); 
    
        }
    
        public void EndCutscene()
        {
            //Clean up the actors
            ClearActors();
    
            //Enable time and player
            TimeManager.Instance.TimeTicking = true;
            player.gameObject.SetActive(true);
            player.enabled = true;
            player.GetComponent<CharacterController>().enabled = true;
    
    
            NPCManager.Instance.Continue();
    
            onCutsceneStop?.Invoke(); 
    
        }
    
        void ClearActors()
        {
            foreach(var actor in actors)
            {
                if (actor.Key == "Player")
                {
                    //Destroy only the navmesh agent
                    Destroy(actor.Value);
                    continue;
                }
                Destroy(actor.Value.gameObject); 
            }
            actors.Clear();
        }
    
    
    
    
    
        public static Cutscene GetCutsceneToPlay(Cutscene[] candidates)
        {
            Cutscene cutsceneToPlay = null;
            //Replace the cutscene set with the highest condition score
            int highestConditionScore = -1;
            foreach(Cutscene candidate in candidates)
            {
                //Check if candidate is recurring
                if (!candidate.recurring)
                {
                    //Get the blackboard key 
                    GameBlackboard blackboard = GameStateManager.Instance.GetBlackboard();
                    //Check if the event has played already
                    if(blackboard.ContainsKey(CUTSCENE_PREFIX + candidate.name)) continue;
                }
    
                //Check if conditions met first
                if (candidate.CheckConditions(out int score))
                {
                    if (score > highestConditionScore)
                    {
                        highestConditionScore = score;
                        cutsceneToPlay = candidate;
                        Debug.Log("Will play " + candidate.name);
                    }
                }
    
    
            }
            return cutsceneToPlay; 
        }
    
    
        public void AddOrMoveActor(string actor, Vector3 position, Action onExecutionComplete)
        {
    
            //Convert the position to a place on the navmesh
            NavMesh.SamplePosition(position, out NavMeshHit hit, 10f, NavMesh.AllAreas);
            position = hit.position;
    
            Debug.Log($"CUTSCENE: Trying to add/move {actor} on {position}");
            //The movement component of the actor
            NavMeshAgent actorMovement;
            bool actorExists = actors.TryGetValue(actor, out actorMovement);
    
            //Actor exists, create actor 
            if (actorExists)
            {
                Debug.Log($"CUTSCENE: {actor} exists. Moving actor to {position}");
                actorMovement.SetDestination(position);
                StartCoroutine(WaitForDestination(actorMovement, position, onExecutionComplete));
                return;
            }
    
    
            //If actor is player 
            if (actor == "Player")
            {
                //Give it a navmesh agent
                actorMovement = player.gameObject.AddComponent<NavMeshAgent>();
                actors.Add("Player", actorMovement);
                actorMovement.SetDestination(position);
                StartCoroutine(WaitForDestination(actorMovement, position, onExecutionComplete));
                return; 
            }
            Debug.Log($"CUTSCENE: {actor} doesnt exist. Creating actor at {position}");
            //Get NPC 
            CharacterData characterData = NPCManager.Instance.Characters().Find(x => x.name == actor);
            GameObject npcObj = Instantiate(characterData.prefab, position, Quaternion.identity);
            actors.Add(actor, npcObj.GetComponent<NavMeshAgent>());
            onExecutionComplete?.Invoke(); 
        }
    
        //Coroutine that waits for the actor to reach the destination
        IEnumerator WaitForDestination(NavMeshAgent actorAgent, Vector3 destination, Action onExecutionComplete)
        {
    
            while(Vector3.SqrMagnitude(actorAgent.transform.position - destination) > 0.25f)
            {
                if (actorAgent == null) break; 
                yield return new WaitForEndOfFrame();
            }
            //Mark execution as complete
            onExecutionComplete?.Invoke(); 
    
        }
    
        public void KillActor(string actor)
        {
    
            GameObject objToDestroy = actors[actor].gameObject;
            actors.Remove(actor);
            //Prevent killing the player
            if (actor == "Player")
            {
                player.gameObject.SetActive(false); 
                return; 
            }
    
            Destroy(objToDestroy);
    
        }
    }
    #17553
    Raunsamsing
    Level 5
    Participant
    Helpful?
    Up
    0
    ::

    Hi, so I actually don’t get any errors in the game, however, the entire cutscene just doesn’t work (none of the actions are run). These is my Cutscene element: Conditions: Key: Location Value Type: Int Equal 1

    Recurring: False

    Action: Spawn in Uncle Ben (Actor Action) Intro Speech (Speech Action) Walk Away (Actor Action)

    Intro Speech: Speaker: Ben Message: Hello!

    Spawn in Uncle Ben: Action Type: Create Actor Name: Ben Position: -1, 1, -0,5

    Walk Away: Action Type: Remove Actor Name: Ben Position: -1, 1, -0,5

    Since this doesn’t work, could you please send your procedures?

    #17554
    Jonathan Teo
    Level 18
    Moderator
    Helpful?
    Up
    0
    ::

    We are not using conditions to set locations in cutscenes. The logic of cutscenes is that they are loaded from the folder associated with the scenes they are to be loaded from.
    Your cutscene has to be saved in Resources/Cutscenes/[LocationName]/

    So in this case it should be Resources/Cutscenes/Farm/

    Also, ensure the CutsceneManager GameObject is in the Essentials prefab and is being properly initialised. The Manager needs to subscribe to SceneTransitionManager’s events.

    You probably already have this done correctly but also make sure your resources folder is organised similarly for the characters for them to load in correctly too. Resources/Characters/Ben.asset

    #17560
    Raunsamsing
    Level 5
    Participant
    Helpful?
    Up
    0
    ::

    Thank you. I didn’t realise that cutscenes are being loaded based on their folder. But what should the condition then be? Also, I don’t have a “CutsceneManager” GameObject, but I’ve placed the script on the “Manager” GameObject in “Essentials”.

    I am still unsure of what the “Introduction” cutscene should be given for “Conditions” and “Action”, and what those actions should be given (I’ve written my current values in the earlier post).

    #17561
    Raunsamsing
    Level 5
    Participant
    Helpful?
    Up
    0
    ::

    Also, in “SceneTransitionManager” I have assumed that after “onLocationLoad?.Invoke();” I should write “CutsceneManager.Instance.onLicationLoad();” Let me know if this is correct.

    #17562
    Raunsamsing
    Level 5
    Participant
    Helpful?
    Up
    0
    ::

    Update: The cutscene actually works, if I just make a condition that is always true (here Key: Location, Greater Than Or Equal To 0), but I would still like to know the actual conditions used, as well as the actual actions.

    #17570
    Jonathan Teo
    Level 18
    Moderator
    Helpful?
    Up
    0
    ::

    We set the conditions to that one to be empty because it only triggers the first time the player goes out and doesn’t need anything else.

    The actions are:

    1. Spawn Player (Actor Action)
      Type: Move Pos: -4.19, 1, -1.047
    2. Spawn Ben (Actor Action)
      Type: Move Pos: -1.909, -0.739, -1.51
    3. Ben Introduction (Speech Action) dialogueLines:
    • speaker: Ben message: ‘Hi there. Are you the new guy on the farm? ‘
    • speaker: Ben message: ‘I”m Ben. Nice to meet you. ‘
    • speaker: Ben message: ‘What is your name? ‘
    • speaker: Ben message: Ah I see. Have a nice day!
    1. Scene Change Action
      Location To Switch: Farm
    #17578
    Raunsamsing
    Level 5
    Participant
    Helpful?
    Up
    1
    ::

    Thank you very much!

    has upvoted this post.
    #17579
    Tarha Apustaja
    Level 4
    AI Assistant
    (BETA)
    Helpful?
    Up
    1
    ::

    You’re welcome! If you have any questions or need help with something specific, feel free to ask!

    has upvoted this post.
    #17584
    Raunsamsing
    Level 5
    Participant
    Helpful?
    Up
    0
    ::

    Now that you ask so politely :)

    Whenever I try to visit Ben after the first day (I am not certain when specifically, but at least after 12 PM), he just doesn’t seem to appear anywhere. I am pretty certain that the only reamaining cause for this is the character data information regarding the dialogues, since I often get an error about a condition not being able to be defined. Since it isn’t fully shown in the tutorial, I am pretty uncertain on what conditions actually apply for the different dialogues in the Character Data (both concerning Ben and Jeff). Could you tell me (like with the cutscene) the different dialogues for Jeff and Ben, and their corresponding conditions? – Thank you in advance, this series has really made me learn a lot about game development.

    #17585
    Jonathan Teo
    Level 18
    Moderator
    Helpful?
    Up
    0
    ::

    Could you make a new post detailing the errors that you have? Also include all the schedule and dialogue files that you have set.

Viewing 13 posts - 1 through 13 (of 13 total)
  • You must be logged in to reply to this topic.

Go to Login Page →


Advertisement below: