Respawn code not working in Unity, Can anyone help me? - c#

My code doesn't work. The player is supposed to respawn when a player with the tag "Player" interacts with an object with this code. Can someone help me, thanks in advance! Code ☟
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class KillPlayerLava : MonoBehaviour
{
public int Respawn;
public float Seconds;
public MonoBehaviour script;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
public IEnumerator OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.CompareTag("Player"))
{
yield return new WaitForSeconds(Seconds);
SceneManager.LoadScene(Respawn);
script.enabled = false;
}
}
}

Here are something which might help you find the answer, the code you posted looks fine but there can be other things causing the issue.
Does your gameobject have a 2D collider?
Does one of the objects that it's colliding with have a Rigidbody2D?
Note: Trigger events are only sent if one of the Colliders also has a Rigidbody2D attached. Trigger events are sent to disabled MonoBehaviours, to allow enabling Behaviours in response to collisions.
Source docs : MonoBehaviour.OnTriggerEnter2D(Collider2D)
Does your play have the Player tag set?

Related

Unity3D OnTriggerEnter2D is never called

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PickupCoin : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.CompareTag("Player"))
{
Destroy(this.gameObject);
Debug.Log("Coin was picked up");
}
}
}
Script is assigned to randomly spawned sprites, but player cannot interact with them, and Debug is never called. This means method is never called for reasons unknown to me.
If you need additional info I can provide it.
First, just check if the player and the created sprites have a Box Collider component.

Why wont the code print in Unitys console?

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
the stuff at the top is just stuff unity adds i am just adding this because my post has too much code apparently
void Update()
{
This tells it to print hi in the console
if (Input.GetKeyDown(KeyCode.Space)) ;
{
Debug.Log("hi.");
}
}
}
hmm, may be your problem is in your code, just clear the ; element
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
Debug.Log("hi.");
}
}
The compiler will show you a red error and also in unity editor.
If you have done my instruction but still can not do it, create a gameobject in the hierarchy and drag the script you have written to the gameobject

Can't figure out what i've done wrong

I'm new to programming and I'm currently trying to do a simple game in Unity.
The code makes some things dissapear when they touch the ground and it works well but the "Evaporated" variable does not update in the Unity Inspector. When something touch the ground, evaporated should be incremented, but it stays at 0.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;
public class EnemyEvaporate : MonoBehaviour
{
public GameObject Enemy;
public int Evaporated;
void OnCollisionEnter(Collision CollisionInfo)
{
if (CollisionInfo.gameObject.name == "Map" || CollisionInfo.gameObject.name == "Player")
{
Thread.Sleep(15);
gameObject.SetActive(false);
Evaporated++;
}
}
}
I'm not really sure what's the behavior you're trying to get in this script. If Evaporated is some kind of 'Global counter' for score, it need to be written different and not store inside script for this gameObject.
It might be related to your gameObject.SetActive(false) which will deactivate your object, so in fact it will disables also the scripts connected with it (and especially this one. SetActive documentation) and removes them from Update() for a given gameObject (so given enemy. If you have 4 Enemy objects on the Scene, in fact you have 4 instances of this script and each has own Evaporated variable)
Why won't you move the void OnCollisionEnter(Collision CollisionInfo) to your Enemy scipt? I think Enemy should now if it collided with anything, not some external script.
You can also use tags instead of names when detecting Collisions.
Also, gameObject.SetActive(false) - if you set your gameObject to disabled, nothing more from its script will happen unless you set it to active again. It e.g. cancels all Coroutine. The gameObject is just "sleeping", I would say. It's not destroyed - you still can see it in your Hierarchy window - but it can't do anything. (By the way, in this case you're setting EnemyEvaporate gameObject as disabled, not Enemy gameObject.)
Also, you can use Coroutine instead of Thread.Sleep(15). It is more common to use Coroutines than Threads in Unity.
Now, Evaporation. If you want to count how many Enemies evaporated (I suppose, looking at Evaporated++;) you should have some external object to count it. The simplest way I can propose fow now is creating a GameObject with EvaporationCounter : MonoBehaviour script attached to it. You can also use Singleton pattern to be sure there's only one object of this type.
public class EvaporationCounter : MonoBehaviour
{
private int evaporates;
public int Evaporates {
get { return evaporates; }
private set
{
if (value >= 0) evaporates = value;
}
}
public void AddEvaporation()
{
Evaporates++;
}
}
Your Enemy class could look like:
public class Enemy : MonoBehaviour
{
private IEnumerator coroutine;
private EvaporationCounter evaporationCounter;
private void Start()
{
evaporationCounter = FindObjectOfType<EvaporationCounter>();
}
private IEnumerator WaitAndSetInactive(float waitTime)
{
yield return new WaitForSeconds(waitTime);
gameObject.SetActive(false);
}
private void OnCollisionEnter(Collision CollisionInfo)
{
if (!CollisionInfo.gameObject.CompareTag("Map") && !CollisionInfo.gameObject.CompareTag("Player")) return;
if (evaporationCounter != null)
evaporationCounter.AddEvaporation();
StartCoroutine(WaitAndSetInactive(15f));
}
}
Calling evaporationCounter.AddEvaporation() from the Enemy script is not the best solution, since it does not apply to the Dependency Inversion principle but I would say it's good for the beginning with Unity.

Calling a script from NPCs in Unity to trigger dialogue

I have followed Brackeys tutorial on Youtube (https://www.youtube.com/watch?v=_nRzoTzeyxU) on how to create a dialogue system for a game. I am currently attempting to adapt this system to where the player can walk up to an NPC and press the "Submit" button to access their dialogue, instead of clicking a button on the canvas/UI like the video shows. To those who have played games like Super Mario64, The Legend of Zelda: Ocarina of time, or most games with text dialogue you may recognize this.
The Interactable script I created detects whether the player is within the collision sphere or not that the NPC has, and allows the player to press the "Submit" button on what is supposed to call the dialogue for the NPC in range. I'm just not sure how to call the script that I named DialogueTrigger that holds the dialogue for the NPC. That, or what I'm trying to accomplish is not being accomplished in the way that I am trying. Any help would be appreciated.
Interactable Script: `
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Interactable : MonoBehaviour {
private GameObject triggeringNpc;
private bool triggering;
public DialogueTrigger Diag;
void Start()
{
}
void Update()
{
if(triggering)
{
Debug.Log("Within Range");
if (Input.GetButtonDown("Submit"))
{
Debug.Log("Pressed the Interact Button");
Diag.TriggerDialogue();
}
}
}
void OnTriggerEnter(Collider other)
{
if(other.tag == "NPC")
{
triggering = true;
triggeringNpc = other.gameObject;
}
}
void OnTriggerExit(Collider other)
{
if(other.tag == "NPC")
{
triggering = false;
triggeringNpc = null;
}
}
}
`
Right now I can put a script for one NPC in the script and it works, but I would rather it call whatever Dialogue Trigger Script that the NPC has. I'm sure there's something I'm missing here.
This one is for Dialogue Trigger
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DialogueTrigger : MonoBehaviour
{
public Dialogue dialogue;
public void TriggerDialogue ()
{
FindObjectOfType<DialogueManager>().StartDialogue(dialogue);
Debug.Log("dm called"); } else { Debug.Log("dm is null"); }
}
}
Solved this as soon as I posted it. Turns out I just needed to combine the Interactable script with the dialogue triggers script and rearranging the collision tags to hit the player that was tagged "Player" rather than having a separate script that detected collision to the NPC.

Go to next level when Key is grabbed by Player Unity 2d

I need some help with a feature I'm implementing for a game made in Unity 2D.
The player must take a key in order to unlock a door (maybe showing an animation) and when the player go in front of that door if he has the key, he will automatically go to the next level.
I need help, cause the door is not letting go to the next level.
Here is the KEY code/script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class KeyScript : MonoBehaviour {
//public AudioSource coinSoundEffect;
public AudioClip key1;
void Awake () {
//source = GetComponent<AudioSource>();
}
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
void OnCollisionEnter2D (Collision2D other) {
Debug.Log("Chiave Presa");
if(other.gameObject.tag =="Player")
GameObject.Find("KeyDoor").SendMessage("HitKey");
SoundManager2D.playOneShotSound(key1);
}
}
Here is the DOOR code/script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class DoorScript : MonoBehaviour {
public bool key = false;
public string nextLevelName;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
void HitKey (){
Debug.Log("La porta è sbloccata");
key = true;
Destroy (GameObject.Find ("Key"));
}
void OnCollisionEnter2D (Collision2D other){
if(other.gameObject.tag == "Player"){
if (key == true){
Application.LoadLevel(nextLevelName);
//Destroy(gameObject);
//GameObject.Find("Key").SendMessage("DestroyKey"); //If you also want to destroy the key
//GoToNextLevel ();
}
}
}
void OnTriggerEnter2D (Collision2D other)
{
Application.LoadLevel(nextLevelName);
}
public virtual void GoToNextLevel()
{
//loadingImage.SetActive(true);
Application.LoadLevel(nextLevelName);
}
}
The code works but when the player goes in front of the door, he is not passing to the next level.
Any help or hint appreciated.
Cheers
First of all, you're missing one thing:
unity is Component based engine
This means you should make interactions between Components, not GameObjects.
In your script there's a public field public bool key which should not be accessible from the outside. But if you're looking for simple and wrong answer that will work then you can just replace this line :
GameObject.Find("KeyDoor").SendMessage("HitKey");
Into this one :
GameObject.Find("KeyDoor").GetComponent<DoorScript>().key = true;
In that case you'll end up with messy code and unstable game. What I can recommend to you as an good alternative is to rewrite your logic a bit.
Instead of making a MonoBehaviour which is not needed you can just create a Component :
public class KeyComponent : Component
{
[SerializeField]
AudioClip m_KeyPickupSound;
[SerializeField]
bool m_IsPickedUp;
public bool PickedUp
{
get { return m_IsPickedUp; }
}
public void PickUp()
{
m_IsPickedUp = true;
SoundManager2D.playOneShotSound(m_KeyPickupSound);
}
}
Now attach this into your Player's Components list and in your door script do:
void OnCollisionEnter2D (Collision2D other)
{
if(other.GetComponent<KeyComponent>() != null && other.GetComponent<KeyComponent>().PickedUp)
{
SceneManager.LoadScene(2);
}
}
Now only thing left is to update your Player's MonoBehaviour and add simple collision check :
void OnCollisionEnter2D(Collision2D other)
{
if(other.tag == "TAG_FOR_KEY")
GetComponent<DoorScript>().PickUp();
}
Now you're interacting with Components and not GameObject which then require less effort changing some scripts.
First off, you should change Application.LoadLevel to SceneManager.LoadScene. The first is obsolete in the newer versions of unity.
Second you need to make sure that your scenes are actually registered in File -> BuildSettings and the parameter you pass to LoadScene matches either the index in that list or the name as string.
Make sure your player needs to have a Rigidbody2D and a Collider2D and the door has a Collider2D component
If your doors Collider2D is a trigger you must use void OnTriggerEnter2D(Collider2D other).
Another problem may be that "Level 2" isn't added to your build settings, make sure that it is added to the level's list.
Answering your last comment as it seemed the problem was that the Collider2D on the door, you can make this in a lot of ways, the easiest way is this:
Add a public string variable called nextLevelName in your Door's script, then when calling LoadLevel, use this variable. You can change the value from the inspector in each level. The problem with this is that if you rearrange the levels then you need to change the strings in each level.
The best solution in that case is this one:
int currentLevelNum = SceneManager.GetActiveScene().buildIndex;
SceneManager.LoadScene(currentLevelNum+1);
This way if you have your levels in order in your build settings you don't need to do anything else.

Categories