Basically I have three classes to try and collect the checkpoints and respawn at the last one reached. The code seems fine, however I'm getting a null reference error upon reaching the checkpoint during runtime. The problem seems to be inside Unity.
private CheckPoint cp;
I can't get anything to go into the inspector section for this instance. Granted, I do a call upon start
cp = GameObject.FindGameObjectWithTag("Checkpoint").GetComponent<CheckPoint>();
I've tired an empty object and I've tried placing one of my checkpoint objects but nothing seems to work. Any advice?
1. Check if you have multiple gameObjects tagged "CheckPoint".
cp = GameObject.FindGameObjectWithTag("Checkpoint").GetComponent<CheckPoint>();
is going to find the first gameObject with that tag and try to get your component, if there is no component, you will get null reference
2. Use this instead
FindObjectsOfType<Checkpoint>();
for more: https://docs.unity3d.com/ScriptReference/Object.FindObjectsOfType.html
3. Use a list/array/any other container in your "CheckpointManager" class and into Start() method of each Checkpoint do:
CheckpointManager.container.add(this);
this should be much easier to manage and you will not have to use tags.
Related
Maybe im missing something obvious but to keep it short. I have working code for a character. When you "dash" I want to leave behind an after-image type effect, by cloning the player, removing its unneeded components and then applying a shader. Issue is as soon as I instantiate the clone the original player stops functioning (cant move etc). It still has all its components and everything as normal, and the clone does get the correct components removed. But it still breaks. As soon as I remove that line, its back to normal. Any ideas?
This is the only relevant code in the script that instantiates the clone.
private void DodgeEffect()
{
GameObject _DodgeSFX = Instantiate(gameObject, transform.position, transform.rotation );
Destroy(_DodgeSFX.GetComponent<PlayerController>());
Destroy(_DodgeSFX.GetComponent<PlayerCombat>());
Destroy(_DodgeSFX.GetComponent<WarpController>());
Destroy(_DodgeSFX.GetComponent<Animator>());
}
its because you are making a copy of gameObject. while Instantiate() returns a GameObject, it also returns whatever you put into the first section of the method. instead, make a seperate gameObject than the player in the editor, and make _DodgeSFX public so you can put the copy into the slot. Then, just instantiate that seperate GameObject and you wont have to destroy the components through script(because you remove the components in the editor), saving time
Ok so from some testing I think its down to the Unity.InputSystem only allowing 1 instance of each Input to be enabled at once. When I instantiated a clone of the player, it still goes through the Enable/Awake functions before those components are destroyed, and since the Inputs on that clone were never disabled, that becomes the "main" one. If I set the main player's scripts with Inputs deactive and then active again, it all works as normal. Note that the script was still working on the main character just fine, it was only the inputs that was broken. Im still not sure why this is the case, if its a limitation of the input system, or intentional, cant seem to find documentation of this experience anywhere.
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)/¯
In the hierarchy, I have a parent Game Object (named "parent"), which has a child (named "child" and tagged "John"). Initially, The parent is active but the child is inactive.
The parent has a script component, in the Update() function of which I have:
GameObject go = GameObject.FindGameObjectWithTag("John");
go.SetActive(true);
It doesn't work and I get "NullReferenceException: Object reference not set to an instance of an object" in the console. Even if the child is initially activated and I want to deactivate it, it still doesn't work and I get the same error. Why? And is it a good idea to use FindGameObjectWithTag() in Update() in the first place?
In Unity, you can't get an inactive GameObject using any Find function unfortunately.
If you're not creating your GameObject go dynamically, use a public variable and assign it via inspector, it's way better performance wise (as Unity probably uses references), and it's easier (imagine you change a tag, you won't need to check in all your code references to that tag)
As pointed out by Jichael, you cannot use Find functions to get inactive gameobjects.
You can however use:
var yourComponent = GetComponentInChildren<YourComponentType>(true);
If your child object has any component attached to it, you could easilly get it like this. Note the true (boolean) parameter. This is used to indicate that you want to check for inactive gameobjects.
A more detailed example:
var spriteRenderer = GetComponentInChildren<SpriteRenderer>(true);
spriteRenderer.Sprite = yourSpriteVariable;
spriteRenderer.gameObject.SetActive(true);
This is also better performant than using Find functionality, since you only need to look through the child objects of the calling behaviour.
Hi i was wondering if there are other ways to set a GameObject active through code in c#
the only one i know is to do this:
public GameObject box;
box.SetActive(true);
which really great, you can just drop of the object on the inspector but i was wondering if there are other ways
like using a specific name of an object or turning GameObjects into active with a certain tag. I'm having a hard time trying to find an example whenever i google it or maybe i'm searching it wrong
any advice?
Did you have a look at the GameObject API or the Manual?
There are Find, FindWithTag, FindGameObjectsWithTag
or also methods like GetComponentInChildren, FindObjectOfType, FindObjectsOfType
(those you can use to find a certain type of component and thereby there according gameObject you can than set (in)active)
but since you requested activateing multiple objects by tag:
var targetObjects = GameObject.FindGameObjectsWithTag("YourTag");
foreach(var obj in targetObjects)
{
obj.SetActive(true);
}
note however that this is a lot more expensive than having the references from the inspector. So in general try to avoid using these FindXY methods if possible.
And yes how remy_rm pointed out correctly in the comments you definitely should not use them in any update loops, or other methods that get called regularly. You should always call them e.g. in Awake, Start etc and store the references for later
Update
If I understand your comment correctly you additionally have some children in those tagged objects that you also want to set active:
var targetObjects = GameObject.FindGameObjectsWithTag("YourTag");
foreach(var obj in targetObjects)
{
obj.SetActive(true);
// also activate all children
foreach(Transform child in obj.transform)
{
child.gameObject.SetActive(true);
}
}
i'm making my first enemy AI in unity. I'm trying to make a finished state machine with the animator controller to do it.
I just discovered the StateMachineBehaviour script which is called when the AI is in a state. It has multiple methods, including the OnStateEnter. It is called everytime the AI enter the state.
My problem is only about optimization, my AI need to get the GameObject "Player" in order to attack it. So i'm getting it in my OnStateEnter method for the moment, which i feel is bad, because i'm getting it every time the animation is called, i would like to get it only once, at the start.
I basicly need a start function but it's not working, i have made research and found nothing. I tried to watch video about people making a finished state machine but they are just getting the same GameObject multiple time ( example here : https://youtu.be/dYi-i83sq5g?t=409 ).
So, is there a way to have a start function or to get an element only once ?
I could make a bool that is called only the first time and that get the GameObject, but again that would be an "useless" if running in my function.
Any suggestions ? Thanks
No, unlike a MonoBehaviour a StateMachineBehaviour has no Start message only OnStateEnter, OnStateExit, OnStateIK, OnStateMove and OnStateUpdate.
There are also Awake and OnEnable but I'm pretty sure they are not used in the StateMachine and might not behave as expected.
You can however either use
OnStateMachineEnter
Called on the first Update frame when making a transition to a StateMachine. This is not called when making a transition into a StateMachine sub-state.
Or use a simple bool flag like
bool alreadyExecuted = false;
OnStateEnter()
{
if(alreadyExecuted) return;
// Do your stuff
alreadyExecuted = true;
}
(Just a guess)
In the Inspector you actually can enable and disable StateMachineBehaviours like components. So it might be able to do this also in script maybe the same way using
enabled = false;
but I didn't find anything about it in the API and since I'm currently on my Smartphone I can't test it.