I am following an Unity tutorial. I face a problem when trying to detect collision in the game. This is the error:
NullReferenceException: Object reference not set to an instance of an object
This is the script:
using UnityEngine;
public class Collide : MonoBehaviour
{
public Movement movement; // A reference to our PlayerMovement script
// This function runs when we hit another object.
// We get information about the collision and call it "collisionInfo".
void OnCollisionEnter(Collision collisionInfo)
{
// We check if the object we collided with has a tag called "Obstacle".
if (collisionInfo.collider.tag == "Obstacle")
{
movement.enabled = false; // Disable the players movement.
Debug.Log("Coollision occured");
}
}
}
As i saw in the second image you have not added the movement reference to the movement field. At the same in the script also you are not assigning the reference. Try to assign at editor or you can create object.
The reason is you have not set the movement field in your Collide component.
You can add it from the Unity Editor or add the following line in your Start function of Collide :
void Start()
{
movement = GetComponent<Movement>();
}
Related
Here is the code in which I was talking about. I can't figure out why my collider isn't working:
using System.Collections.Generic;
using UnityEngine;
public class SphereCollider : MonoBehaviour
{
GameObject obj;
void Awake ()
{
obj = GameObject.FindGameObjectWithTag("Player");
}
// Update is called once per frame
void Update()
{
void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.name == "Player")
{
obj.GetComponent<Health>().health -= 25;
}
}
}
}
Rather than using the code you have, make sure to change some code. This is what you should change: get rid of the obj variable and the awake function. Then instead of finding the object with that name, use tag. Also get rid of Update(){} and take the OnCollisionEnter(){} out of it.
A few more changes are shown in code:
void OnCollisionEnter(Collision collision){
var obj = collision.GameObject;
if (obj.Tag == “Player”){
obj.GetComponent<Health>().health -= 25;
}
}
This will work as long as: the script is called Health, the variable inside Health is called health, and it is set to a float, and the player’s tag is set to Player.
Not sure if the code pasted in the question is just copied over wrong, but OnCollisionEnter() is its own unique method and should not be nested in Update().
If the player will be colliding with this Sphere object often, it is good to cache a component rather than using GetComponent frequently. However I assume in your case this Sphere will be one of many obstacles, so calling the GetComponent in the collision is fine. The issue with your current code is the gameObject you are colliding with might not have the name exactly spelled as Player, which would make your collision check fail. Caching the object that has the tag of Player is a bit redundant when you can just check it inside of the collision check.
I will use your entire snippet of code so there is no confusion
using System.Collections.Generic;
using UnityEngine;
public class SphereCollider : MonoBehaviour
{
void OnCollisionEnter(Collision col)
{
// compare if the collider's gameObjects tag is equal to our target tag (Player)
if (col.gameObject.tag == "Player")
{
// get the component of Health on our gameObject that we collided with that has the tag of Player
obj.GetComponent<Health>().health -= 25;
}
}
}
I'm having some problems on instantiating an enemy in unity, it gives me always this error setDestination" can only be called on an active agent that has been placed on a NavMesh., and then it places a 2d model somewhere in my map
public GameObject enemy;
public Transform spawn;
// Start is called before the first frame update
void Start()
{
spawnNew();
}
void spawnNew() {
Instantiate(enemy, spawn.transform.position, Quaternion.identity);
}
After you have spawned an enemy, call the NavMeshAgent.Warp() function to position the agent on the desired position, which of course must be inside the navmesh.
Context
I'm working in a pickup system in my game. I've a component called AbstractSightCollider that has a sphere collider and some AbstractPickupableObject that are the objects meant to be picked up.
AbstractSightCollider is attached to the main character, but could be attached to any alive entity or anything that is able to contain inventory objects.
The way i designed it, it's that when AbstractSightCollider detects an object, it fires an UnityEvent called PickupDetected and when the player leaves the range of pickup, it call an UnityEvent called PickupLeave
The problem
I can't make OnCollisionEnter and OnCollisionExit trigger.
Some code
This is attached to AbstractSightCollider
public class AbstractObjectSight : MonoBehaviour
{
public OnPickupableDetected pickupDetected;
public OnPickupableLeave pickupLeave;
private void OnCollisionEnter(Collision col) {
GameObject gameObject = col.gameObject;
AbstractPickupableObject abstractPickupableObject =
gameObject.transform.GetComponent<AbstractPickupableObject>();
if (abstractPickupableObject != null) {
pickupDetected.Invoke(abstractPickupableObject);
}
}
private void OnCollisionExit(Collision col) {
GameObject gameObject = col.gameObject;
AbstractPickupableObject abstractInventoryObject =
gameObject.transform.GetComponent<AbstractPickupableObject>();
if (abstractInventoryObject != null) {
pickupLeave.Invoke(abstractInventoryObject);
}
}
[System.Serializable]
public class OnPickupableDetected : UnityEvent<AbstractPickupableObject> { }
[System.Serializable]
public class OnPickupableLeave : UnityEvent<AbstractPickupableObject> { }
}
And here are the properties:
Thanks for your time
Make sure both objects (the one with the script and the one that will cause the trigger) have colliders and rigidbodys, I find if one doesn't have those the triggers and collisions will not work.
I just found out the problem.
OnCollisionEnter and OnCollisionExit aren't the events that i needed to listen, because they work with rigidbody. My AbstractSight is that, a non body abstract sphere where the entities are allowed to grab items.
Instead, i used OnTriggerEnter, OnTriggerExit and now it works like a charm.
Rigid body on the parent object means the collider will work on ANY child component but the rigid body MUST be on the parent object.
Example:
MyProjectile has a rigid body and a collider - set isTrigger = true
MyEnemy parent object just holds scripts
MyEnemy childObject holds the enemy prefab including its collider,
Everything is set to isKinematic = true, with no gravity.
Everything works fine.
I have got my Hand Prefab attached to Player Prefab as a child.
I want to spawn Gun Prefab in my Hand Prefab(Players child).
Is this way i can do this from Hand level?
At the moment I am spawning Gun from Hand, but it works only on single Player. While i play with 2 players, in the moment of spawning a Gun. Game crashes for client. This is the Error im getting:
NullReferenceException: Object reference not set to an instance of an object
UnityEngine.Networking.NetworkServer.SpawnWithClientAuthority (UnityEngine.GameObject obj, UnityEngine.Networking.NetworkConnection conn) (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkServer.cs:1565)
HandHolder.CmdGetGun () (at Assets/Scripts/HandHolder.cs:27)
HandHolder.Update () (at Assets/Scripts/HandHolder.cs:19)
Thats my Code for Hand:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
public class HandHolder : NetworkBehaviour {
[SerializeField] GameObject gun;
private GameObject playerGun;
// Update is called once per frame
void Update () {
if(GetComponentInParent<NetworkIdentity>().isLocalPlayer)
{
if (playerGun)
{
playerGun.transform.position = new Vector3(transform.position.x, transform.position.y, transform.position.z - 1);
playerGun.transform.rotation = transform.rotation;
}
else if (Input.GetKeyDown(KeyCode.I))
{enter code here
CmdGetGun();
}
}
}
// [Command]
public void CmdGetGun()
{
playerGun = Instantiate(gun, transform.position, transform.rotation) as GameObject;
NetworkServer.SpawnWithClientAuthority(playerGun, GetComponentInParent<NetworkIdentity>().connectionToClient);
}
}
When im adding [Command] before CmdGetGun() method, in the moment of spawning a gun i got this error:
There is no NetworkIdentity on this object. Please add one.
UnityEngine.Networking.NetworkBehaviour:get_isServer()
HandHolder:CallCmdGetGun()
HandHolder:Update() (at Assets/Scripts/HandHolder.cs:19)
But when i add NetworkIdentity to my child Hand Prefab it shows me that hasAuthority, isLocalPlayer is False for both Hand and Player.
I have no idea how can i spawn Gun in Hand Prefab.
Here are Components and tree:
Your network object is your Player, so you need to route your network functions through your player.
Call CmdGetGun()* in your player class and call it from there.
*CmdGetGun() should not be a [Command]
Optionally, you can call CmdGetGun as a Command, but then you don't want networked instantiation, just local (the command will be called all clients, so all clients will locally create the gun).
EDIT
CmdGetGun will create the object on all clients, but it won't parent it like you are expecting. You should probably try the second approach I mentioned (call it as a command, but instantiate locally)
I'm instancing a small UI canvas with text to appear above a pick up on contact:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PickUpCheck : MonoBehaviour {
public GameObject pickUp;
public GameObject textBox;
public GameObject particle;
private Vector3 pickUpPos;
// Use this for initialization
void Start () {
pickUpPos = pickUp.transform.position;
}
void OnTriggerEnter2D(Collider2D collider)
{
Instantiate(particle, pickUpPos, new Quaternion());
Instantiate(textBox, pickUpPos , new Quaternion());
Destroy(pickUp.gameObject);
}
}
The canvas and text appear somewhere else though. Specifically, at the position of the text object I originally reference in the editor.
I'm not sure why this is overriding the position set in the instance code. I've moved the referenced canvas object prefab around (including to the origin) and re-referenced it to the pick up object and it always will appear at this position instead of the pick up position.
Edit - Just to clarify, pickUp is the game object this script is attached to. The GameObject particle is a particle effect set to instance when the object is collided with. It is unrelated to the current problem.
You're setting the position on Start() which means that it'll get set once when you start running the game.
Have you tried setting it when you need the current position, like this?
void OnTriggerEnter2D(Collider2D collider)
{
pickUpPos = pickUp.transform.position;
Instantiate(particle, pickUpPos, new Quaternion());
Instantiate(textBox, pickUpPos , new Quaternion());
Destroy(pickUp.gameObject);
}
So I found a simple solution to the problem - I assigned the instance of the created object to a variable and then set the position of that variable to the position of the pick up object:
void OnTriggerEnter2D(Collider2D collider)
{
pickUpPos = pickUp.transform.position;
textBox = Instantiate(textBox, pickUpPos , new Quaternion());
textBox.transform.position = pickUpPos;
Destroy(pickUp.gameObject);
}
Works as intended now.