How to persist variables across multiple Ink stories (Variable Observer) | Unity + Ink tutorial

Поделиться
HTML-код
  • Опубликовано: 29 дек 2024

Комментарии • 110

  • @ShapedByRainStudios
    @ShapedByRainStudios  3 года назад +42

    Thanks for watching! 🙂There's an issue in this tutorial where if you try to build the project, it will fail because the Ink.UnityIntegration package is only available to the Editor. Thank you to @Jason Kennedy for bringing this to my attention and my apologies to whoever this issue inconveniences!
    Here's a workaround that can be used. I updated the code on Github to reflect this change as well, which you can reference here - github.com/shapedbyrainstudios/ink-dialogue-system/tree/5-persist-variables-implemented .
    *1 - Create a new ink file called load_globals.ink.* Make the contents the below line. This will now compile into JSON and can be included into the project as a TextAsset, which we can use to load the variables in globals.ink.
    INCLUDE globals.ink
    *2 - Make the DialogueManager take in a TextAsset instead of the Ink.UnityIntegration.InkFile.* You'll want to use the below code as well as be sure to drag in the load_globals JSON file into the loadGlobalsJSON variable slot in the Unity editor.
    // variable for the load_globals.ink JSON
    [Header("Load Globals JSON")]
    [SerializeField] private TextAsset loadGlobalsJSON;
    // pass that variable to the DIalogueVariables constructor in the Awake method
    dialogueVariables = new DialogueVariables(loadGlobalsJSON);
    *3 - Rework the DialogueVariables constructor.* Replace it with the below code, which will create a story from the TextAsset rather than try to compile it ourselves.
    public DialogueVariables(TextAsset loadGlobalsJSON)
    {
    // create the story
    Story globalVariablesStory = new Story(loadGlobalsJSON.text);
    // initialize the dictionary
    variables = new Dictionary();
    foreach (string name in globalVariablesStory.variablesState)
    {
    Ink.Runtime.Object value = globalVariablesStory.variablesState.GetVariableWithName(name);
    variables.Add(name, value);
    Debug.Log("Initialized global dialogue variable: " + name + " = " + value);
    }
    }
    Again - my apologies for the inconvenience this might cause! I unfortunately did not realize that the Ink.UnityIntegration package was only available in the Unity editor. I hope this workaround is sufficient for everyone!
    Aside from that, I recently started up a Discord server where you're welcome to come ask questions, suggest a video topic, or just hang out! It may take a bit to build up a community there, but I hope it eventually becomes a helpful place for other passionate developers! ➔ 📱 discord.gg/99gcnaHFf9

  • @vinylz3511
    @vinylz3511 Год назад +8

    The next brackeys right here. All of your ink tutorials have seriously been amazing. Can't wait to see more of what you teach!

    • @ShapedByRainStudios
      @ShapedByRainStudios  Год назад +1

      Thanks so much for the kind words, that means a lot! 🙂

    • @vinylz3511
      @vinylz3511 Год назад +1

      @@ShapedByRainStudios Do you think you could do a naming system sometime? You can't really write to ink files so it's very hard for me to think how the player would choose a name that can then be called upon. Like in animal crossing or pokemon for example

  • @jimchaney5987
    @jimchaney5987 2 года назад +4

    I've been pouring over your ink/unity videos for over a month, building your code into my fps game and resolving issues with controllers and other game systems. Finally walked up to an npc and had a successful interaction with choices, global variables working and it looked nice. I just wanted to say, thank you for being so thorough with this series, especially the bug and polish videos which get less attention.
    You've taught me so much in such a great manner! I look forward to your future content.

    • @ShapedByRainStudios
      @ShapedByRainStudios  2 года назад

      Thanks so much for the comment - the kind words are greatly appreciated and that really makes my day to hear you were able to incorporate it into your game! 🙂

  • @emielmuter3990
    @emielmuter3990 2 года назад +6

    Hi again! I've been following this series of yours to help me with my graduation project, and I have to say, I have tremendous respect for the work you put into these tutorials. Everything seems to work like a charm for me, so I just wanted to thank you! I'm at that part of my process where I (sadly) have to wrap up game development, so no more Ink for me for now, but I'm sure the stuff from these videos is going to find its way back in some of my future work. Thanks again and cheers!

    • @ShapedByRainStudios
      @ShapedByRainStudios  2 года назад

      Hey there! 🙂Thank you so much for the kind words! That means a lot and I'm really glad to hear this series helped! Best of luck to you with your future endeavors and I hope this knowledge finds it's way back to you as well in the future! Cheers!

  • @absentminded55
    @absentminded55 Год назад +3

    I just want to say i hugely appreciate these videos and especially appreciate that you take the time to read and respond to the comments. I've solved most of my issues by simply going in to the comments and reading your replies to other peoples comments.

  • @evanlane1690
    @evanlane1690 2 года назад +2

    Yessss. This series has basically made Ink useful for me and my project. I've been dying to use Ink since I saw their GDC talk and their writer described her views on narrative. Couldn't figure it out at scale though, except using a monolithic Ink file. Thanks for this!

    • @ShapedByRainStudios
      @ShapedByRainStudios  2 года назад

      Really glad to hear this series helped! Thank you for the kind words! 🙂

  • @tracenreap4296
    @tracenreap4296 2 года назад +3

    Just found your Ink + Unity tutorials and they're amazing. My team and I are definitely going to use this going forward in our game! Ink is so powerful and integrates so nicely with Unity!

    • @ShapedByRainStudios
      @ShapedByRainStudios  2 года назад +1

      Really glad to hear all of that and thank you for the kind words! 🙂

  • @markorossie9296
    @markorossie9296 3 года назад +7

    This was really interesting. I really love all the Ink - unity tutorials you've done. However one thing I really found challenge is to figured how a "Quest System" fits in in all these and/or perhaps a Cutscenes. These two would be so interesting to see your take on it. Thanks.

    • @ShapedByRainStudios
      @ShapedByRainStudios  3 года назад +14

      Hey! I'm really glad to hear that - it means a lot! 🙂
      It depends on what you're looking for in a "Quest System", but I'd say that between Ink logic and persisting variables, you can probably create a basic Questing System with minimal extra code.
      The main addition I would make to this tutorial is adding a 'SetVariableState' method in the DialogueManager so you can modify the global variables through C# code as well. It would look something like this...
      // this method will allow of a variable defined in globals.ink to be set using C# code
      public void SetVariableState(string variableName, Ink.Runtime.Object variableValue)
      {
      if (dialogueVariables.variables.ContainsKey(variableName))
      {
      dialogueVariables.variables.Remove(variableName);
      dialogueVariables.variables.Add(variableName, variableValue);
      }
      else
      {
      Debug.LogWarning("Tried to update variable that wasn't initialized by globals.ink: " + variableName);
      }
      }
      From there, you should be able to do basic quest mechanics (like get this item, etc...) which are handled in small C# scripts depending on the item. Then you can set global Ink variables as a medium between your C# code and Ink Dialogue so that way your Ink Story knows what to display.
      Ink has LOTS of really interesting ways to use variables/conditionals to display different dialogue. One example that comes to mind is 'Conditional Choices', which is where you use a boolean variable to show/hide a choice - which I think is really useful for a Questing System.
      I'm not sure if you've seen this video, but if you haven't, then it's worth a watch to give you a good idea of Ink's capabilities. It doesn't cover everything Ink has to offer, but it does cover quite a bit you might find useful in implementing a Questing System. - ruclips.net/video/KSRpcftVyKg/видео.html
      The last thing I'll say is that it could also be useful to implement a 'QuestManager' or something similar that if you find that there are things you have to manage that don't entirely relate to the Dialogue System. Of course, that'll depend on the questing system you're going for.
      I hope that all helps!

    • @markorossie9296
      @markorossie9296 3 года назад +1

      @@ShapedByRainStudios Interesting point of view Trever!. Thanks. Found all this so inspiring.

  • @stiggzz2299
    @stiggzz2299 2 года назад +1

    Dude you are a magician, these tutorials are amazing!@@@!!

    • @ShapedByRainStudios
      @ShapedByRainStudios  2 года назад

      Haha thanks so much for the kind words! I'm really glad you're finding them to be useful! 🙂

  • @ZisTraxMop
    @ZisTraxMop 2 года назад +2

    Thank you so much for the series! It was my first introduction to ink! I've been experimenting since, and it's so fun to play around and have different outcomes! Keep it up!

    • @ShapedByRainStudios
      @ShapedByRainStudios  2 года назад

      Right on! I'm really glad the series helped and thank you for the kind words! 🙂

  • @tobiasoder8384
    @tobiasoder8384 2 года назад +1

    The way you explain things is just amazing. Thank you so much for your videos!

  • @breynartstudios
    @breynartstudios Год назад +1

    Awesome tutorials, mate. Really awesome and helpful! Thanks a lot :)

  • @gabrielklark3357
    @gabrielklark3357 2 года назад +1

    My mind is blown 🤯🤯🤯
    Thank you so much for these series

  • @Nebulaoblivion
    @Nebulaoblivion 2 года назад +1

    Dude you're a legend. Thanks for making all these videos.

  • @MinerProfessional
    @MinerProfessional 2 года назад +1

    Thank you for such understandable lessons! I like that before starting work, you explain all the logic "on the fingers." Please continue to record various videos, and success will not make yourself wait!

    • @ShapedByRainStudios
      @ShapedByRainStudios  2 года назад +1

      Thanks so much for the kind words - it means a lot and I'm really glad you found these helpful! 🙂

  • @Halsdran
    @Halsdran 3 года назад +1

    Great Tutorial and just at the right time! Really helped me. :)

  • @marinavlachandreas5197
    @marinavlachandreas5197 Год назад +3

    But there is a compile automatically box under the global.ink .. that wouldn't work for the compilation part?

    • @ShapedByRainStudios
      @ShapedByRainStudios  Год назад

      If I remember right, at the time of making this video, even with the automatic compile checkbox checked it wasn't compiling the globals ink file. If that's compiling for you in the editor though, you can bypass that whole section! 🙂
      Also - It looks like you already did the fix that's in the pinned comment of this video which is great! For anyone else reading this in the future - be sure to take a look at the pinned comment for this video as there's a fix regarding how we go about compiling the globals ink file.

  • @Dominik-K
    @Dominik-K 3 года назад +1

    Thanks a bunch, I like your ink tutorials a whole lot

    • @ShapedByRainStudios
      @ShapedByRainStudios  3 года назад

      You're welcome and I'm glad to hear that! Thanks so much for the kind words! 🙂

  • @AdroitConceptions
    @AdroitConceptions 3 года назад +5

    The namespace Ink.UnityIntegration exists only in an Editor folder in Unity. Your code in this project will not work outside of the editor because of this. It will not work in a final project/build.

    • @Paullozz
      @Paullozz 3 года назад +2

      Yup and there's a reason for that. Everything under `Ink.UnityIntegration` is tooling and not meant at all to be used at runtime.

    • @ShapedByRainStudios
      @ShapedByRainStudios  3 года назад +1

      Thank you for bringing this to my attention. I've updated the pinned comment for this video with a work-around and also pushed up a change to the Github project.
      I hope that helps and my apologies to whoever this issue inconveniences!

  • @pedroaurelio_n6391
    @pedroaurelio_n6391 2 года назад +2

    Hey Trever, thanks a lot for the tutorials! I found your channel by chance yesterday while looking for videos about dialogue systems in Unity because I created a messy one long time ago and wanted to start over. And your solution is the best one out of the ones I watched in my opinion! I followed all of the videos without problems and after some modifications to fit in with my own input logic I'm pretty happy to have created a dialogue system with Ink to use in my games.
    But because I'm not familiar at all with Ink, I'm struggling to wrap my head around an efficient way to use states or effects with it.
    For states, imagine there's a NPC with dialogue1 that branches whether or not the player has already talked to him. Then after collecting 10 coins, he has a dialogue2 that branches in the same way. I think that having a "coins" variable in globals is guaranteed in most scenarios for easy access, but do I create a variable in globals for each NPC state and use a single and long Ink file for every NPC? Or maybe I manage states in C# code and have multiple Ink files that I switch when needed
    Regarding the effects, there's the Ink tags in the portrait/layout examples, but I'm currently using Unity events for more complicated things like deactivating game objects or any custom function I need. But maybe there's a better alternative that I didn't think of yet.
    I guess my main questions boils down to: does Ink have tools or solutions for some more complex stuff and I simply lack the knowledge or am not familiarized enough yet, or outsourcing most of the stuff to C# programming is actually the way to go for most problems? Sorry about the rambling, I'm just really happy to have found a great channel with videos on the exact topic I wanted and my brain is now overwhelmed thinking about all the things that I could experiment on. I'm eyeing your save/load system tutorial too, for sure that'll be a great video as well! Keep up the good work and I'm looking forward to your new videos!

    • @ShapedByRainStudios
      @ShapedByRainStudios  2 года назад +2

      Hey there! I love the enthusiasm and I'm really glad you found the tutorials helpful! 🙂Ink has a lot of depth for a narrative scripting language and can definitely take a bit to warp your head around. Once you get over the learning curve, I think you'll find it to be really versatile.
      For states, you can structure these however you'd like to. I'll run through your coins example to illustrate a good way to set this up.
      For your coins example, I would do this as one variable that's an integer in globals - 'VAR coinsCollected = 0'. Check out my response to a comment on this video by @ツDrReaMzZ about modifying your global variables from C# code. It's a pretty simple addition, but will allow you to increment the 'coinsCollected' from your C# code when you collect a coin.
      From there, you can reference that coinsCollected variable in any NPC Ink file to determine what dialogue you want to use. One thing that might help here is to use Knots to organize your Ink files, and have a logic gate at the top to determine which Knot(s) you'll start from based on a condition. So for the coinsCollected example, the below Ink syntax would go straight to the 'collected' knot if any coins have been collected, but otherwise would go to the 'none_collected' knot.
      { coinsCollected > 0 : -> collected | -> none_collected }
      === collected ===
      I see you've collected {coinsCollected} coins!
      -> DONE
      ===none_collected ===
      You need to collect coins. You don't have any right now!
      -> DONE
      The above strategy should let you use different dialogue for the same NPC in a fairly organized way.
      Ink has TONS of built-in logic for handling dialogue. So to answer the second part of your question - you can usually handle everything you need to do within Ink; however, when it comes to actually maintaining variables like the 'coinsCollected' example, that might be better left to your C# code.
      I'm not sure if you've seen this video or not yet, so I'll link to it here just in case - ruclips.net/video/KSRpcftVyKg/видео.html&t
      That video aims to give a fast paced overview of many of the core capabilities that Ink provides. That said, it's not all-inclusive and Ink can do much more than I go over in that video.
      I hope that all helps and I hope you enjoy using Ink as much as I have been for my own project! 🙂

  • @areebahmed9181
    @areebahmed9181 Год назад +3

    the global ink file was automatically compiled like other ink files,
    what changes do i need to make to just initialize the dictionary with the global vars

    • @irispecquet7252
      @irispecquet7252 7 месяцев назад

      I did what he said in the pinned comment, but I passed directly the JSON file from the global.ink file in the DialogueManager inspector instead of the loadGlobal JSON file.

  • @direpixel4947
    @direpixel4947 2 года назад +1

    Great video series by the way! At roughly 11:30 you show how to change a variable in the dictionary, but the way you are managing it is inefficient. Instead of removing and re-adding it with the new value, you can simply use this statement since you already validated that the key exists in the dictionary: variables[name] = value; That will change the value in the dictionary without having to remove it and re-add it.

    • @ShapedByRainStudios
      @ShapedByRainStudios  2 года назад +1

      Thank you for the kind words and thank you for sharing! 🙂 That's a much better way to write that portion of code and I'll definitely be doing it that way myself from now on!

  • @oliviapinson9043
    @oliviapinson9043 Год назад +1

    What's the best way to have the ink file play a different line of dialogue the second time you interact with an NPC and so on? I know sequences are a thing but that only seems to work within the actual instance of the ink file-- the way it's programmed in your tutorials seems to make a new nstance each time instead. I decided to just do it by iterating a global var each time you talk to one, but I feel like there's gotta be a better way. Thanks for your tutorials! They've been super helpful!

    • @ShapedByRainStudios
      @ShapedByRainStudios  Год назад

      Hey there! Really glad the videos have been helpful!
      In the system from these videos, the most straight forward way I can think of is probably what you're already doing with iterating a global variable.
      If you find yourself needing to do that in a lot of situations though - you could try to go with something similar to the alternate approach described below:
      Consider using something like an Ink External Function to exit dialogue mode instead of exiting when the story is completed.
      The idea here is that since you'd be exiting before the story is completed, you could keep the stories state such that it resumes at the same point you left off when talking to that NPC again.
      Of course, this would require that you don't reset the story state between dialogue (which we *are* doing in this tutorial series). This can be done by creating the Ink Story object in the trigger event script and passing that through to EnterDialogueMode(..) rather than creating the Ink story in the DialogueManager.
      This would also allow you to use things like sequences by having the Ink story loop infinitely and exiting only with that Ink External Function call.
      I have a video on Ink External Functions (if you haven't already seen it) here which should hopefully help. They're basically just a way of calling a C# method from your Ink dialogue file and can come in handy for a lot of things. - ruclips.net/video/dwxu4Q-GJU0/видео.html
      There are a lot of different ways you could go about this, but I hope that helps give you another idea to work with! Best of luck!

  • @gamerex2730
    @gamerex2730 2 года назад +2

    Thank you for the tutorial! Just 2 quick questions though:
    What function should I be using to convert ink value types into c# types and vice versa (e.g. an IntValue to int and vice versa)?
    Any idea on how to go about getting the type an Ink.Runtime.Object variable that I can use in a switch statement?

    • @ShapedByRainStudios
      @ShapedByRainStudios  2 года назад +3

      Hey there and no problem! 🙂
      The below two examples are using a boolean type, but you'd just change the syntax slightly for other types (string, int, etc...). Unfortunately, you do need to know the type of that variable ahead of time to choose the correct type syntax.
      *Ink.Runtime.Object to a C# type*
      // typecast the Ink.Runtime.Object as a BoolValue, which is a type that extends from Ink.Runtime.Object
      Ink.Runtime.BoolValue pokemonChosenBoolValue = (Ink.Runtime.BoolValue)
      DialogueManager.GetInstance().GetVariableState("pokemon_chosen");
      // from there, you can call .value which will give you the C# type
      bool pokemonChosen = pokemonChosenBoolValue.value
      // alternatively, you can do this all in a single line
      bool pokemonChosen = ((Ink.Runtime.BoolValue) DialogueManager.GetInstance().GetVariableState("pokemon_chosen")).value
      *C# type to Ink.Runtime.Object*
      // create a new Ink.Runtime.Object, but when you create it use BoolValue and pass in the value as the parameter
      Ink.Runtime.Object obj = new Ink.Runtime.BoolValue(pokemonChosen);
      To answer your second question, I would recommend converting to the C# type before you use it in a switch statement or other C# logic.
      If the above is a bit confusing - you can watch a couple videos on a Computer Science topic known as 'Polymorphism' - which is the technique being used here to treat the Ink.Runtime.Object as different object types (BoolValue, StringValue, etc...).
      I hope that all helps!

  • @drreamzz7499
    @drreamzz7499 2 года назад +2

    Hello, Trever, you have great tutorials that helped me a lot. Thank you for your hard work. But I have a question. Maybe I didn't catch up on something, so if it was mentioned, please excuse me, but how do I change a variable from Ink through C# code?

    • @ShapedByRainStudios
      @ShapedByRainStudios  2 года назад +10

      Hey there! No problem and thank you for the kind words!
      I should have included that in the tutorials as a good amount of people have asked about this haha. Luckily, it's a pretty simple edition to what's already there.
      To change one of the global Ink variables from any C# script, you can add the below 'SetVariableState' method to your DialogueManager.
      // this method will allow of a variable defined in globals.ink to be set using C# code
      public void SetVariableState(string variableName, Ink.Runtime.Object variableValue)
      {
      if (dialogueVariables.variables.ContainsKey(variableName))
      {
      dialogueVariables.variables.Remove(variableName);
      dialogueVariables.variables.Add(variableName, variableValue);
      }
      else
      {
      Debug.LogWarning("Tried to update variable that wasn't initialized by globals.ink: " + variableName);
      }
      }
      Then, you'd call it from another script with something similar to the below line to change a variable by name. You'd use StringValue, IntValue, etc.. depending on the type.
      // convert the variable into a Ink.Runtime.Object value
      bool pokemonChosen = false;
      Ink.Runtime.Object obj = new Ink.Runtime.BoolValue(pokemonChosen);
      // call the DialogueManager to set the variable in the globals dictionary
      DialogueManager.GetInstance().SetVariableState("pokemon_chosen", obj);
      I hope that answers your question!

  • @unluckyyooo6598
    @unluckyyooo6598 Год назад +1

    Is there a way to set value from c# instead of just read?

  • @abrahamlopezdelgado8415
    @abrahamlopezdelgado8415 Год назад +1

    Hi Trever! I'm enjoying so much with your incredible tutorial! 😄
    I'd like to ask you how can I call a function in c# according to the choice selected.
    Thanks again!😋

    • @ShapedByRainStudios
      @ShapedByRainStudios  Год назад +1

      Hey there! Glad you're enjoying the tutorial! 🙂 Take a look at something called 'Ink External Functions'. I don't currently have a video on them, but that's likely what you'll want to use for calling C# code based on a choice.
      Scroll down to the 'External Functions' section on this page to see more on them. github.com/inkle/ink/blob/master/Documentation/RunningYourInk.md
      Hope that helps and best of luck!

  • @TriNguyen-kq9iq
    @TriNguyen-kq9iq Год назад +2

    Hi dude! I just want to ask how to change those Ink variables in C# Scripts? I dun'no what to do.

    • @ShapedByRainStudios
      @ShapedByRainStudios  Год назад +1

      Hey there! You'll want to add a 'SetVariableState(..)' method similar to how we set up GetVariableState() - except it'll set a variable in that dictionary instead of get one. I have the code for this stubbed out on my Discord under the FAQ channel (look for the post 'How do I change Ink variables from a Csharp script') if you want a bit more guidance. I hope that helps! 🙂

  • @Darkho1y
    @Darkho1y Год назад +1

    While regular observer is more or less documented on git VariableChangedEvent is not mentioned anywhere unless you dive into VariablesState def... Was it how you found it or Im missing some documentation online? Thanks!

    • @ShapedByRainStudios
      @ShapedByRainStudios  Год назад

      Hey there! I don't remember exactly how I came across the VariableChangedEvent stuff. There's a good chance I just came across it when playing with stuff in my IDE. A lot of my learning for this series was a combination of looking at the docs and trying different stuff based on IDE suggestions. If I remember right, there were unfortunately some things missing in the Ink docs. I hope that helps and best of luck!

  • @Rangeon
    @Rangeon 3 года назад +2

    Hi! Can you make a video on how to play a sound every time it types a character?

    • @ShapedByRainStudios
      @ShapedByRainStudios  3 года назад

      Hey there! I do want to do some tutorials on creating a sound management system at some point (probably separate from these dialogue system tutorials). I'll keep this in mind for when I get around to making those! 🙂.
      Until then, be sure to check out the below video on the typing text effect if you haven't already. In that video, whenever you add a letter to the TMPro object, you can play a sound, which should accomplish this.
      Unity typing text tutorial video - ruclips.net/video/2I92egFvC80/видео.html
      As for playing the sound - in Unity you can use an 'Audio Source' component.
      Thanks for the suggestion and I hope that helps!

  • @datadonascimento
    @datadonascimento Год назад

    i was able to setup the global variables just fine, but what about local variables that are declared in the individual ink files? i could not find a way to detect the var changes using the variableChangedEvent subscription

  • @johnsonxu2589
    @johnsonxu2589 3 года назад +3

    Hi, Thanks a lot for this tutorial. I just have a little problem. I followed all these tutorial, when I finished a dialogue with Layout on the right, and go talk to another NPC, the Dialogue remains Layout on the right through the rest of Dialogue. This won't happened if the Dialogue is finished by NPC, which the Layout is on the right.

    • @ShapedByRainStudios
      @ShapedByRainStudios  3 года назад +1

      Hey there! How the system is set up through that dialogue portraits/layouts/names tutorial is that it'll only change when you use an Ink tag, so I believe what you described is expected if you're not using an Ink tag at the start of new dialogue.
      *Are you using Ink tags and it's just not changing?* - if so, this could either be that animation keyframes are missing for the layouts (it's super easy to miss some) OR something is off in your switch statement that parses in the Ink tags.
      *OR do you want the dialogue to default to the left (or right) for every new dialogue without having to use Ink tags?* - If so, you can include the logic to default it in the EnterDialogueMode() method just like it's changed during the switch statement.
      I also recommend putting Debug.Log("") statements around the code to ensure things are happening how you expect them to be. That'll help narrow down the problem.
      I hope that answers your question! 🙂

    • @ZisTraxMop
      @ZisTraxMop 2 года назад

      I had the same issue, only in my case the layout was stuck to the left (default is right). I just added a line to bring the layout back to its default state before closing the dialogue box.

  • @jonanabanana5817
    @jonanabanana5817 3 года назад +2

    How would I go about asking for the player's name and logging that information into a variable to be used in my story? I don't think inky supports a player input feature and if I use something like an input field and store the name data in a string in some script, I don't know how to get my ink files to access that string variable since the method in the video only shows how to reference variables from other inky files.

    • @ShapedByRainStudios
      @ShapedByRainStudios  3 года назад

      Hey there! You have the right idea. 🙂 You'd want to handle player input for the name on the Unity side (so an Input Field like you mentioned) and then you can call the DialogueManager to set that variable in the DialogueVariables dictionary.
      To make that possible, you just need to add a 'SetVariableState(..)' method in the DialogueManager. Then, you can call that from other scripts to store variables in the dictionary that then can be used by both your C# code and Ink. Of course, you'd also want to add the variable to your globals ink file.
      If you want to see an example of a 'SetVariableState(..)' method, check out my response to a comment on this video made by Marko Rossie. I stubbed that method out there that you can copy/paste.
      I hope that helps!

    • @jonanabanana5817
      @jonanabanana5817 3 года назад

      @@ShapedByRainStudios Thanks for the reply, I have one last question. I'm a beginner at coding so this might just be super obvious but how do I convert a string into an ink.runtime.object value. I created an InputName script that would be called when the player submits their response, but I can't figure out how to fulfill the second parameter of the SetVariableState method that you provided under Marko Rossie's comment.
      public class InputName : MonoBehaviour
      {
      private string playerName;
      public GameObject inputField;
      public void RegisterName()
      {
      playerName = inputField.GetComponent().text;
      DialogueManager.GetInstance().SetVariableState("playerName", /*Don't know what to put here?*/ );
      Debug.Log(playerName);
      }

      }
      thanks a bunch again

    • @ShapedByRainStudios
      @ShapedByRainStudios  3 года назад

      @@jonanabanana5817 Hey! It's definitely not super obvious, especially if you're more of a beginning to programming.
      Ink.Runtime.Object is a parent class to other classes like Ink.Runtime.StringValue, InkRuntime.BoolValue, etc... Or to put it differently, classes like Ink.Runtime.StringValue all inherit from Ink.Runtime.Object by extending them.
      That means that you can pass in a Ink.Runtime.StringValue and it will be recognized as a Ink.Runtime.Object. In programming, this is referred to as polymorphism (if you're interested in looking more into how that works - just look that word up).
      So TL;DR - you can use the below line to call the SetVariableState method and that should work.
      *DialogueManager.GetInstance().SetVariableState("playerName", new Ink.Runtime.StringValue(playerName));*

    • @jonanabanana5817
      @jonanabanana5817 3 года назад

      @@ShapedByRainStudios Everything turned out good. Thank you so much and thanks for the fast response!

  • @noahboisard8450
    @noahboisard8450 2 года назад +1

    Hi, thanks for the tutorial, I was wondering if you could do the opposite ? as in initializing a variable through code and then reading it in ink. I'm sorry if this was asked before, but I couldn't find any info on the subject, any result I got was like you did, going from ink to code

    • @ShapedByRainStudios
      @ShapedByRainStudios  2 года назад +1

      Hey there and glad you found the video helpful! 🙂 With this setup, the variable needs to be declared in the globals.ink file. This is mostly because the Inky editor will complain and potentially not compile if it can't find those variable references. Unfortunately I'm not aware of any way around that.
      That said, you CAN change it on the C# side after it's been declared in the globals.ink file.
      If you want to change variables from C# scripts, you'll need to create a 'SetVariableState' method similar to 'GetVariableState' in this video, but of course, set the variable in the shared globals dictionary rather than get it. As long as it's modified in that dictionary and ALSO exists in the globals.ink file, you'll be able to modify those variables through C# code.
      I have an example of this stubbed out on the FAQ channel of my Discord if you want an example to go off of. Hope that helps and best of luck!

    • @noahboisard8450
      @noahboisard8450 2 года назад

      @@ShapedByRainStudios thanks for the answer! It's gonna help a lot !

  • @sgtcuddlekins5171
    @sgtcuddlekins5171 2 года назад +1

    Hey man hope you're well. I've been really enjoying this tutorial series and it's been extremely helpful to me in my project. I'm just wondering if you would be able to quickly explain to me how to include ink files that aren't in the same folder? In this video you quickly mention it but I can't quite seem to figure it out for myself.
    In my Assets folder I have a folder called Dialogue, and within it I have folders for all sorts of ink stuff, including a folder for Globals where the globals.ink is. Hopefully this makes sense
    Many thanks, keep up the good work!

    • @ShapedByRainStudios
      @ShapedByRainStudios  2 года назад +2

      Really glad to hear the tutorial series has been helping and thank you for the kind words! As long as *all of your dialogue files are in the Assets directory of the Unity project* , you'll be able to navigate between them using Relative Pathing. You can Google that term if you're unfamiliar with the concept and a lot of resources should pop up.
      In short though, think of it like you're starting from whatever directory the current file is in and you can use *..* to go backwards a directory. So in your case, it sounds like you might want to do something like ../Globals/globals.ink (backwards a directory and then into the Globals folder).
      That said, I remember seeing someone mention a bug on the Inkle Github page about how sometimes it shows an error in Inky for the Include path even when it's correct - but it actually compiles just fine. The issue I'm thinking of was pretty dated though (5+ years if I remember right) and I believe they fixed it. I don't think you'd run into that issue, but figure it's worth mentioning.
      I hope that helps a bit and best of luck! 🙂

  • @adamhanusek2746
    @adamhanusek2746 2 года назад +1

    Everything is amazing, thank you but... how does the -= and += works with functions? It's confusing me a little

    • @ShapedByRainStudios
      @ShapedByRainStudios  2 года назад +1

      Hey there and glad to hear that! 🙂 += and -= can be used to add or remove floats, strings, and even delegates in C#. In the case of this video, we're using using += and -= to add and remove the VariableChanged() function (delegate) as a listener for when a variable is changed.
      It can definitely be a bit confusing, but here are the C# docs for += which might help a bit more - learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/addition-operator

    • @adamhanusek2746
      @adamhanusek2746 2 года назад

      @@ShapedByRainStudios thank you

  • @jaeeee_lyn
    @jaeeee_lyn 3 месяца назад

    Hi, I realised that when I edited the variable names in my globals.ink file, Unity is not reading the new variables name properly. instead it is still reading the old variable names. how do I resolve this? is there something wrong with my DialogueVariables script?

  • @dongn405
    @dongn405 3 года назад +1

    This tutorial was extremely helpful, thank you. I do have a question about dynamically updating Ink files from a c# script; is this possible?
    How would you manage a shopkeeper giving you an item, but saying something like "you don't have enough room" if your inventory is full, etc

    • @ShapedByRainStudios
      @ShapedByRainStudios  3 года назад +1

      I'm glad to hear you found it helpful! 🙂
      You should be able to make a slight modification to this tutorial to dynamically update Ink files from your C# code (although I haven't completely tested what I'm about to outline, so be sure to let me know if this doesn't actually work or if you find issues).
      I'm assuming what you mean by 'dynamic' is that the story is already running when you need the update to occur. If that's not the case, and you're just trying to set variables via C# code, you can ignore step 1.
      1 - Create an UpdateStoryState method in the DialogueVariables class that updates the variable state in a story. You can use your VariablesToStory(..) method, but you'll need to drop/re-add the variableChangedEvent listener before you do so.
      2 - Create a 'SetVariableState' method in the DialogueManager that can be used to set a variable in the Dictionary through C# code. At the end of that method, call the 'UpdateStoryState' in step 1 so that the story updates dynamically.
      As for something like managing inventory - I would just set a globals variable to your inventory size (maintained on the C# side) and update it anytime you enter dialogue (so in the DialogueManager EnterDialogueMode method or somewhere similar). That way, when you enter dialogue the inventory size is always accurate. Then, you can check against that in your Ink file logic.
      I hope that helps answer your questions! See the comment I made back to Marko Rossie on this video on an example of a 'SetVariableState' method.

  • @luluskuy
    @luluskuy Год назад

    Hi! is this works with your save system? so when we save the game, the global file is also saved?

  • @ignitingillumination9805
    @ignitingillumination9805 3 года назад +1

    I've been trying to find a solution for doing user input, but as far as I know Ink does not support that. Do you know of a workaround to get user input in unity and have that used within the Ink scripts? Thank you! Great videos! I have learned so much from you and can't wait to see more :D

    • @ShapedByRainStudios
      @ShapedByRainStudios  3 года назад +1

      I'm really glad you've found the videos helpful! 🙂
      That's a really interesting use case. I don't believe there's a great solution for this in Ink/Unity, but you could set variables in the Ink story depending on player Input. I'm not sure how the Unity-Ink plugin will handle that performance-wise, but it might be fine.
      So for example, you'd...
      (1) Have a variable called 'JumpPressed' declared in your globals.ink file.
      (2) Then, add a 'UpdateVariableState' method in your DialogueManager that you can use to update a variable in the Dictionary via C# code - similar to how 'GetVariableState' exposes values to be readable in this tutorial.
      (3) Then, in a C# script where you're handling Input, you'd set the 'JumpPressed' variable to true/false depending on the players input.
      (4) Last, you'd want to load those variables into the current story every frame (or at least when they change) when dialogue is playing. In other words, call the VariablesToStory() method in this tutorial every frame.
      That's at least what comes to mind for how I'd approach this. I hope that helps!

    • @ignitingillumination9805
      @ignitingillumination9805 3 года назад

      @@ShapedByRainStudios thank you so much for the detailed reply!

  • @arthurjacquey42
    @arthurjacquey42 2 года назад +1

    Hey ! I'm a beginner and I want to create a system of this style: "If you speak a Character1, Character2 have a new dialogue" with boolean, but i don't know update new variables on my script :/ can you help me ? Thanks !

    • @ShapedByRainStudios
      @ShapedByRainStudios  2 года назад +2

      Hey there! I believe the video covers what you're asking. I go over a simple example briefly at 4:50 in the video to update a variable from an Ink file. With this system, the variable observer will pick up that change and make it in the dictionary so it can be referenced across other Ink files (hence other NPCs).
      Or Are you asking how to update the variables from a C# script? In that case, take a look at my response to a comment on this video by ツDrReaMzZ . I outlined the code you'd need to add to make this possible.
      If it's neither of those - feel free to clarify and I'm happy to try and help you figure it out. 🙂

  • @bacjam6139
    @bacjam6139 2 года назад +1

    Amazing tutorial series, but I have a question how would you go about despawning an npc once their dialogue has finished then spawning in a different npc?

    • @ShapedByRainStudios
      @ShapedByRainStudios  2 года назад +1

      Hey! Thanks so much, I'm glad you've been enjoying it! 🙂There are a lot of ways you could go about this depending on your game.
      1 - The most straight forward way from where this tutorial leaves off would be having a variable in your globals file to determine if the NPC should be active or not. Then, you could set that variable true/false at the very end of the dialogue and use a script similar to the one used to change the pokemon color in this tutorial, except set a gameobject active/inactive based on the variable.
      2 - A more direct way could be to use Ink External Functions and call a binded function at the end of the ink file. This is more or less the same as the previous solution I mentioned, but could be worth looking into. Scroll down to the External Functions section in this doc for more info on how those work - github.com/inkle/ink/blob/master/Documentation/RunningYourInk.md
      You could also include logic in your ExitDialogueMode() method, but that would require a good amount of set up to do in a flexible way. I would give one of the above two methods a try. I haven't messed with this much myself, so if for any reason what I recommended isn't working - let me know and I'll take some time to dig deeper. I hope that helps!

  • @REFRAME_267
    @REFRAME_267 3 месяца назад

    9:55 DialogueVariables & Dialogue Manager

  • @Jourlik
    @Jourlik 2 года назад +1

    Hello, is there any way to start method from ink file? Or can i only place some kind of a tag, for example boolean, and if it's true then i call it with the HandleTags method?

    • @ShapedByRainStudios
      @ShapedByRainStudios  2 года назад +1

      Hey there! 🙂 There is! I don't currently have a tutorial for it, but Ink External Functions will allow you to call a C# function from your Ink file. Docs can be found here for them (scroll down to the External Functions section) - github.com/inkle/ink/blob/master/Documentation/RunningYourInk.md

    • @Jourlik
      @Jourlik 2 года назад

      @@ShapedByRainStudios thanks for a fast answer!

  • @Jiminal_
    @Jiminal_ 2 года назад +1

    Hello there Trevor! Amazing video however, I was wondering is there a way to have special dialogue choices if you choose a specific dialogue? Like in the game ‘Kindergarten’ let me know, thanks!

    • @ShapedByRainStudios
      @ShapedByRainStudios  2 года назад

      Thanks for the kind words, I'm glad you found the video helpful! 🙂 I haven't played 'Kindergarten' myself, but if I'm understanding correctly - there is!
      Ink has something called 'Conditional Choices' which sound like what you're looking for. You can use variables (whether they're global or just local) to turn the choices on/off. Here's some documentation that should help you get started with them - github.com/inkle/ink/blob/master/Documentation/WritingWithInk.md#conditional-choices

    • @Jiminal_
      @Jiminal_ 2 года назад

      @@ShapedByRainStudios Thank you so much this sounds just like what I’m looking for, I’ll defiantly look into that

  • @addisonjacoby
    @addisonjacoby 2 года назад +1

    Since you can set Ink variables via code would it make any difference/be better to move the Global Variables to a C# script instead? Could still do the init on start up but would fix the issue of having to compile the ink into json as well has giving other scripts a little bit easier access to all the globals? Great tutorial regardless love the content!

    • @ShapedByRainStudios
      @ShapedByRainStudios  2 года назад +1

      Hey there! I think that would be a really interesting thing to play around with and is probably possible given a bit of tinkering!
      That said, the main issues I can imagine you'll run into are (1) the Ink dialogue files themselves may not compile if they're missing references to the global variables, but I'd have to test that to be sure. And then, (2) the Inky editor will complain it's missing references to those variables, so you would loose the ability to troubleshoot your dialogue in Inky.
      Instead, I recommend adding a 'SetVariableState()' method, similar to GetVariableState(), to set variables in the Dictionary from your C# code (if you haven't already). Then you'll be able to both access and modify those variables from C# code like you mentioned. I have a example of this stubbed out on my Discord server if that's something you're looking to add.
      Thank you for the kind words and I hope that helps! 🙂

    • @addisonjacoby
      @addisonjacoby 2 года назад

      @@ShapedByRainStudios Oh good points! I am still in the newer stages of learning ink, I did not think about that. Thank you for taking the time to provide such a detailed response! I will checkout the discord!

  • @the_timme
    @the_timme 2 года назад +1

    Hey mate, first of all awesome tutorial series, really appreciate it!
    I have a slight issue, probably only an oversight on my part, but as soon as i include the Ink file with the global variables in any other ink file, the file with the variables does not get compiled anymore (and the already compiled version disappears from the project view). Thus i can not drag it into the Dialogue Manager. Can you help me figure out what I am doing wrong?

    • @the_timme
      @the_timme 2 года назад

      yeah nvm i got it. again, great work :)

    • @ShapedByRainStudios
      @ShapedByRainStudios  2 года назад

      @@the_timme Right on! Thanks so much for the kind words and glad you were able to figure it out! 🙂

  • @garulouie
    @garulouie 10 месяцев назад +1

    How can I get if the player has already talked to a specific NPC?

    • @garulouie
      @garulouie 10 месяцев назад

      For anyone looking for an answer to this, I found one! Pretty much repeat these steps, with the DialogueVariables functions, variables, etc in your DialogueTrigger script. Make sure to replace "DialogueVariables" with DialogueTrigger, as well as make a seperate file to hold the alreadytalked variable as if it was a globals variable for the specific ink file and a loadvariablesfile for it.

  • @priskon5950
    @priskon5950 Год назад

    How would you change an Ink's global variable through script?

  • @ImaginatorPage
    @ImaginatorPage 2 года назад +1

    Hey there Trever, great video as always, it helped me a lot! I’m kinda stuck in my project though because I used this system to change scenes (if the dialogue choice == yes, load scene, else return) and it works, but when I stop playing and hit play again, the second scene automatically loads. And if I try to go back to the previous one, I can’t as well, it loads the next one as soon as I try to go back. Could you maybe have some ideas on how to make the variable reset every time a new scene is loaded? Maybe it has something to do with the PlayerPrefs system, and I’m not a coder at all so it’s been really difficult to try and fix this on my own 😅 thanks in advance!

    • @ShapedByRainStudios
      @ShapedByRainStudios  2 года назад +1

      Hey there! Thanks for the kind words and I'm glad you've been finding these videos helpful! 🙂 Scene transitions can be really tricky. It's really hard to recommend concrete things without knowing how your game/scenes are set up, but here are a couple things to think about which might help give some direction.
      1 - If the second scene is automatically loading when you press play and you're using PlayerPrefs to keep track of this in some way - that's likely where the issue is. You can try to clear PlayerPrefs in the Unity top-left menu (Edit -> Clear All PlayerPrefs) to see if that fixes the issue temporarily. If that does fix it for the next time you play, you'll be able to narrow down the issue to how PlayerPrefs are being handled. In that case, you may want to clear certain PlayerPrefs when the game first starts up, which there are lots of ways to do that can be seen here - docs.unity3d.com/ScriptReference/PlayerPrefs.html
      2 - This may not be related to your issue at all, but when transitioning scenes this way, I would ensure that ExitDialogueMode() gets called _before_ you do the scene transition. I only mention this because I know of others who have done something similar and have run into issues with Dialogue still playing, the player being frozen, etc.. in the new scene - which typically have related to Dialogue Mode not exiting between the transition.
      I hope that helps a bit and best of luck to you!

    • @ImaginatorPage
      @ImaginatorPage 2 года назад

      @@ShapedByRainStudios Thank you so much for the help man! The issue was atually simples than I thought, I just had to create another script to change the same variable that was changed before with another dialogue choice! Then the variable doesn't persist the same, and as a result the player doesn't get stuck in the same scene forever. Thanks again and keep up with the amazing work!

  • @tontonton5791
    @tontonton5791 2 года назад +1

    Hello thank you for the great tutorials!
    I have been trying what JonanaBanana did with inputting a name and saving it. but i am getting an error of "object reference not set to an instance of an object" on the code DialogueManager.GetInstance().SetVariableState("playerName", new Ink.Runtime.StringValue(playerName));
    my globals ink file just have this:
    VAR playerName = ""
    I'm new to unity so i may have missed something. I hope you can help me. thanks!

    • @ShapedByRainStudios
      @ShapedByRainStudios  2 года назад

      Hey there! That syntax for those two lines looks correct to me. Unfortunately there could be a lot of different things going on to cause the error you're seeing. Here are a few things that come to mind that you can double check.
      1. If you look at the error call stack in the Unity console (click on the error in the console output), sometimes it might point you to a spot in the code where the error is happening. This can be really helpful in narrowing it down a bit more, so I would take a look at that first thing.
      2. The name input (the DIalogueManager.GetInstance.SetVariableState(..) line) might be happening _before_ the globals dictionary has been initialized. This seems unlikely, but might be good to confirm the order in which these happen by putting in some Debug.Log(..) statements.
      3. The DialogueVariables object, Dictionary, or something else isn't getting initialized. Double check that you're creating a 'new DialogueVariables(..)' like at around 8:20 in the video. Likewise, ensure that the DialogueVariables constructor is initializing the dictionary as well like at around 10:10 in the video.
      4. It could also be that something isn't dragged into the Unity inspector that should be. Double check that all of the items have been dragged in as it's a really easy thing to miss. Specifically, the stuff at around 10:56 in the video.
      I hope that helps a bit and best of luck! 🙂

    • @tontonton5791
      @tontonton5791 2 года назад

      @@ShapedByRainStudios Thanks for the reply! I will be double checking everything