How to assign variables in the inspector for a script on an instantiated object? - c#

Good evening.
So I want to assign a text box to an instantiated object but how do I go about doing this via code and not manually. As hundreds of these prefabs could be instantiated I need to be able to assign the text box in the inspector via code at runtime (As in when they are created).
Just to note: all these fields are assigned on the object that this prefab is a clone of, just for some reason the scripts copy over but the assigned values don't?
Let me know if you need to see any code but I think the question explains enough.
Thank you in advance!

https://gamedev.stackexchange.com/questions/135209/how-to-store-references-to-scene-objects-in-prefabs - This post answers my question. (It is a set of ways to assgn variabkes to prefabs in the inspector).
I thought I might as well repost it here as the answer is on a different forum.
GameObject bullet = Instantiate(bulletPrefab, transform.position, transform.rotation);
bullet.GetComponent<BulletScript>().shooter = gameObject;
Seems to be the best way to do it, using GetComponent to decidd what script you want to assign something to and then assigning that part using .variable = whatever you want it to be.

Related

Spawning gameobjects relative to the position, width and length of another gameobject?

I'm currently developing a game in Unity using C# and I've run into a small problem.
I need to spawn a certain gameobjects relative to the Spawnposition and length of another game object. Now I figured that bounds.size would be the best function to use in this instance. As shown bellow I declare first the variable that uses this in my start method:
public void Start()
{
GameObject PointBar = (GameObject) Resources.Load("PointBar Horizontal");
PointBarVectorLength = PointBar.GetComponent<BoxCollider2D>().bounds.size.x;
PointBarVectorConv = Camera.main.WorldToViewportPoint(new Vector2(PointBarVectorLength, 0f));
}
However, the gameobjects in question are inactive at start's call and thus I presume don't return any value for bounds.size when called.
Does anyone know how I can access the bounds.size or equivalent of an inactive gameobject or is there something else I'm missing here?
As noted in the documentation for the Collider.bounds property, bounds "will be an empty bounding box if the collider is disabled or the game object is inactive". So your assumption was pretty much right. Since the object doesn't exist in worldspace that makes sense.
I'm not sure about the most elegant solution for your use case but two options spring to mind.
Calculate the object's spawn dimensions by accessing its transform.localScale and factoring in the scale of prospective parent objects. That could get messy but you could probably also write a helper method to make it more manageable.
Instantiate the object somewhere off screen after you load it, access its Collider.bounds property to get the information you need then move it where ever you want it or store the information for later.
There may be better solutions but that's what leaps to mind for me.
I solved the issue by using GetComponent().bounds.size.x;
instead of BoxCollider. This component can get accessed when the game object is not active.

Refactor/Rename Unity inspector variable names?

Refactoring or renaming member variables is commonplace in software development, but this can be difficult while working in Unity. If a variable is visible to the inspector the old variable is destroyed, along with whatever value set, and a new variable is created. Is there a way to tell Unity that this new variable is the same as the old one preserving the values set in the inspector for all instances of the component?
Yes, there's a way -- use the FormerlySerializedAs attribute:
[FormerlySerializedAs("theOldName")]
[SerializeField] float theNewName = 0f;
(An alternative, brute force approach is to do a text search & replace in the scene file to rename something, by the way.)

Neither null nor type check detecting destroyed object/component?

I have an issue for which I've found a workaround, but can't understand why Unity isn't working the way I expect, or what I'm doing wrong. Basically, I am referencing a renderer component of a destroyed object in a script (long after it's been destroyed), and neither null checks nor type checks let me know it's destroyed.
I have a script that's modifying the shaders on some objects temporarily so I can apply effects on to them; when the effects are done it puts the materials/shaders back the way they were.
It happened that I was swapping out a character's weapon in the same frame I began one of these effects, so the script wound up with a reference to the renderer of a destroyed object (the old weapon). Many frames later when the effect was to finish, it naturally err'd out.
I tried a type check first to see if the reference was still to a renderer -- no luck. Unity's doc says a null check should work, but it still doesn't.
if (pair.Key != null && pair.Key is Renderer renderer) { renderer.materials = pair.Value; }
I get:
MissingReferenceException: The object of type 'SkinnedMeshRenderer' has been destroyed but you are still trying to access it.
Your script should either check if it is null or you should not destroy the object.
activeInHierarchy likewise does not work.
Adding a DestroyImmediate to the code where I destroy the object works fine; the object isn't there by the time the effect starts, so the reference is never made. However, that only solves this one problem, and not other such cases.
Can anyone tell me how to check properly for references to destroyed objects or components, or if I'm doing something wrong in my checking? Should I be referencing the gameObject instead of the renderer component or something like that?
EDIT:
Since a commenter asked for it, here's a gist of the full code for the effect. The destruction is happening outside this, as it's totally unrelated.
https://gist.github.com/jackphelps/f507d949a84c53457f570c5009bcb6d4
SOLVED -- SORT OF?
I changed the dictionary to store the renderer's game object instead of the renderer, and as expected a simple null check worked for detecting a destroyed object. I'd love to know why it doesn't work on the renderer, and if there's a proper way to check!
The best way I could find to solve this was to store a reference to the renderer's gameObject rather than to the renderer component itself. In this case, a simple null check at the end of the script works fine, as expected.
I'm not accepting this answer because it still doesn't tell me how to check for a component's presence when the game object was removed ¯(°_o)/¯

Hierarchy Climbing and Descending Unity

I have the following hierarchy on my Player prefab for what will be a very simple multiplayer shooter.
It works this way, the Controller object has the scripts that deal with player input, the PlayerShip object has all of the turning, moving, shooting scripts etc and the Camera is just as it sounds, a camera with a few scripts on it for moving it about.
When a new Player is instantiated the Control script needs to locate its relevant PlayerShip, simple enough.
This can be achieved using the following code:
_playerShip = gameObject.transform.parent.gameObject.transform.FindChild("PlayerShip").GetComponent<PlayerShip>();
Which works fine, the only thing is, to me that looks very clunky, inelegant and brittle. Consequently, I'm wondering if there's a better, more efficient, less ugly way of achieving the same thing?
First of all,
_playerShip = gameObject.transform.parent.gameObject.transform.FindChild("playerShip").GetComponent<PlayerShip>();
is redundant. That can be reduced to
_playerShip = gameObject.transform.parent.FindChild("playerShip").GetComponent<PlayerShip>();
or even use '/' just like you do with folder names.
_playerShip = GameObject.Find("Player/playerShip").GetComponent<PlayerShip>();
Now, instead of instantiating the Object and searching for it later on, you can actually instantiate it and retrieve the reference at the-same time.
GameObject obj = Instantiate(prefab,Vector3.zero,Quaternion.identity) as GameObject;
_playerShip = obj.GetComponent<PlayerShip>();
If it is a network game that you instantiate with Network.Instantiate:
GameObject obj = Network.Instantiate(prefab,Vector3.zero,Quaternion.identity,0) as GameObject;
_playerShip = obj.GetComponent<PlayerShip>();
Now, send the PlayerShip reference to the Control script.
If this isn't being called every frame consider this:
_playerShip = GameObject.Find("PlayerShip").GetComponent>PlayerShip>();
Read more about the above here: https://docs.unity3d.com/ScriptReference/GameObject.Find.html
If it is being called every frame look in to this:
https://docs.unity3d.com/ScriptReference/GameObject.FindWithTag.html
Either one should be easier to understand.
EDIT: I may have misunderstood. Would rearranging the hierarchy so that controller is a parent of playerShip? Then you should be able to just look at the child, rather than going through a parent to a sibling.

Turn on Gravity on current object

I am working on a simple game - when I click on the screen a cube should start using gravity (I have unchecked the "Use Gravity" setting for that cube). However, I do not know how to reference it. I found that I could write .useGravity = true; but I have no idea what to put before the dot.
Gravity comes from the RigidBody. So use something like this in the code.
GetComponent<RigidBody>.useGravity=true;
This of course assumes your script is acting on the same object. If you need to get another object, well, that's a different question.
You can give him a special name like "CubePlayer" and after in your code reference him as:
GameObject.Find("CubePlayer").use....
Other way is to assign a var to it from Inspector, in JavaScript it is like this:
public var MyCube : GameObject;
...
MyCube.use.....
It is possible in C to do this too.

Categories