I have a list in RoomSO that contains premade ButtonSOs that i created in the editor and dragged and dropped into the list. RoomSO is also premade (made in the editor) Then at runtime i create an instance of a ButtonSO and tried adding it to RoomSO buttons. I look at the RoomSO in the editor and i get "Type mismatch". I canĀ“t understand why?
RoomSO script:
[CreateAssetMenu(fileName = "New Room", menuName = "Rooms/Room")]
public class RoomSO : ScriptableObject
{
public List<ButtonSO> buttons;
public void AddButton()
{
ButtonSO bt = (ButtonSO) ScriptableObject.CreateInstance<ButtonSO>() as ButtonSO;
bt.buttonText = "Hello";
buttons.Add(bt)
}
}
My ButtonSO script:
[CreateAssetMenu(fileName = "New Button", menuName = "Rooms/Button")]
public class ButtonSO : ScriptableObject
{
public string buttonText;
}
You issue isn't really an "issue".
What happens is that usually Unity expects a ScriptableObject asset reference assigned to the fields in the Inspector. Because the actual use-case of ScriptableObject is to have certain exchangeable data/behaviour container assets.
What you are doing is creating instances on runtime. These instances are only stored in the temporary memory since you never actually store them as assets into your project.
You will see the type mismatch in the Inspector, but actually this means there is a valid reference - otherwise it would say either None (ButtonSO) or Missing (ButtonSO), it only won't be saved once the Playmode ends. The later Missing (ButtonSO) you will see after ending the Play Mode since the List<ButtonSO> will still exist, also the items within it - but the according references you created during runtime will be destroyed.
Your runtime code should still work as expected as long as the Play mode is running.
The same happens btw if you assign e.g. a GameObject field within a ScriptableObject with a reference from the Scene during runtime.
In general though: If you create these instances on runtime - why do they need to be ScriptableObjects? You could just use a normal class.
Related
Can someone please help me with this, am trying to use OpenFileDialog class from System.Windows.Forms to open a file dialog and read the selected file. Then, this error showed up. I've referenced it but still the same, below is the code.
`using UnityEngine
using UnityEngine.UI
using System.Windows.Forms;
public class OpenFileButtonScript : MonoBehaviour
{
public TextFieldScript textFieldScript;
public void OpenFile()
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "Text Files (*.txt)|*.txt|All Files (*.*)|*.*";
openFileDialog.FilterIndex = 1;
openFileDialog.Multiselect = false;
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
string filePath = openFileDialog.FileName;
string text = System.IO.File.ReadAllText(filePath);
textFieldScript.inputField.text = text;
}
}
}`
It may look like you have access to all of the native Window system libraries, but it just looks like it. In actuality, a lot of the time you're simply given stubs, or shims, that look like the full Window libraries, because there's a certain element that Unity wants to use from those namespaces. If you think about it, the code you present above, what do you think it should do on Android or Nintendo devices? The simple answer is, it simply won't work.
Generally in cases like this, you have to gain access to the native operating system, and perform those calls directly. For example, there is a file browser asset on the Asset Store, that does this for you. It's not free, because the process isn't trivial.
Depending on how much effort you want to put in, you CAN read files from the local file stores (to varying degrees based on platform). It's possible to read the list of files in a location, and use either uGUI or UIToolkit to create your own File Open Dialogue box. Again, this isn't a trivial task either. So you have to be sure that you'd want to go down that path.
This seems like a very basic question, but I can't seem to figure it out. I am trying to make a crafting system in unity. I made an inventory system with an items that are scriptable objects storing the name of the item as a string and amount of the item as an int. To add the crafting system, I am trying to make recipe scriptable objects that hold a list of items, the amount needed per item, and the output item of the recipe. My code for the recipes is as follows:
public class Recipe : ScriptableObject
{
new public string name = "New Recipe";
public List<Item> requiredItems;
public Item outputItem;
}
The problem is that I want to have each item in the list of required items have their own amount which I can set, but I can't seem to get it to work. I can only make it so that there is one amount variable for all the items or I have to make a new list for the amounts of the items, which I don't think is a good idea. Is there any way I can contain both the item and amount in the same list?
I would suggest making a struct that holds the name and amount of the reguired item. To find the referenced item at runtime make a singleton manager and hold references to all items in that manager. This way you overcome the limitation of always getting only one item out of a recipe at the same time as well (e.g. 5 sticks from 1 log).
public struct CraftingItem
{
public string itemName;
public int itemAmount;
}
public class Recipe : ScriptableObject
{
new public string name = "New Recipe";
public List<CraftingItem> requiredItems;
public CraftingItem outputItem;
}
I've created a brand new test scene that only contains a prefab which has a list variable containing 3 scriptable objects (located in my project Resources folder) and a script graph containing my flow which logs a count of the list to the debug log, and prints the description of the first scriptable object in the list.
Everything works fine when I test in the Unity editor, but when I build for iOS and run it on my phone, the scriptable objects data never gets loaded (in this case, the description.) You can see in the mobile console that there's an error for a missing arg which is where the description is connected.
Here's the code from my script that defines the SO:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName = "New Item", menuName = "Item")]
public class Item : ScriptableObject
{
public string itemname;
public string description;
public Sprite icon;
public bool consumable;
public Targets target;
public int range;
public StatTypes stat1;
public int stat1Value;
}
This script is located in my Assets/Scripts/ScriptableObjects folder.
Unity screenshot
Here's my script graph:
And here's the console log on iOS:
I'm using Unity version 2021.1.15f1
My scriptable objects are located in the Assets/Resources/Items folder
I've tried regenerating my units in the Visual Scripting project settings, and 'Item' is added as a type in the list of node types.
Everything works fine in the Unity editor.
I've been working on this solidly for hours and can't seem to get anywhere, so your help will be much appreciated.
I have created a few TextMeshPro UI InputFields in Unity and can't seem to access the text after a user has inputted something. I can do it when it's a normal InputField but not with the TM Pro version. I've created a Serializefield of type TMP_InputField which I have hooked up in the inspector (also including using TMPro namespace).
Could somebody please outline the steps required to get the text into a variable because I am stumped! The script is currently sitting on a different GameObject. I have an array of type TMP_InputField called theFields and when I debug theFields[0].name that seems to work fine (using FindObjectsOfType<>) but when I try to just access a specificField.text it throws a null reference objection when trying to edit the field during the game. Any tutorials/support would be very welcome!
Did you try with UnityEvents fields on the Inspector of TMP_InputField?
I make a simple script and it combines with TMP_InputField
using UnityEngine;
public class InputfieldListener : MonoBehaviour
{
public void OnChangedInputField(string input)
{
Debug.Log("[OnChangedInputField] " + input);
}
public void OnEndedInputField(string input)
{
Debug.Log("[OnEndedInputField] " + input);
}
public void OnSelectedInputField(string input)
{
Debug.Log("[OnSelectedInputField] " + input);
}
public void OnDeslectedInputField(string input)
{
Debug.Log("[OnDeslectedInputField] " + input);
}
}
Then you can find the log of each event.
FYI, the creator has a youtube channel and there is a related video tutorial.
using TMPro;
public TMP_InputField TMP_IF;
TMP_IF.interactable = true;
TMP_IF.text = "whatever you want";
For those interested in year 2020 :)
Seems that property interactable is instantly disabled, solution was to enable it so it text could be updated...
I just code it up and then in the editor drag the TMP_InputField object into the corresponding slots in the script.
So, code-wise, I would have script like Milorad Zivanovic shows.
If you want multiple ones you might have:
public TMP_InputField [] myInputs;
In the editor (as described above in my first sentence) you just hit the plus button and drag them in. Or just highlight them all and drag in all at once. If you lock your object in the editor to do this (little lock icon up top right) don't forget to unlock it.
To access in your code you either loop or use an index. Like to get the first one you would do this:
{//... in some method
myInputs[0].text = "something";
}
PS: I did not have to explicitly set the interactable field.
PPS: The answer that HyoJin KIM gave is great and best if you like using Unity's Event. I just gave this answer so you'd have an additional way of doing it that might match your original attempt(s).
Be aware that if you do choose this latter approach it is very easy to make the mistake of choosing the static version of the same method (they are listed twice!) Many times I make this mistake. Choose the top one (non-static, aka Dynamic) for most cases!
NOTE: I'm casting a wider net than Unity Answers, my original question can be found here.
I've created a ProTools CueSheet importer. It uses OnPostprocessAllAssets() to detect a files in the project that have a .cuesheet extension. It then runs those cuesheet files through my parser. This generates a ScriptableObject which is then turned into an asset via Database.CreateAsset().
The problem is, this leaves me with two files, the original cuesheet and the newly generated asset. Is there any way I can generate the asset in such as way that the original cuesheet acts as the asset, the same way textures or FBX files do?
public class CueSheetPostProcessor : AssetPostprocessor {
static string extension = ".cuesheet";
static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths) {
foreach (string assetPath in importedAssets) {
if (assetPath.EndsWith(extension, StringComparison.OrdinalIgnoreCase)) {
string newPath = assetPath + ".asset";
Session session = CueImporter.Load(assetPath);
AssetDatabase.CreateAsset(session, newPath);
AssetDatabase.SaveAssets();
}
}
}
}
I would create a PropertyDrawer for the Serializable class CueSheet such that it accepts the .cueSheet TextAsset or path to the .cueSheet file and create an instance of the class CueSheet and assign it or modify it.
Rather than create a new asset, have you tried using AssetDatabase.AddObjectToAsset instead? An file in Assets can "hold" multiple assets and multiple asset types. When importing a .fbx, the output in the project inspector is several things: a GameObject tree (ie, a prefab), some models, maybe a rig, and so on. All these are "contained" in the processed .fbx