About a month into making my first game, I have realized that I am very confused when it comes to attaching gameobjects as classes to another game object's script. That's a mouthful so here's my issue.
My Game.cs attached to Game (gameobject) has
public Player player;
My Player.cs is attached to a Player (gameobject) prefab
Why can I drag a Player gameobject, that has a player script, into the Game gameobject's "player" field? How does that make sense? It should be
public GameObject player;
Then I would drag my prefab gameobject "Player".
The reason why this confuses me is, If i Instantiate "player", am I instantiating a gameobject? It seems not, because I cannot do this:
GameObject newPlayer = Instantiate(player, new Vector3(1,1,1), Quaternion.identity) as GameObject;
newPlayer.transform.SetParent(GameObject.Find("Level"));
If I do I will get the error the newPlayer is null.
A script is actually a Component object like any other object (most of the time).
It is technically not too easy to drag a Component object from an inspector onto another slot in another inspector. Probably thats why they made this "shorthand", when you can drag the actual GameObject instead from the hierarchy.
If the dragged GameObject has a matching component to a slot, it counts as you have dragged the Component itself.
You cannot instantiate a script Component using Object.Instantiate, you'll always instantiate a GameObject this way, see the docs. If you need the script, simply get the component from the brand new instance.
It can be confusing indeed, I personally prefer naming convention something like:
public GameObject playerObject;
public Player player;
Unity. by default, will cast any gameobject into the possible component, for example, if you have a Transform in your script and pass a gameobject (as a lot of tutorials do), it will automatically cast to the transform of given gameobject.
The main problem with that is simply that if you try to attach an object without Player script, it will probably crash in one way or another if you don't check the value.
Anyway, while you are working with your own scene and are sure the player gameobject has the necessary script, it won't be a problem in any way
Oh, about the last part, attaching components is common for already instantiated objects, to instantiate from a component you should get the parent game object of that script, and it would not make sense as you could easily attach the prefab directly
I don't remember now exactly how, sorry
Related
Hope you're well. I've been trying to make it so when the bullet collides with the enemy, the enemy dies using the Destory(gameObject); function.
Yet, when it destroys the gameObject, this prevents the enemies from spawning as the spawner cannot find the gameObject.
So, I'd need to make it so Destory(gameObject); only destroys a single enemy bullet hits, not the full gameObject.
your mistake is you are destroying the referenced object, and your other script wants to call it.
do not use a scene object as reference object. make it a prefab, and than drag that prefab on object with script. it will solve your problem.
I'm learning unity3d and c# right now with c++ and c knowledge. However, I'm confused with this line of code.
private Gameobject cubePrelab;
This is a simple line of code which "defines the object that we want to spawn" according to the lecturer.
Then he immediately do things like:
Instantiate(cubePreLab, ...,...)
which clones the object according to the documentation online.
I'm confused about the first line of code which it seems like we are just defining an object without actually initializing it. However, the result is with these two line of code, we can actually create a box on the screen but I'm confused why it is a box instead of maybe a trangle.
I suggest you read about Unity Prefabs
Since you're new to Unity, I assume you've started off by putting a few objects -- such as a cube -- into your scene right? The Unity Editor makes it easy to put objects into your scene while you're designing your game, but what if you wanted to dynamically add objects into your scene while you're playing your game?
For example, imagine that you created a scene that has a cannon in it, and every time the player hits the Space key, you want to fire a cannonball. When you create your Scene in the Unity editor, you put your cannon in your scene, but how do you add cannonballs while you're playing the game?
You could have a bunch of code that creates a cannonball from scratch every time you fire one, but that's a very time consuming and error-prone way of doing it. This is where prefabs come in. A prefab is like a blueprint for an object that you're going to add to your scene later. So a cannonball prefab would be an object that you design in the Unity Editor just like any other Unity object that you're adding to your scene. You could assign its size, its material, its color, its attack power, and so on through the Unity Editor (no code needed).
First you would create a prefab in the Unity Editor for your cannonball.
After you create a cannonball prefab, you would add a property on your Cannon class such as public GameObject cannonballPrefab, and you'd drag your cannonball prefab from the Unity editor into the "Cannonball Prefab" property of the Cannonball component on your cannon object in the Unity Inspector. So if you only look at the C# code, it looks like the cannonballPrefab field is never getting initialized. However, you are initializing it by dragging a prefab into it in the Unity Editor. To reference your initial question, this is also how Unity knows to create a box and not a triangle in your example. Unity will create an instance of whatever your prefab is.
Then within your Cannon code, you can instantiate an instance of your cannonballPrefab while you're playing the game each time you want to add a cannonball into your scene.
Now when you call Instantiate(cannonballPrefab... Unity adds an instance of your cannonball into your scene. Then you'd probably do some additional initialization by assigning it an initial position, an initial speed, an initial direction, and so on.
Also, like Pac0 said, the tutorial probably has public GameObject cubePrefab (not private) so that you can drag a reference into it from the Unity Editor. Alternatively you could keep it private and add the [SerializeField] attribute to it like below. Unity won't let you assign a private field from the editor unless it has the [SerializeField] attribute on it.
[SerializeField]
private GameObject cubePrefab;
Example
In Unity5, assuming that a GameObject with name "SomeObject" was stored as a prefab at Assets/Resources/SomeObject.prefab, I know that I can create an instance of the prefab as follows:
GameObject prefab = Resources.Load<GameObject>("SomeObject");
GameObject instance = GameObject.Instantiate(prefab);
Once executed, the instance GameObject will be a copy of the original "SomeObject" prefab, and will have been placed in the current active scene with the name "SomeObject(Clone)".
As far as I understand, the GameObject prefab represents the actual prefab asset, and any changes made to it (setting name, adding components, etc) are written to the original prefab asset, and these changes persist even after exiting editor play mode.
Questions
Since all GameObjects are normally stored in a scene, and the scene property on GameObject prefab in the above example seems to be Unloaded/Invalid/Unnamed, where exactly should I consider this special GameObject to be? I seem to be able to do everything with it that I can do with normal GameObjects, short of being visible in the hierarchy/scene view.
Is it effectively in some kind of limbo state, or a special PseudoScene? It seems to persist through LoadSceneMode.Single scene changes, but is not like the special DontDestroyOnLoad scene that Objects are moved to when passed into GameObject.DontDestroyOnLoad(...).
Are there any other noteworthy differences between prefab and instance in the above example, other than lifetime changes, the invalid scene and being different objects from one another (Having different GetInstanceID(), etc)?
Since calling GameObject.Instantiate(...) on prefabyields a GameObject that is in a valid scene, is there any way to manually create GameObjects that are in a similar 'no scene' state? I am aware that Unity intends for all GameObjects to be in scenes and so this is purely an academic question.
I have tried looking through the documentation of the functions involved, but none go into the technical details of what specifically is happening when you call Resources.Load on a prefab resource.
1.Where exactly should I consider this special GameObject to be?
It's in a separate file and not referenced in the scene. Once Resources.Load<GameObject>("SomeObject"); is called, it is loaded into the memory waiting to be used when GameObject.Instantiate is called.
If it is declared as public GameObject prefab; and assigned from the Editor instead of GameObject prefab Resources.Load<GameObject>("SomeObject");, it will be loaded into the memory automatically when the scene loads.
2.Are there any other noteworthy differences between prefab and object?
Yes.
Prefabs cannot be destroyed with the Destroy or DestroyObject function. It has to be destroyed with the DestroyImmediate function by passing true to its second arguement: DestroyImmediate(prefab, true);
3.Is there any way to manually create GameObjects that are in a similar 'no scene' state?
No, there is no way to manually create GameObjects that are in a similar 'no scene' state.
Although you can fake it.
The closest thing to that is to make the GameObject invisible in the Editor's Hierarchy and Inspector tabs by modifying the GameObjects's hideFlags variable then deactivate that GameObject.
GameObject obj = new GameObject("SomeObject");
obj.hideFlags = HideFlags.HideInHierarchy | HideFlags.HideInInspector;
After that, deactivate the GameObject:
obj.SetActive(false);
Now, the GameObject is invisible in the Editor and it is also invisible in the Scene and Game View.
There is really no big difference between prefabs and a typical GameObject. Prefab is just a container that holds the GameObject so that it can be re-used and shared between scenes. Modifying one prefab will update any instance of it.
Imagine when you have hundreds of GameObjects of the-same type in the scene and need to modify all of them. With prefab, you only need to modify one of them or just the prefab then click Apply to update other instances. This is the only thing you should think of prefabs.
Im trying to make it so that when i trigger a trigger in Unity, it doesnt remove the trigger, but it does remove what the trigger is attached to. but i cant seem to figure out how to do it.
void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("pickup"))
{
audio.Play(); //Play it
other.gameObject.SetActive(false);
count = count + 1;
SetCountText();
}
}
This is an example of what im trying to do, but imagine it trying to set something else to inactive.
When you deactivate the game object, the attached collider will be deactivated too. If you want to deactivate a game object and let the collider exist you need to distinct between those two, i.e. have two game objects: one just for the collider and one for the actual object. now you can remove the actual object while the collider can continue to function.
The implementation depends on how you are handling the trigger.
case 1:
OnTriggerEnter is written in a script attached to the game object which static collider (ground) is attached to.
static collider is a collider without a rigidbody.
add a child to this game object and put the visuals in it (i.e. renderer or audio source).
add public GameObject Child; to the script.
set the reference of the child via unity inspector window.
deactivate the child instead of collider's gameobject in OnTriggerEnter method: Child.SetActive(false);
case 2:
OnTriggerEnter is written in a script attached to another game object which also has a dynamic collider (ball) and a rigidbody.
dynamic collider is a collider with a rigidbody.
add a child to the game object which the static collider is attached to
add a script to the game object (MyScript)
add public GameObject Child; to the script.
set the reference of the child via unity inspector window.
deactivate the child instead of collider's gameobject in OnTriggerEnter method: (other as MyScript).Child.SetActive(false);
When you deactivate an object with gameObject.SetActive(false); you automatically deactivate every component on you object (Renderer, Triggers, Scripts, ...)
There is two options to achieve what you want to do:
Use another object as a trigger (a Plane or a Cube and deactivate your object from this new object)
Or as suggested by #madjlzz you can deactivate your Renderer and RigidBody
Using Unity 5.0.2f1 for Mac.
Created a UI Text object (called LifeCountUI) in the scene. Then, on my Player's script (attached to my Player GameObject), I have the following field serialized:
[SerializeField]
public Text LifeCountText;
This Player GameObject is also a prefab.
My intention was to drag the LifeCountUI in the inspector to the serialized field on the Player GameObject. However, Unity does not allow me to do this when I select the Player prefab.
It only works, if I drag an instance of the Player prefab on to the scene, and then drag the LifeCountUI to the field (but obviously, that is not the prefab).
Am I doing something wrong here? I essentially want to have the ability to control the text field from the prefab instance.
Have a look at what gurus say about it in famouse 50 Tips for Working with Unity (Best Practices) article:
Link prefabs to prefabs; do not link instances to instances. Links to prefabs are maintained when dropping a prefab into a scene; links to instances are not. Linking to prefabs whenever possible reduces scene setup, and reduce the need to change scenes.
This is one of reason you are unable to maintain a reference.