I have the following class
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PixelSystem
{
public GameObject pixelPrefab;
public Texture2D[] style;
public List<Chunk> chunks;
public GameObject mGameObject;
public PixelSystem(GameObject _mGameObject)
{
mGameObject = _mGameObject;
chunks = new List<Chunk>();
}
}
Chunk and Pixel are structs but I don't think they are relevant.
I would like pixelPrefab and style to be serialized but cannot seem to be able to make that work. This script is not attatched to a GameObject.
I have looked into getting the assets at runtime with Resources or Addressables but I would like to be able to set these fields from the editor.
I have tried making the class inherit from MonoBehaviour and having [SerializeField] public GameObject pixelPrefab; and [SerializeField] public Texture2D[] style;, but the result of this is that pixelPrefab is settable from the editor but instead of showing style it shows mGameObject, for some reason... ¯\_(ツ)_/¯
Edit: Turns out that the [SerializeFields] do nothing here, the result is the same without them.
I've also tried puting [System.Serializable] before the class, but as far as I can tell this does nothing at all.
Someone plz help.
Edit:
Due to some misunerstandings I would like to clarify a few things:
I have the prefab asset already, it is in my assets folder not in my scene, creating the assets is not the problem.
pixelPrefab would work fine as a static property, however, style would not.
Style only needs serializing for a default value and so is not a priority.
This code is very incomplete, the constructor is incomplete, I want an answer to this qusetion before I spend time writing code that may be unusable.
I want to select the assets in the editior
I do not want to have a function that must be called before the classes are used, so that the assets are loaded
I do not want to load the assets each time they are referenced, so no get {load();}
This is what I want to see in the editor when I select my script:
And this is the closest thing to what I want so far:
Which I get by setting the class to inherit from MonoBehaviour, I'd rather not inherit from anything, and idk if you are meant to have MonoBehaviour classes that aren't attatched to gameObjects, but if this is necessary then so be it.
complete .cs file here
A few things here. I'm going to assume this point is the most important:
I want to select the assets in the editior
So, in order to be able to do this, every field you want to see has to be able to be serialized by Unity and also Unity needs to be able to draw the GUI for that thing. You said,
I would like pixelPrefab and style to be serialized but cannot seem to be able to make that work.
and again here I'm taking "serialized" to really mean that you just want those fields exposed in the Editor so you can stick things into them. So when you give me the following snippet I immediately see several issues:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PixelSystem
{
public GameObject pixelPrefab;
public Texture2D[] style;
public List<Chunk> chunks;
public GameObject mGameObject;
public PixelSystem(GameObject _mGameObject)
{
mGameObject = _mGameObject;
chunks = new List<Chunk>();
}
}
The first is that PixelSystem itself isn't serialized. You either need to tag the class with [System.Serializable] to use Unity's serializer or you need to inherit from something that Unity already knows should be serialized, like Component or MonoBehaviour (MonoBehaviour inherits Component). The issue with Component and subclasses is that they need to exist on a GameObject, so you can't new a Component, you have to .AddComponent<YourComponent>().
Now as you've discovered, when you have your script inherit MonoBehaviour, you see
that pixelPrefab is settable from the editor but instead of showing style it shows mGameObject, for some reason... ¯\_(ツ)_/¯
And the reason it's showing mGameObject can be seen in your class' member variables:
public GameObject pixelPrefab;
public Texture2D[] style;
public List<Chunk> chunks;
public GameObject mGameObject;
You can see that pixelPrefab is a public GameObject. Great! (1) your class is inheriting MonoBehaviour, so Unity knows to serialize it, (2) pixelPrefab is public, so the Editor knows to show it, and GameObject is itself a serializable object that Unity knows how to draw, so the end result is that Unity adds pixelPrefab to the Editor GUI for your class.
Then you get to style, which is public, so the Editor knows it should show it, but it's an array and Unity doesn't know how to draw the Editor GUI for an array. It's an array of Texture2D, which it does know how to draw, but it doesn't know how to handle the array aspect, so it doesn't add style to your GUI.
Then you get to chunks, which is public, so the Editor knows it should show it, and it's a List, which Unity does know how to handle, but it's a List of Chunk, which I'm betting is not inheriting MonoBehaviour and is also not tagged with [System.Serializable], so Unity doesn't know that it's supposed to be serializing Chunk. This means that it does know it's supposed to be drawing a list, but it think it's not supposed to be drawing any contents for the list, so it skips the list completely.
Finally you get to public GameObject mGameObject, which gets drawn for all the same reasons that pixelPrefab gets drawn, and finally you get what you see in the Editor in your last screenshot: Only pixelPrefab and mGameObject are drawn in your class GUI:
So, what to do if you want to view your class in an Editor pane and you also want to see pixelPrefab and style?
Have something that can be serialized, like a MonoBehavior, hold a reference to PixelSystem OR have PixelSystem inherit MonoBehavior.
If PixelSystem is not a MonoBehavior then it needs to have [System.Serializable] on the line above public class PixelSystem.
Do what you've already done and have public GameObject pixelPrefab.
Convert style from an array to a list so Unity knows how to draw it.
You should wind up with the following:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class PixelSystem
{
public GameObject pixelPrefab;
public List<Texture2D> style = new List<Texture2D>();
public List<Chunk> chunks;
public GameObject mGameObject;
public PixelSystem(GameObject _mGameObject)
{
mGameObject = _mGameObject;
chunks = new List<Chunk>();
}
}
You can also have Chunk be serialized and shown in your Editor pane if you tag that class with [System.Serializable], and you only need the [SerializeField] tag for fields that aren't already public. You can still add that tag to public fields just like you can add [System.Serializable] to a MonoBehaviour but it's redundant. Not required.
Related
So, I have an ItemObject which is a ScriptedObject
In an ItemObject I want to create an array/list that stores the scripts in it
The scripts that will be stored in this array/list will be used to extend the functionality of the GameObject (Imagine as unique skills for player, not attributes)
To do this, I'm going to add the script as a component with Player.AddComponent(SCRIPT.GetType())
So, it is assumed that after I create an item asset in the project directory, I can select the number of script skills and add them through the inspector
Also, as a sad alternative, I was considering using GameObject, which would store scripts as components. And that, to me, is terribly unhandy, given that there could be hundreds of the scripts. And unfortunately, I'm still not experienced enough, so it's the best I've come up with so far.
I solved my problem in the following way:
By adding the script as an Object and displaying its type in the console, I found out that it is a MonoScript
So just by adding using UnityEditor I was able to create a list consisting of MonoScript
using UnityEditor;
class Script : MonoBehaviour
{
List<MonoScript> scripts
}
And then, using [GameObject].AddComponent([MonoScript].GetClass()) I was able to add this script as a component to the GameObject
class AddScriptAsComponent : MonoBehaviour
{
GameObject object;
MonoScript script;
void Add()
{
object.AddComponent(script.GetClass())
}
}
You could do something like
using UnityEngine;
public class ItemObject : ScriptableObject{
[SerializeField] List<MonoBehaviour> scripts;
}
Although, if I'm understanding the objective correctly, maybe it would be a good idea to have a look at the concept of prefabs instead.
When I put this script into the object, a cube, it does not register the platform it hits beneath when I make the gameObject the platform. I'm trying to get the two objects to detect collision between each other but it does not seem to work. Neither objects are trigger checked in the Box Colliders. The cube has a rigid body with gravity checked but the platform does not. This is a 3D game.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Collision : MonoBehaviour
{
public Transform gameObject;
void onCollisionEnter(Collision col)
{
if (col.gameObject);
{
Debug.Log("Yes");
}
}
}
As Sven Viking already said, you have to change the syntax from onCollisionEnter to OnCollision enter. Also, let's take a look at your logic:
You want to check that, if your cube object collides with another object, and if that object is the same as the one you're referencing, you want to see a log of that in your console. Currently, however, you're asking for something else.
First of all, your platform is not stored as a gameObject, it's stored as a Transform. Those two are different things, the Transform stores the position/rotation/scale of an object, while 'GameObject' is the entire object, includng its Transform. Also, you named your variable gameObject, which you should never do - Never name variables with the same name as existing elements.
'col' represents the collision. col.gameObject is the gameObject of that collision. There's no logic demanded there. You're just making a reference. What you want, instead, is compare the gameObject of the collision with your referenced gameObject(the platform) and, if both of them are the same, then you can proceed. Therefore, what you want is:
public class CollisionScript : MonoBehaviour
{
public GameObject platform;
void OnCollisionEnter(Collision col)
{
if (col.gameObject == platform);
{
Debug.Log("Yes");
}
}
}
Let me know if this solves your problem.
EDIT: I see now you also named your class 'Collision', which I'm pretty sure would break things, as Collision is already a class within Unity(you can check that looking at "Collision col", that indicates there is a class named Collision). You should change both the class name on the top of the script and the file name to reflect that change.
I have a script with a public UnityEvent and I am trying to drag a scene object to the object slot so I can access its methods but its not accepting the object. I'm not sure what i'm doing wrong.
The scene object is a prefab instance and I did try unpacking the prefab but it didnt make a difference.
In a comment you mentioned the script you are talking about is a StateMachineBehaviour.
StateMachineBehaviour does not inherit from MonoBehaviour but rather from ScriptableObject
ScriptableObject instances "live" in the Assets not a certain Scene
You (usually) can not have any Scene references in any assets like Prefabs or ScriptableObjects.
There are some workarounds however that still allow you to do that. You can e.g. create ScriptableObject containers for every value you want to pass. Something like e.g.
[CreateAssetMenu]
public class GameObjectReference : ScriptableObject
{
public GameObject gameObject;
public void SetActive(bool value)
{
if(gameObject) gameObject.SetActive(value);
}
}
such an instance of GameObjectReference now is a ScriptableObject and thus also "lives" in the Assets => you can reference it in any other asset as Prefabs and other ScriptableObjects.
So all you need to do is make sure that you set this value from within your scene e.g. using
[ExecuteInEditMode]
public class GameObjectReferenceSetter : MonoBehaviour
{
public GameObjectReference gameObjectReferenceAsset;
private void Awake()
{
gameObjectReferenceAsset.gameObject = gameObject;
}
}
You can create such a reference-asset and setter pair for each type you need and transpass the required public methods so you can call them from the UnityEvent.
Having the [ExecuteInEditMode] this should also be set already in EditMode. However since "officially" it is still not possible to have a scene reference on a ScriptableObject field the value usually says Type missmatch but references the correct object as you should see when you click on the field.
Another alternative is using some kind of dependency-injection (for Unity an often mentioned and free solution is e.g. Zenject). It is a bit complex to set it up the first time but once you got it working it is more flexible and better scaleable since you wouldn't need to implement a wrapper for each type you want to pass in to a StateMachineBehaviour.
More information and how-tos about Zenject can be found on their github page
I have a model with an animator; and a controller script to make it move, then I created a simple class called "TheEntity", which hold a name, and an int for the energy. When the time goes by, the energy goes down, so the mesh walk around or perform animations at random.
public class TheEntity()
{
public string name;
public int energy;
public TheEntity()
{
// make a random name
name = "joe"+ rnd.next(1,1000).toString();
energy = rnd.next(20, 100);
}
}
When the energy value goes to 0, the mesh "goes to sleep", and regenerate again in a certain amount of time.
If I have a list of TheEntity instances, as it would be if I have a list of NPC, what would be the correct way to assign a mesh to each entity class in the list?
Should I have a script on the mesh, that has a reference to a TheEntity class. and assign it at runtime when I load the mesh prefab?
Or should I put the whole "TheEntity" class script on the mesh, and save it as prefab, so every time that I load the prefab, I will have a mesh with a related TheEntity instance directly?
"Things" in the Unity scene are GameObject , that's all there is to it.
Your class must be a MonoBehaviour to be on a game object.
In Unity, everything is a MonoBehaviour (a Component). There is, quite literally, nothing else whatsoever in Unity.
(Of course, you may have some "raw" non-Unity classes for things like say math calculations, but that's irrelevant.)
It's just that simple.
public Class Entity:Monobehaviour
{
}
attach that to an empty game object. Add the models (meshes) .. or whatever you want. Add sound effects, add anything.
Regarding "changing the mesh", no problem.
Do that in a routine in Entity, if you like.
public Class Entity:Monobehaviour
{
public void ChooseRandomMesh()
{
}
public void ChooseRandomColorPattern()
{
}
public void RunForTheHills()
{
}
public void AttackHero()
{
}
}
If you prefer, write a Component which does nothing other than randomly change the mesh.
public Class Entity:Monobehaviour
{
public void RandomizeEntity()
{
}
public void ChooseRandomColorPattern()
{
}
}
.. and attach that script to the game object, also.
In Unity, everything is a MonoBehaviour (a Component), it's that simple.
Regarding making it a prefab, if you want to, sure do that. Read any of thousands of tutorials on prefabs.
There's a critical comment you made in your comments below:
"Also the entity class is not MonoBehaviour..."
Here's an incredibly critical point in understanding Unity:
1) You're quite right that your "model" or "AI" or "database connection" sort of has "nothing to do" with unity game objects. (They of course don't have a "position" or "mass!" or anything, right?!)
HOWEVER HOWEVER HOWEVER HOWEVER HOWEVER HOWEVER HOWEVER HOWEVER HOWEVER
2) In Unity unless a class is a MonoBehaviour: you can't do anything with it/ You can't even access the run loop, it's a total nonstarter.
THUS THUS THUS THUS THUS THUS THUS THUS THUS THUS THUS THUS THUS THUS
3) In Unity all the stuff like that, IS IN FACT a MonoBehaviour AND YOU SIMPLY sit it on an empty game object. (Usually the name in the Heirarchy starts with underscore, say, so you know it's "not really" a conventional game object.)
The simple bottom line is in your preload scene (you must have one in 100% of projects) you have all your "AI" and "model" and "database" stuff, just sitting on one or more "pretend" markers (marker == otherwise empty game object).
Bottom line, when you say below "your model is not a MonoBehaviour" that is wrong. It will have to be a MonoBehaviour (if you think about it, it's absolutely inevitable you'll need to access the runloop, if nothing else) ... just make it a MonoBehaviour and put it on a marker, almost certainly in your preload.
I hope it makes sense. Essay on the topic.
I'm designing a 3D Tetris game. I'm new to unity and just started to learn some basics in this site
My plan is not to create a regular tetris board, but to create a 3D surface, with width,height and depth so the user will need to build a surface in order to destroy the objects.
So in my design I know that I need an object generator and to create an object (Tetris cube) in they that I'm calling the object generator in the update method with some timer.
Also the idea is to make a 3d matrix that represent the game board so I could check in the game logic if there is a "surface" in that matrix.
This is a part of the game logic script.. and my problem is that i don't know where to put this script.. I mean in the game logic I need to create a random cube, and to check if there is a surface that can be destroyed.. but where should I put the game logic script?
I always used IDE's like visual studio or eclipse so there you can have a main class with the main method that start your program.. and now in unity i'm confused..
Edit:
Thanks for your replying.. I forgot to mention that I have something like 3 scenes (levels) in the game.. so for each level (scene) should I create an empty game object?
make an empty gameobject and attach your object that you want to spawn(as child) to it and attach your spawn code to that empty object(parent)
Create an empty gameobject like mentioned and put a script on it that saves it from being destroyed on scene-change (some sort of singleton).
Some basic way to do it:
using UnityEngine;
using System.Collections;
public class GameController : MonoBehaviour
{
private static GameController instance
public static GameController Instance
{
get { return instance; }
}
private void Awake()
{
instance = this;
DontDestroyOnLoad(instance);
}
}
The DontDestroyOnLoad will hold the whole gameobject with everything attached to stay loaded on scene-change.