Okay, I am making a simple game mechanic where you are a ball rolling along a small panel. On the edge of the panel are 8 child objects. 4 of them are triggers on the edges of the panel, and 4 of them are empty game objects 1 unit away from each edge of the panel for the location of the next panel prefab to spawn at. The ball has a trigger on it that detects the location of the empty game objects to tell the panel prefab where to spawn. When the ball enters a specific trigger frm the panel the ball is suppose to instantiate a panel prefab on the location that I assign based on the trigger the ball enters. Here is my code:
public GameObject panelPrefab;
Transform frontSpawn;
Transform backSpawn;
Transform leftSpawn;
Transform rightSpawn;
private bool allowSpawn;
void Awake()
{
allowSpawn = true;
}
void OnTriggerStay(Collider spawn)
{
if (spawn.gameObject.tag == "FrontSpawn")
{
frontSpawn = spawn.transform;
}
else if (spawn.gameObject.tag == "BackSpawn")
{
backSpawn = spawn.transform;
}
else if (spawn.gameObject.tag == "LeftSpawn")
{
leftSpawn = spawn.transform;
}
else if (spawn.gameObject.tag == "RightSpawn")
{
rightSpawn = spawn.transform;
}
}
void OnTriggerEnter (Collider other)
{
if (other.gameObject.tag == "Front" && allowSpawn == true)
{
Instantiate (panelPrefab, frontSpawn.transform.position, Quaternion.identity);
allowSpawn = false;
}
else if (other.gameObject.tag == "Back" && allowSpawn == true)
{
Instantiate (panelPrefab, backSpawn.transform.position, Quaternion.identity);
allowSpawn = false;
}
else if (other.gameObject.tag == "Left" && allowSpawn == true)
{
Instantiate (panelPrefab, leftSpawn.transform.position, Quaternion.identity);
allowSpawn = false;
}
else if (other.gameObject.tag == "Right" && allowSpawn == true)
{
Instantiate (panelPrefab, rightSpawn.transform.position, Quaternion.identity);
allowSpawn = false;
}
}
void OnTriggerExit (Collider other)
{
allowSpawn = true;
}
My issue is on each of the Instantiate calls, I am getting a NullReferenceException. I have the panelPrefab assigned in the unity editor, and I don't know what could be causing this! If anyone can help me here it would be GREATLY appreciated... So thank you in advance!
OnTriggerEnter is called before OnTriggerStay. The error is not due to the panelPrefab object. It might happen that your rightSpawn, leftSpawn etc. objects are null and hence cannot access the transform property of a null object.
Before instantiating verify if rightSpawn etc. is null or not and then access it's position.
Related
I am Working on an multiplayer fps game the code throws an missing reference exception in the line given below the error doesn't show up when there is only one player in the room but it starts coming as soon as another player joins the room
private IEnumerator Shoot()
{
ammoLeft -= 1;
animator.SetBool("fire", true);
RaycastHit hit;
if (Physics.Raycast(playerCam.position, playerCam.forward, out hit, range))
{
//Missing Reference Expection The transform you are accessing is destroyed
//code works in singleplayer
if (hit.transform.tag == "Player" && hit.transform != null)
{
HealthManager HealthScript = hit.transform.gameObject.GetComponent<HealthManager>();
if (HealthScript != null)
{
HealthScript.TakeDamage(damage);
}
}
}
yield return new WaitForSeconds(0.3f);
animator.SetBool("fire", false);
if (ammoLeft <= 0f)
{
StartCoroutine("Reload");
}
Error in this line
Physics.Raycast(playerCam.position, playerCam.forward, out hit, range)
I have checked if my camera is null but the problem doesn't fix so I am clueless
private void Awake()
{
if (!pv.IsMine)
{
Destroy(ui);
}
if (playerCam == null)
{
playerCam = FindObjectOfType<Camera>().transform;
}
ammoLeft = magazineSize;
animator = GetComponent<Animator>();
}
Inspector Window
https://i.stack.imgur.com/Tc69B.png
In my level, I have a water collider where if you fall in, it triggers a splash effect and water sounds. However, because there is already an object inside the water, whenever I start the level, the water collider triggers and splash and water sounds despite the object already being in the collider.
So, even with the object deep inside the water collider, it creates the splash sound and water effect as if it just fell in.
How do I prevent this?
My code involves OnTrigger2D functions. But how do I make Unity check if an object is already colliding before level load?
Code:
private void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Player")
{
gravityoriginal = playerrigidbody.gravityScale;
massoriginal = playerrigidbody.mass;
playerrigidbody.gravityScale = 0.1f;
playerrigidbody.mass = other.GetComponent<Rigidbody2D>().mass + 2f;
splash.Play(); //Plays the initial splash if velocity is high
underwaterbool.IsUnderwater = true; //stop dust particle
mainmusic.enabled = true;
powerupmusic.enabled = true;
deathmusic.enabled = true;
}
else if (other.tag == "Snatcher")
{
masssnatcheroriginal = snatcherrigidbody.mass;
gravityoriginalsnatcher = snatcherrigidbody.gravityScale;
snatcherrigidbody.gravityScale = 0.1f;
snatcherrigidbody.mass = other.GetComponent<Rigidbody2D>().mass + 2f;
splashsnatcher.Play();
snatchersounds.enabled = true;
}
else if (other.tag != "Player" && other.tag != "Snatcher" && other.GetComponent<Rigidbody2D>() != null)
{
gravityoriginalbox = other.GetComponent<Rigidbody2D>().gravityScale;
massoriginalbox = other.GetComponent<Rigidbody2D>().mass;
other.GetComponent<Rigidbody2D>().mass = other.GetComponent<Rigidbody2D>().mass + 2f;
other.GetComponent<Rigidbody2D>().gravityScale = 0.1f;
other.GetComponent<ParticleSystem>().Play(false);
splashaudio.Play();
Splashparticlesforbox.IsUnderwaterBox = true;
}
if(other.GetComponent<Rigidbody2D>() != null)
{
other.GetComponent<Rigidbody2D>().velocity = new Vector2(0f, -0.5f);
}
if (!cooldown)
{
splashaudio.Play();
}
cooldown = true;
StartCoroutine(waittime());
}
Can you post your OnTrigger2D functions code please? Normally Unity does not trigger the OnTriggerEnter method if an object is already inside the trigger when the scene beggins but the OnTriggerStay is executed every frame.
Anyway... one option (not the best one I think) would be to put a boolean propoerty in the trigger that is initialized true and use it to prevent the OnTriggerFunctions to do anything til the fame ends. Then in the LateUpdate method you can set the property as false.
bool m_FirstFrame = true;
void onEnable()
{
m_FirstFrame = true;
}
void OnTriggerEnter2D(Collider2D collision)
{
if(m_FirstFrame){
return;
}
.... //Rest of code
}
//Same for the other OnTrigger2D methods you use
void LateUpdate()
{
m_FirstFrame = false;
}
I hope it helps! Tell me if you need something more, and please, post your code, that way is easier for us to fint where is the issue and get how to fix it.
Good luck ^^
I'm drawing using LineRenderer but I enable and disable the gameobject where the script is at different times.
The first enable it works perfect, after I disable and enable, I get this error
IndexOutOfRangeException: Index was outside the bounds of the array.
error shows to this line of code
Vector2 touchPos = Camera.main.ScreenToWorldPoint(Input.touches[0].position);
Here is all the code
public GameObject linePrefab;
private Line activeLine;
private void Update()
{
if (Input.touchCount > 0)
{
if (Input.GetTouch(0).phase == TouchPhase.Began)
{
GameObject lineGO = Instantiate(linePrefab);
activeLine = lineGO.GetComponent<Line>();
}
if (Input.GetTouch(0).phase == TouchPhase.Ended)
{
activeLine = null;
}
}
if (activeLine != null)
{
Vector2 touchPos = Camera.main.ScreenToWorldPoint(Input.touches[0].position);
activeLine.UpdateLine(touchPos);
}
}
You're assuming the user is touching the screen in your code.
You need to check if there are any active touches before processing the touch position. Specifically, you can add to your if check whether or not Input.touchCount > 0
I am looking to show a line in my app from where the model is placed so that the user knows position where the model is kept in real world. When user changes device camera away from model the line gets turned on to show where the model is. Similarly it turns off when model is detected. I have attached images to show from a similar app white dotted lines show the path. Notice how the lines disappear when the model is detected.
LineRenderer lins;
public GameObject Lineprefab;
private GameObject newline;
public Transform startpoint;
public Renderer m_rend1;
bool HitTestWithResultType (ARPoint point, ARHitTestResultType resultTypes)
{
List<ARHitTestResult> hitResults = UnityARSessionNativeInterface.GetARSessionNativeInterface ().HitTest (point, resultTypes);
if (hitResults.Count > 0 && check==true)
{
foreach (var hitResult in hitResults)
{
Debug.Log ("Got hit!");
//obj.Hideplane();
Genplanes.SetActive(false);
if (Select == 0) {
Debug.Log("hit-zero!");
Instantiate(Instaobj[0], ForSelect);
check = false;
}
if (Select == 1) {
Debug.Log("hit-one!");
Instantiate(Instaobj[1], ForSelect);
check = false;
}
if (Select == 2) {
Debug.Log("hit-two!");
Instantiate(Instaobj[2], ForSelect);
check = false;
}
m_HitTransform.position = UnityARMatrixOps.GetPosition (hitResult.worldTransform);
m_HitTransform.rotation = UnityARMatrixOps.GetRotation (hitResult.worldTransform);
Debug.Log (string.Format ("x:{0:0.######} y:{1:0.######} z:{2:0.######}", m_HitTransform.position.x, m_HitTransform.position.y, m_HitTransform.position.z));
obj.StopPlaneTracking();
}
}
return false;
}
private void Start()
{
spawngenerator();
newline.SetActive(false);
m_rend1 = GetComponent<MeshRenderer>();
}
void spawngenerator()
{
GameObject newline = Instantiate(Lineprefab);
lins = newline.GetComponent<LineRenderer>();
}
private void LateUpdate()
{
lins.SetPosition(0, startpoint.position);
lins.SetPosition(1, m_HitTransform.position);
if( m_rend1.isVisible==true)
{
Debug.Log("Render is Visible");
newline.SetActive(false);
}
else if( m_rend1.isVisible==false)
{
newline.SetActive(true);
Debug.Log("It is InVisible");
Debug.Log("Render is InVisible");
}
}
void Update () {
#if UNITY_EDITOR //we will only use this script on the editor side, though there is nothing that would prevent it from working on device
if (Input.GetMouseButtonDown (0)) {
Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
RaycastHit hit;
//we'll try to hit one of the plane collider gameobjects that were generated by the plugin
//effectively similar to calling HitTest with ARHitTestResultType.ARHitTestResultTypeExistingPlaneUsingExtent
if (Physics.Raycast (ray, out hit, maxRayDistance, collisionLayer)) {
//we're going to get the position from the contact point
m_HitTransform.position = hit.point;
Debug.Log (string.Format ("x:{0:0.######} y:{1:0.######} z:{2:0.######}", m_HitTransform.position.x, m_HitTransform.position.y, m_HitTransform.position.z));
//and the rotation from the transform of the plane collider
m_HitTransform.rotation = hit.transform.rotation;
}
}
#else
if (Input.touchCount > 0 && m_HitTransform != null )
{
var touch = Input.GetTouch(0);
if ((touch.phase == TouchPhase.Began || touch.phase == TouchPhase.Moved) && !EventSystem.current.IsPointerOverGameObject(touch.fingerId))
{
var screenPosition = Camera.main.ScreenToViewportPoint(touch.position);
ARPoint point = new ARPoint {
x = screenPosition.x,
y = screenPosition.y
};
// prioritize reults types
ARHitTestResultType[] resultTypes = {
//ARHitTestResultType.ARHitTestResultTypeExistingPlaneUsingGeometry,
ARHitTestResultType.ARHitTestResultTypeExistingPlaneUsingExtent,
// if you want to use infinite planes use this:
//ARHitTestResultType.ARHitTestResultTypeExistingPlane,
//ARHitTestResultType.ARHitTestResultTypeEstimatedHorizontalPlane,
//ARHitTestResultType.ARHitTestResultTypeEstimatedVerticalPlane,
//ARHitTestResultType.ARHitTestResultTypeFeaturePoint
};
foreach (ARHitTestResultType resultType in resultTypes)
{
if (HitTestWithResultType (point, resultType))
{
return;
}
}
}
}
#endif
}
.
First, I 'd start with checking if the model is within the bounding box of the camera https://docs.unity3d.com/ScriptReference/Renderer-isVisible.html
if the object is not visible (isVisible == false), create a line renderer from object position to wherever it should end.
The end point could be a camera child place just in front of it, so it looks like it starts from the user to the object.
As I am new to Unity3D and started with Space Shooter tutorial. Now I am unable to create a simple life system for the space ship, probably, it's a silly mistake but I've been on it for few hours already, searching for the solution.
The OnTriggerEnter code is:
void OnTriggerEnter (Collider other)
{
if (other.CompareTag ("Boundary") || other.CompareTag ("Enemy"))
{
return;
}
if (explosion != null) //hit object explosion
{
Instantiate (explosion, transform.position, transform.rotation);
}
if (other.tag == "Player" && playerHealth >= 1) {
playerHealth--;
gameController.SubLive (playerHealth);
}
if (other.tag == "Player" && playerHealth <= 0) {
Instantiate (playerExplosion, other.transform.position, other.transform.rotation);
Destroy (other.gameObject);
gameController.GameOver ();
}
Destroy (gameObject); //destroy hit object
gameController.AddScore (scoreValue);
/**/
}
I've found that the solution is to decrement player health every time collision happens, however, it does only work the first time once player ship collides with asteroid or enemy ship. The triggers are player ship, enemy ship and bolts (shot from ships). All of the objects has rigidbody. Could you please suggest what am I doing wrong?
Thanks in advance!
You can find non-edited Space Shooter script Here
Ugh! After getting some rest and coming back with a fresh mind I managed to solve it myself! (Was easier that i thought, though!)
void OnTriggerEnter (Collider other)
{
if (other.CompareTag ("Boundary") || other.CompareTag ("Enemy"))
{
return;
}
if (explosion != null)
{
Instantiate (explosion, transform.position, transform.rotation);
}
if (other.tag == "Bolt")
{
Destroy (other.gameObject);
}
if (other.tag == "Player")
{
gameController.SubLive (); //if player ship collides asteroid or enemy ship reduces 1 health
if (gameController.isDead == true) //explodes ship once playerHealth is 0
{
Instantiate (playerExplosion, other.transform.position, other.transform.rotation);
gameController.GameOver ();
Destroy (other.gameObject);
}
}
gameController.AddScore (scoreValue);
Destroy (gameObject);
}
Script piece in gameController:
<...>
private int playerHealth;
public bool isDead;
<...>
void Start ()
{
playerHealth = 3;
isDead = false;
}
<...>
public void SubLive()
{
playerHealth--;
UpdateLives ();
if (playerHealth <= 0)
{
isDead = true;
}
}
void UpdateLives ()
{
livesText.text = "Lives: " + playerHealth;
}