I've encountered what I think is a bug with InkObjects. I've created items similarly to your example. However, my items have some variables that are not [InkVisible], for example, the item's sprite or description. The problem is that, during runtime, all the variables not marked [InkVisible] become empty.
Hello Julian, this package is helping me a great deal! However, I'm having trouble with the Runtime Objects. I'm using the method OnInstanceFieldValueChanged() to update my UI. As I understand it, every time Ink changes a variable of a specific InkObject, this method is triggered. However, is there a way of knowing which is the variable that changed? I want to avoid checking all variables one by one every time one of them changes since there are a lot. Thank you in advance!
Hey Ireth. Great to hear you are making use of the Runtime Objects! Thanks for the idea - I just pushed version 1.1.1 with the functionality you are requesting. Check out the HealthBar example for how to use it and let me know if you have any more questions or requests!
It would help to optimize my code if I could pass on parameters to the Action of AddFieldCallback(). As you can see in the image below, There are some repetitive actions that could be simplified in a single action that takes two parameters:
For example: UpdateAbility(GameObject ability, int value).
In this case I would need two parameters, but other actions may need more, or less parameters. Is it possible to update your code so the Action taken by AddFieldCallback() could take a variable number of parameters?
I hope it's not too much to ask! I've been looking for ways to do it but I can't figure it out. You're no doubt a better coder than me, though! ;)
It is not necessary to store the lambda in a local variable ("conLambda"), typically I would just pass it directly as the second parameter of AddFieldCallback, but I broke it out into its own line for clarity.
The basic way I think about lambdas is that they declare a function that operates on a given set of parameters.
(param0, param1, etc.) => [turns into] [action on parameters]
In this case, your function operates on no parameters, hence the empty parentheses at the start of the lambda declaration.
From the perspective of the InkObjects system, using an Action with no parameters makes the most sense for a FieldCallback, as the system does not have any data that it needs to pass along when it invokes the action (though I could imagine a very complete system might want to pass along the name and value of the field that is being updated, and maybe I will push an update later that has that functionality, but it wouldn't accomplish what you are trying to do).
Anyway, let me know if you have further questions or encounter any other issues!
Hi Julian. Thank you so much! I had never heard of lambdas before. It's silly that simply adding " () => " in front of the function magically makes it work as an Action (well, I guess the action is to call that function). I had been trying to do just that for the longest time.
Now I just need to solve one last challenge that has to do with InkObjects... something that I'm starting to fear might be impossible. I hope I'm wrong! I want players to be able to create their own characters, and use them inside the Ink story.
The way I'm trying to accomplish that is by replacing the values in the InkObject I call "Hero", which is a type of InkObjectHero I created, with the values introduced by the player right before the story starts. This seems like the simpler approach, but the Internet doesn't seem to like the idea of modifying scriptable objects at runtime. Instead of finding tutorials on how to do it, all I find are people saying "don't do that!".
So the other thing I tried is creating a new InkObjectHero at runtime and assigning it as the LibraryObject to observe. However, I've run into a couple problems with this method. Firstly, the ObjectLibrary needs to be rebuilt at runtime in order to include the new Hero, which I don't know how to do (or even if it's possible). And secondly, assuming I could do that, when I add new heroes to the Resources folder they are assigned a new ID, and my story is currently written to use the first ID (0) as the original Hero. I'd somehow need to pass the ID of the Hero the player created to the story. Or maybe change the order in which the Objects are specified in the "Specified Objects List" before updating the Library at runtime, in order to make the new Hero be the first.
I don't know, maybe there is a much easier way to approach this that I'm not seeing. I hope you can shed some light! Or, at least, let me know if it's even possible to do! Thank you so much in advance!
Well there is no inherent issue with changing values of a Scriptable Object at runtime in Unity. Some people might not like it for stylistic reasons but it's certainly possible. But I don't think that is what is causing you problems in this case.
The issue you are running into is specifically with InkObjects and where they "live."
The InkObjectLibrary can only be modified while authoring the game/story. InkObjects is a tool which can be used to populate your Ink story with data that can be manipulated in Ink and read back by Unity. But once you export your library to Ink, your InkObjects live in Ink and can only be modified in Ink.
If you notice that the InkObject asset in your Unity project is grayed out and not editable during play mode, this is because there is a custom UnityEditor for InkObjects that is doing that manually and reflecting the values from the Runtime instance of that Library Object. This is because changing the Library Object after exporting the Library to Ink will have zero effect on your game (apart from being very confusing).
If you want the user to modify the player character, that will need to happen in Ink, just like any other part of the Ink story. I know some things might be difficult to achieve (for example text entry) but many things will be easy to change interactively within Ink through choices. Your app could skin the choices to make it look like a more typical character design interface.
I will look into potentially expanding the InkObject system so that you can push overrides to InkObjects from Unity to Ink at runtime. I agree that would be very useful, though in my basic research into Ink my understanding was that pushing data to Ink was unsafe (for example, the Ink docs do not recommend changing values via external function).
← Return to package
Comments
Log in with itch.io to leave a comment.
Hello Julian, it's me again! :D
I've encountered what I think is a bug with InkObjects. I've created items similarly to your example. However, my items have some variables that are not [InkVisible], for example, the item's sprite or description. The problem is that, during runtime, all the variables not marked [InkVisible] become empty.
Do you have any idea why this might be happening?
Thank you in advance!
Thanks for the bug report Ireth! Will take a look at it when I get a chance.
Hey Ireth, this bug is now fixed. Thanks again for reporting the issue.
Hello Julian, this package is helping me a great deal! However, I'm having trouble with the Runtime Objects. I'm using the method OnInstanceFieldValueChanged() to update my UI. As I understand it, every time Ink changes a variable of a specific InkObject, this method is triggered. However, is there a way of knowing which is the variable that changed? I want to avoid checking all variables one by one every time one of them changes since there are a lot. Thank you in advance!
Hey Ireth. Great to hear you are making use of the Runtime Objects! Thanks for the idea - I just pushed version 1.1.1 with the functionality you are requesting. Check out the HealthBar example for how to use it and let me know if you have any more questions or requests!
You're awesome Julian! Thanks a lot :D
It would help to optimize my code if I could pass on parameters to the Action of AddFieldCallback(). As you can see in the image below, There are some repetitive actions that could be simplified in a single action that takes two parameters:
For example: UpdateAbility(GameObject ability, int value).
In this case I would need two parameters, but other actions may need more, or less parameters. Is it possible to update your code so the Action taken by AddFieldCallback() could take a variable number of parameters?
I hope it's not too much to ask! I've been looking for ways to do it but I can't figure it out. You're no doubt a better coder than me, though! ;)
Happy to help! I would suggest making use of lambdas - https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/lamb...
So in your case, something like this...
It is not necessary to store the lambda in a local variable ("conLambda"), typically I would just pass it directly as the second parameter of AddFieldCallback, but I broke it out into its own line for clarity.
The basic way I think about lambdas is that they declare a function that operates on a given set of parameters.
(param0, param1, etc.) => [turns into] [action on parameters]
In this case, your function operates on no parameters, hence the empty parentheses at the start of the lambda declaration.
From the perspective of the InkObjects system, using an Action with no parameters makes the most sense for a FieldCallback, as the system does not have any data that it needs to pass along when it invokes the action (though I could imagine a very complete system might want to pass along the name and value of the field that is being updated, and maybe I will push an update later that has that functionality, but it wouldn't accomplish what you are trying to do).
Anyway, let me know if you have further questions or encounter any other issues!
Hi Julian. Thank you so much! I had never heard of lambdas before. It's silly that simply adding " () => " in front of the function magically makes it work as an Action (well, I guess the action is to call that function). I had been trying to do just that for the longest time.
Now I just need to solve one last challenge that has to do with InkObjects... something that I'm starting to fear might be impossible. I hope I'm wrong! I want players to be able to create their own characters, and use them inside the Ink story.
The way I'm trying to accomplish that is by replacing the values in the InkObject I call "Hero", which is a type of InkObjectHero I created, with the values introduced by the player right before the story starts. This seems like the simpler approach, but the Internet doesn't seem to like the idea of modifying scriptable objects at runtime. Instead of finding tutorials on how to do it, all I find are people saying "don't do that!".
So the other thing I tried is creating a new InkObjectHero at runtime and assigning it as the LibraryObject to observe. However, I've run into a couple problems with this method. Firstly, the ObjectLibrary needs to be rebuilt at runtime in order to include the new Hero, which I don't know how to do (or even if it's possible). And secondly, assuming I could do that, when I add new heroes to the Resources folder they are assigned a new ID, and my story is currently written to use the first ID (0) as the original Hero. I'd somehow need to pass the ID of the Hero the player created to the story. Or maybe change the order in which the Objects are specified in the "Specified Objects List" before updating the Library at runtime, in order to make the new Hero be the first.
I don't know, maybe there is a much easier way to approach this that I'm not seeing. I hope you can shed some light! Or, at least, let me know if it's even possible to do! Thank you so much in advance!
Well there is no inherent issue with changing values of a Scriptable Object at runtime in Unity. Some people might not like it for stylistic reasons but it's certainly possible. But I don't think that is what is causing you problems in this case.
The issue you are running into is specifically with InkObjects and where they "live."
The InkObjectLibrary can only be modified while authoring the game/story. InkObjects is a tool which can be used to populate your Ink story with data that can be manipulated in Ink and read back by Unity. But once you export your library to Ink, your InkObjects live in Ink and can only be modified in Ink.
If you notice that the InkObject asset in your Unity project is grayed out and not editable during play mode, this is because there is a custom UnityEditor for InkObjects that is doing that manually and reflecting the values from the Runtime instance of that Library Object. This is because changing the Library Object after exporting the Library to Ink will have zero effect on your game (apart from being very confusing).
If you want the user to modify the player character, that will need to happen in Ink, just like any other part of the Ink story. I know some things might be difficult to achieve (for example text entry) but many things will be easy to change interactively within Ink through choices. Your app could skin the choices to make it look like a more typical character design interface.
I will look into potentially expanding the InkObject system so that you can push overrides to InkObjects from Unity to Ink at runtime. I agree that would be very useful, though in my basic research into Ink my understanding was that pushing data to Ink was unsafe (for example, the Ink docs do not recommend changing values via external function).