Beginner having Problems with Restarting Scenes when Dying in Unity - c#

so I’m trying to create a respawn system as a beginner, and everything seems to be working the first time but the second time it seems to be unbehaving. If anyone knows how to help me, I would appreciate it
LevelControl:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class LevelControl : MonoBehaviour
{
public int index;
public string levelName;
public GameObject GameOverPanel;
public static LevelControl instance;
private void Awake()
{
if (instance == null)
{
DontDestroyOnLoad(gameObject);
instance = GetComponent<LevelControl>();
}
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("Player"))
{
//Loading level with build index
SceneManager.LoadScene(index);
//Loading level with scene name
SceneManager.LoadScene(levelName);
//Restart level
//SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}
}
public void LoadLevel1()
{
SceneManager.LoadScene("Game");
}
public GameObject GetGameOverScreen()
{
return GameOverPanel;
}
}
PlayerMovement:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public CharacterController2D controller;
public float runSpeed = 40f;
float horizontalMove = 0f;
bool jump = false;
bool crouch = false;
// Update is called once per frame
void Update()
{
horizontalMove = Input.GetAxisRaw("Horizontal") * runSpeed;
if (Input.GetButtonDown("Jump"))
{
jump = true;
}
if (Input.GetButtonDown("Crouch"))
{
crouch = true;
}
else if (Input.GetButtonUp("Crouch"))
{
crouch = false;
}
}
void FixedUpdate()
{
// Move our character
controller.Move(horizontalMove * Time.fixedDeltaTime, crouch, jump);
jump = false;
//FindObjectOfType<GameManager>().EndGame();
}
void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "Enemy")
{
//Destroy(FindObjectOfType<CharacterController2D>().gameObject);
GameObject.Find("Player").SetActive(false);
LevelControl.instance.GetGameOverScreen().SetActive(true);
}
}
}
Error In Unity Video: https://imgur.com/a/Sr0YCWk
If your wondering what I'm trying to do, well, when the 2 colliders of the Player and Enemy collide, I want a restart button to pop up, and the Character to get destroyed, and after that restart the level as is.

You didn't provide much but I try to work with what we have.
In LevelController you have
private void Awake()
{
if (instance == null)
{
DontDestroyOnLoad(gameObject);
instance = GetComponent<LevelControl>();
}
}
First of all just use
instance = this;
;)
Then you are doing
LevelControl.instance.GetGameOverScreenn().SetActive(true);
I don't see your setup but probably GetGameOverScreenn might not exist anymore after the Scene reload while the instance still does due to the DontDestroyOnLoad.
Actually, why even use a Singleton here? If you reload the entire scene anyway you could just setup the references once via the Inspector and wouldn't have to worry about them later after scene changes...
Also
GameObject.Find("Player").SetActive(false);
seems odd .. isn't your PlayerController attached to the Player object anyway? You could just use
gameObject.SetActive(false);

Ok, Normally it would be easier just to do this:
if (collision.gameObject.tag == "Enemy")
{
//Destroy(FindObjectOfType<CharacterController2D>().gameObject);
gameObject.SetActive(false);
LevelControl.instance.GetGameOverScreen().SetActive(true);
But this will NOT work if you want to attach the script to any other gameobjects for any reason. If you are then first make a game object variable containing the player, like this:
public GameObject Player = GameObject.Find("Player");
Then say
Player.SetActive(false);
This creates a player gameobject which you can access by calling the variable.

Related

Why can I not collect coins and I get an error message

I'm new to unity and C# as well but I do have a small understanding of it because I've learnt python. At the moment I've run into an error, I'm trying to make a coin collection system and also the players movement in one script simply because it seems neater that way and easier to play audio.
The error comes up on this line, [SerializeField] private Transform groundcheck = null; (it's used so the player can jump over and over). I have a theory that maybe I just need to change the collision value, but other then no clue what I need to do to change this error.
Full Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
[SerializeField] private Transform groundcheck = null;
private bool jumpkeywaspressed;
private float horizontalInput;
private Rigidbody rigibodycomponent;
public AudioSource coincollect;
// Start is called before the first frame update
void Start()
{
rigibodycomponent = GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
jumpkeywaspressed = true;
horizontalInput = Input.GetAxis("Horizontal");
}
private void FixedUpdate()
{
rigibodycomponent.velocity = new Vector3(horizontalInput * 3, rigibodycomponent.velocity.y,0);
if (Physics.OverlapSphere(groundcheck.position, 0.1f).Length == 1)
{
return;
}
if (jumpkeywaspressed)
{
rigibodycomponent.AddForce(Vector3.up * 5, ForceMode.VelocityChange);
jumpkeywaspressed = false;
}
}
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.layer == 6)
{
coincollect.Play();
ScoreManager.sManger.IncreaseScore(1);
Destroy(other.gameObject);
}
}
}
I also have another script which is used to increase the score but I don't think it effects my error.

Unity - Actions Being Called Twice - OnTriggerEnter, OnClick, EVERYTHING? [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 10 months ago.
Improve this question
So I'm creating a Sheep Counter Game and yesterday, when I went to bed everything was working great. Today, when I opened Unity up to do some finishing touches, everything I'm doing is being called twice...
So when I click the start button it calls the start game twice, then when my sheep hit obstacles it calls OnTriggerEnter twice. Idk what I did wrong or what happened and would prefer to not have to restart the whole project...
Console Log
Counter Script
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
public class Counter : MonoBehaviour
{
public TMP_Text savedText;
public TMP_Text deadText;
private int savedCount = 0;
private int deadCount = 0;
private void Start()
{
savedCount = 0;
deadCount = 0;
}
public void AddSavedSheep()
{
savedCount++;
savedText.text = "Saved: " + savedCount;
}
public void AddDeadSheep()
{
deadCount++;
deadText.text = "Dead: " + deadCount;
}
}
Sheep Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SheepControls : MonoBehaviour
{
private Rigidbody rb;
[Header("Movement")]
[Tooltip("How fast to move GameObject Forward.")]
public float forwardSpeed = 4.0f;
[Tooltip("Apply this much force to Rigidbody.")]
public float jumpForce = 5.0f;
private float groundY;
[Space]
[SerializeField] private bool jumping;
[SerializeField] private bool isDestroyed;
[SerializeField] private bool isSaved;
public ParticleSystem explosionParticles;
private Counter counter;
void Start()
{
rb = GetComponent<Rigidbody>();
groundY = (transform.position.y)+0.02f;
counter = FindObjectOfType<Counter>();
}
void Update()
{
transform.Translate(forwardSpeed * Time.deltaTime * Vector3.forward);
if (Input.GetKeyDown(KeyCode.Space) && !jumping)
{
if(transform.position.y < groundY)
{
Jump();
}
}
jumping = false;
}
private void Jump()
{
jumping = true;
rb.AddForce(Vector3.up * jumpForce);
}
private void OnTriggerEnter(Collider other)
{
if (other.CompareTag("ExplosiveWire"))
{
if (isDestroyed) return;
else
{
Debug.Log("Hit Wire");
isDestroyed = true;
Destroy(gameObject);
Instantiate(explosionParticles, transform.position,
explosionParticles.transform.rotation);
}
counter.AddDeadSheep();
}
if (other.CompareTag("Goal"))
{
if (isSaved) return;
else
{
Debug.Log("Reached Goal");
isSaved = true;
Destroy(gameObject);
}
counter.AddSavedSheep();
}
}
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.CompareTag("Sheep"))
{
Physics.IgnoreCollision(this.GetComponent<Collider>(),
collision.gameObject.GetComponent<Collider>());
}
}
}
GameManager Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class GameManager : MonoBehaviour
{
public bool isGameActive;
public GameObject titleScreen;
public GameObject sheepControllerPrefab;
public void StartGame(int difficulty)
{
titleScreen.SetActive(false);
isGameActive = true;
InvokeRepeating(nameof(SpawnSheepWave), 2.0f, 2.0f);
}
public void Restart()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
}
public void SpawnSheepWave()
{
Instantiate(sheepControllerPrefab, transform.position,
transform.rotation);
}
}
Start Button Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class DifficultyButton : MonoBehaviour
{
private Button button;
private GameManager gameManager;
[Header("Difficulty Level")]
[Tooltip("The spawn rate will be divided by this number.")]
public int difficulty;
void Start()
{
gameManager = GameObject.Find("GameManager").GetComponent<GameManager>();
button = GetComponent<Button>();
button.onClick.AddListener(SetDifficulty);
}
public void SetDifficulty()
{
Debug.Log(gameObject.name + " was clicked.");
gameManager.StartGame(difficulty);
}
}
So, it's actually adding the score twice, so originally I thought maybe I need to do an isDestroyed or isSaved check and added that to the script but nothing seems to keep it from adding the score twice, or thinking I clicked the start button twice.
Double increment of the score
I feel like my code is fine, I just don't know what is going on with it and why it is calling everything twice. Do you think there is a solution, or that I might just have to recreate the game in a new project?
Would trying to disable the box collider when it enters the trigger maybe fix the problem?
There is only one BoxCollider on the sheep, and the one BoxCollider on the fence, and one BoxCollider on the goal. They all have rigid bodies and the calls are being made correctly, they just happen two times at once.
Thanks for any help you guys can provide!
I also tried moving the increment step before or after the if statements to see if it would do anything different but I get the same results.
private void OnTriggerEnter(Collider other)
{
if (other.CompareTag("ExplosiveWire"))
{
if (isDestroyed) return;
else
{
Debug.Log("Hit Wire");
isDestroyed = true;
Destroy(gameObject);
Instantiate(explosionParticles, transform.position,
explosionParticles.transform.rotation);
counter.AddDeadSheep();
}
}
if (other.CompareTag("Goal"))
{
if (isSaved) return;
else
{
Debug.Log("Reached Goal");
isSaved = true;
Destroy(gameObject);
counter.AddSavedSheep();
}
}
}
[Edit]
Added Image of scripts attached to game objects.
Scripts Attached to Game Objects
Each click you call start on your difficulty button. Which has already run. So you will get 2. See the choices in your start button inspector

Game object can't detect others when using collision.gameObject.tag in unity

I have designed a scenario as below:
I created an object spawner to collide with things tagged as "ob", using a boolean to manage the timing to spawn new obstacles. Nonetheless, after some testing, I found that it seemed like nothing had ever collided with one another(Judged by the strings I put in the if condition had never shown in the console.) Can't figure out why! Please HELP!!!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class newObSpawning : MonoBehaviour
{
public GameObject[] oblist;
private bool hasOb=true;
public float adjustSpawnx;
void Update()
{
if (!hasOb)
{
spawnObs();
hasOb = true;
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.CompareTag("ob"))
{
hasOb = true;
Debug.Log("hasOb"); //just for testing
}
}
private void OnTriggerExit2D(Collider2D collision)
{
if (collision.gameObject.CompareTag("ob"))
{
hasOb = false;
Debug.Log("hasOb");
}
}
public void spawnObs()
{
int i = Random.Range(0, oblist.Length);
Debug.Log(i);
float y = 7.87f;
GameObject newob = Instantiate(oblist[i], new Vector3(transform.position.x+ adjustSpawnx,y,0), Quaternion.identity);
}
}
obspawner carry a "follow player" script to move at the same pace as the player,and it went just well
Your player doesn't seem to have a Rigidbody2D component. Add Rigidbody2D to your player. A collider can only emit OnTriggerEnter2D or OnTriggerExit2D events if there is a rigidbody on the object too
You have to tag the object "ob" that you want to register the collision with, most probably, I think what you are searching for is the collision of your player with object spawner so tag the player with "ob".

Trying to get death and respawn working in my game

I can't get my respawning in my game to work, I have followed numerous tutorials, but have been failing to change one small aspect of them. I have a health variable in my game, and all the tutorials have the player die and respawn right upon touching the enemy. I want it to be so you take damage when touching an enemy, and when your health reaches 0 you are brought to a game over scene. I just can't seem to figure it out. I am new to game dev so I have tried my absolute hardest to solve the problem on my own, but to no avail. This is pretty much my last resort. I appreciate any help I can get.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class PlayerHealth : MonoBehaviour
{
public static PlayerHealth instance;
public int maxHealth;
public int health;
public int GameOver;
public event Action DamageTaken;
public int Health
{
get
{
return health;
}
}
// Start is called before the first frame update
void Awake()
{
if(instance == null)
{
instance = this;
}
}
private void Start()
{
health = maxHealth;
}
// Update is called once per frame
public void TakeDamage()
{
if(health <= 0)
{
return;
}
health -= 1;
if(DamageTaken != null)
{
DamageTaken();
}
}
public void heal()
{
if (health >= maxHealth)
{
return;
}
health += 1;
if (DamageTaken != null)
{
DamageTaken();
}
}
void OnCollisionEnter(Collision other)
{
if(other.gameObject.tag == "Enemy")
{
TakeDamage();
}
if(health <= 0)
{
SceneManager.LoadScene(GameOver);
}
}
}
I don't see anything wrong with your code specifically. It could be a different issue in the editor, which is usually the case. To debug try one of the following:
Check that the OnCollisionEnter is actually being triggered
Check that the Enemey has the Enemy Tag.
You can check 1 & 2 with the following code:
void OnCollisionEnter(Collision other)
{
// Check what the tag is
print(other.gameObject.tag);
...
}
There should now be messages when you run the program. Other things to check:
Make sure the player object has the PlayerHealth script attached to it.
Make sure that the player has a RigidBody
Make sure the enemy has a collider
Make sure the enemy collider is not set to Trigger

OnCollisionEnter not working Unity3D

I'm trying to build a game where u need to dodge falling objects. I've made a hazard but it seems as if the hazard 'clone' is behaving diffrently.
I've made a collision script when the hazard hits the platform it needs to disappear. This works for the hazard object, but not the hazard clone objects that fall.
As u can see in the first screenshot, the red circled block behaves
like it use to. But the blue circled once (clones) fall right through
objects.
As u can see in the second screenshot, the red circled one is gone,
because it hit the platform. But still the blue once fall right
through.
Thanks in advance!
Below u will find the Collision script, below that is the Hazard Spawn script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HazardCollisionFunctions : MonoBehaviour {
#region Variables
//Public
//Private
#endregion
#region UnityFunctions
void Start()
{
}
void Update()
{
}
#endregion
private void OnCollisionEnter(Collision collision)
{
if(collision.gameObject.tag == "platform")
{
this.gameObject.SetActive(false);
}
if(collision.gameObject.tag == "Player")
{
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpawnHazards : MonoBehaviour {
#region Variables
//Public
//Private
[SerializeField]
public float minX = 0.0f;
[SerializeField]
public float maxX = 0.0f;
[SerializeField]
private GameObject[] hazards; //potential array of hazards
[SerializeField]
private float timeBetweenSpawns = 0.0f;
private bool canSpawn = false;
private int amountOfHazardsToSpawn = 0;
private int hazardToSpawn = 0;
#endregion
#region UnityFunctions
public void Start()
{
canSpawn = true; //Temp start
}
public void Update()
{
if(canSpawn == true)
{
StartCoroutine("GenerateHazard");
}
}
#endregion
private IEnumerator GenerateHazard()
{
canSpawn = false;
timeBetweenSpawns = Random.Range(0.5f, 2.0f); //Testing values
amountOfHazardsToSpawn = Random.Range(1, 5); //Testing values
for(int i = 0; i < amountOfHazardsToSpawn; i ++)
{
Vector3 spawnPos = new Vector3(Random.Range(minX, maxX), 8.0f, 0.0f); //Gen spawnpoint for the hazard
Instantiate(hazards[hazardToSpawn], spawnPos, Quaternion.identity); //Spawn the hazard
}
yield return new WaitForSeconds(timeBetweenSpawns);
canSpawn = true;
}
}
OnCollisionEnter
OnCollisionEnter takes Collision object as a parameter and it requires the isTrigger property of the attached Collider component to be FALSE.
void OnCollisionEnter(Collision collision)
{
foreach (ContactPoint contact in collision.contacts)
{
Debug.DrawRay(contact.point, contact.normal, Color.white);
}
}
OnTriggerEnter
OnTriggerEnter takes Collider object as a parameter and it requires the isTrigger property of the attached Collider component to be TRUE.
void OnTriggerEnter(Collider other)
{
if (other.CompareTag("CheckPoint"))
{
Destroy(other.gameObject);
}
}
If you are instantiating the object from prefab, make sure that
prefab have required components (rigidbody/collider) and
properties to achieve the desired behaviour.
To detect Collision/Trigger, at least one of the object must have a
physics component (Rigidbody)
Rigidbody MUST be attached to the moving object.
Hope this helps :)

Categories