enable onCollitionEnter by a variable - c#

I have 2 script and i am try to make one trigger for the first script to enable other script trigger, i have try to investigate but i still stuck on my code.
my first code is
using UnityEngine;
using System.Collections;
public class endpoint10 : MonoBehaviour {
public static int IsColliderEnabled;
endpoint10.IsColliderEnabled = 0;
void OnTriggerEnter(Collider other)
{
if (IsColliderEnabled = 1) {
//do stuff here
// The switch statement checks what tag the other gameobject is, and reacts accordingly.
switch (other.gameObject.tag) {
case "end":
Debug.Log (other.gameObject.tag);
PlayerPrefs.SetInt ("moneyPref", scoreManager.money);
PlayerPrefs.SetInt ("scorePref", scoreManager.score);
ScoreSystem.level += 1;
PlayerPrefs.SetInt ("levelPref", ScoreSystem.level);
Debug.Log ("values stored");
Application.LoadLevel ("level_11");
break;
}
}
// Finally, this line destroys the gameObject the player collided with.
//Destroy(other.gameObject);
}
}
and my second code is
using UnityEngine;
using System.Collections;
public class trigguercubex : MonoBehaviour {
public GameObject[] objects;
void OnTriggerEnter(Collider other)
{
endpoint10.IsColliderEnabled = 1;
Debug.Log (other.gameObject.tag);
}
// Finally, this line destroys the gameObject the player collided with.
//Destroy(other.gameObject);
}

Do you have a game manager script?
You could use setters and getters
using UnityEngine;
using System.Collections;
public class GameManager : MonoBehaviour {
public static GameManager instance = null;
private bool triggerredOccurred = false;
public bool IsTriggerredOccurred {
get { return triggerredOccurred;}
}
public void TriggerredOccurred() {
triggerredOccurred = true;
}
void Awake(){
if (instance == null) { //check if an instance of Game Manager is created
instance = this; //if not create one
} else if (instance != this) {
Destroy(gameObject); //if already exists destroy the new one trying to be created
}
DontDestroyOnLoad(gameObject); //Unity function allows a game object to persist between scenes
}
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
}
In your endpoint class, when the collision was detected
GameManager.instance.TriggerOccurred ();
In your trigguercubex class
if (GameManager.instance.IsTriggerOccurred) {
do some stuff ();
}
I attach the GameManager script to my game's Main Camera

Related

Error MissingReferenceException: The object of type 'GameObject' has been destroyed but you are still trying to access it

I have been making a 2D game in Unity. I'm trying to make a game over screen appear every time a ball touches the player. I also added advertisements to release it. I added Restart and Continue buttons. When you press continue, an ad shows and the game continues. When Restart is pressed, it resets the game and your score. Whenever I restart the game and then press continue, the ad is played, but the game does not continue.
Here is the collision script:
using UnityEngine;
public class hitDetect : MonoBehaviour
{
public GameObject menuContainer;
private void OnTriggerEnter2D(Collider2D other)
{
Debug.Log("HIT");
menuContainer.SetActive(true);
Time.timeScale = 0;
}
}
This is the script that restarts the game:
using UnityEngine;
using UnityEngine.SceneManagement;
public class RestartGame : MonoBehaviour
{
public void Restart()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
Time.timeScale = 1;
}
}
Here is the advertisement and continue script:
using UnityEngine;
using UnityEngine.Advertisements;
public class continueGame : MonoBehaviour, IUnityAdsListener
{
string placement = "rewardedVideo";
public GameObject menuContain;
private void Start()
{
Advertisement.AddListener(this);
Advertisement.Initialize("4006857", true);
}
public void Continue(string p)
{
Advertisement.Show(p);
}
public void OnUnityAdsReady(string placementId)
{
}
public void OnUnityAdsDidError(string message)
{
}
public void OnUnityAdsDidStart(string placementId)
{
}
public void OnUnityAdsDidFinish(string placementId, ShowResult showResult)
{
if(showResult == ShowResult.Finished)
{
menuContain.SetActive(false);
Time.timeScale = 1;
}
}
}
Once you call
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex)
a "new" scene is loaded and therefore anything currently existing is destroyed.
In continueGame you do
private void Start()
{
Advertisement.AddListener(this);
Advertisement.Initialize("4006857", true);
}
But you never remove that listener!
Thus the next time the Advertisement fires its event it is still trying to execute them of the now already destroyed continueGame instance.
Therefore you always should remove any listeners as soon as you don't need them anymore:
private void OnDestroy ()
{
Advertisement.RemoveListener(this);
}

Beginner having Problems with Restarting Scenes when Dying in Unity

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.

Why is OnLevelWasLoaded () called twice and why are my variable's values different in each call?

I currently have 2 scenes, house scene and overworld scene. Whenever the player enters the house scene, I will save the previous scene with currentArea and position with currentPosition in that scene the player was at. After exiting the house scene, the player will go back to where they last were by checking if the loaded scene's name is currentArea. However, I am currently encountering a problem as I notice that OnLevelWasLoaded() is called twice when a scene is loaded. Furthermore, currentArea will contain the previous scene's data in one call but be empty in another call.
I have tried putting the code in Awake() or Start().
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class SceneTransition : MonoBehaviour
{
public static SceneTransition instance = null;
[SerializeField] string currentArea = "";
[SerializeField] Vector3 currentPosition;
void Awake()
{
if (instance == null)
instance = this;
else if (instance != this)
{
Destroy(gameObject);
return;
}
DontDestroyOnLoad(gameObject);
if (SceneManager.GetActiveScene().name == currentArea)
{
BasePlayer.instance.transform.position = currentPosition;
CameraController.instance.transform.position = new Vector3(currentPosition.x, currentPosition.y, CameraController.instance.transform.position.z);
}
else if (GameObject.FindGameObjectWithTag("StartingPoint"))
{
BasePlayer.instance.transform.position = GameObject.FindGameObjectWithTag("StartingPoint").transform.position;
CameraController.instance.transform.position = new Vector3(GameObject.FindGameObjectWithTag("StartingPoint").transform.position.x, GameObject.FindGameObjectWithTag("StartingPoint").transform.position.y, CameraController.instance.transform.position.z);
}
}
private void OnLevelWasLoaded(int level)
{
if (SceneManager.GetActiveScene().name == currentArea)
{
BasePlayer.instance.transform.position = currentPosition;
CameraController.instance.transform.position = new Vector3(currentPosition.x, currentPosition.y, CameraController.instance.transform.position.z);
}
else if (GameObject.FindGameObjectWithTag("StartingPoint"))
{
BasePlayer.instance.transform.position = GameObject.FindGameObjectWithTag("StartingPoint").transform.position;
CameraController.instance.transform.position = new Vector3(GameObject.FindGameObjectWithTag("StartingPoint").transform.position.x, GameObject.FindGameObjectWithTag("StartingPoint").transform.position.y, CameraController.instance.transform.position.z);
}
}
public void LoadArea(string nextArea)
{
SceneManager.LoadScene(nextArea);
}
public void LoadEvent(string nextScene)
{
SaveCurrentArea();
SceneManager.LoadScene(nextScene);
}
public void SaveCurrentArea()
{
currentArea = SceneManager.GetActiveScene().name;
currentPosition = BasePlayer.instance.transform.position;
}
public void LoadCurrentArea()
{
SceneManager.LoadScene(currentArea);
}
}
I expected currentArea to be the name of the previous area the player was at but it is sometimes null
You can try out the alternative approach described here
using UnityEngine.SceneManagement;
void OnEnable()
{
//Tell our 'OnLevelFinishedLoading' function to start listening for a scene change as soon as this script is enabled.
SceneManager.sceneLoaded += OnLevelFinishedLoading;
}
void OnDisable()
{
//Tell our 'OnLevelFinishedLoading' function to stop listening for a scene change as soon as this script is disabled. Remember to always have an unsubscription for every delegate you subscribe to!
SceneManager.sceneLoaded -= OnLevelFinishedLoading;
}
void OnLevelFinishedLoading(Scene scene, LoadSceneMode mode)
{
Debug.Log("Level Loaded");
Debug.Log(scene.name);
Debug.Log(mode);
}

Unity 3D Attaching Score Display Script to prefab

I was following Unity 3d tutorial on the Learn Unity website, but here is the thing I wanted to do things a bit differently. It worked out well at start but in the end this turned out to be a bad decision and now I manually need to attach the script to every pickable object.
Here is my code:
Note: What it does is rotate the Pickups and display the score when the pickups collide with player ball.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PickUps : MonoBehaviour {
public Vector3 Rotate;
private int Score;
public Text ScoreGUI;
private void Start()
{
Rotate = new Vector3(0, 25, 0);
Score = 0;
DisplayScore();
}
void Update () {
transform.Rotate(Rotate*Time.deltaTime);
}
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("Ball"))
{
Destroy(this.gameObject);
Score = Score + 1;
DisplayScore();
}
}
void DisplayScore()
{
ScoreGUI.text = "SCORE " + Score.ToString();
}
}
Problem:
It works yes but I need to manually attach the text (under canvas) to every pickup object which is exhausting and not a good thing to do.
What I want To achieve:
Like in the tutorials mostly they use prefabs in this kind of work (I think), problem is I can attach the text to the pickups (objects/biscuits) in the current scene but I cannot drag and attach the text To the prefab of biscuits I made the text just wont attach in its blank for "Text".
You shouldn't change the score Text directly. Use a Controller to make the bridge instead. I would do something like this:
Put this script somewhere in your scene:
public class ScoreManager : Singleton<ScoreManager>
{
private int score = 0;
// Event that will be called everytime the score's changed
public static Action<int> OnScoreChanged;
public void SetScore(int score)
{
this.score = score;
InvokeOnScoreChanged();
}
public void AddScore(int score)
{
this.score += score;
InvokeOnScoreChanged();
}
// Tells to the listeners that the score's changed
private void InvokeOnScoreChanged()
{
if(OnScoreChanged != null)
{
OnScoreChanged(score);
}
}
}
This script attached in the Text game object:
[RequireComponent(typeof(Text))]
public class ScoreText : MonoBehaviour
{
private Text scoreText;
private void Awake()
{
scoreText = GetComponent<Text>();
RegisterEvents();
}
private void OnDestroy()
{
UnregisterEvents();
}
private void RegisterEvents()
{
// Register the listener to the manager's event
ScoreManager.OnScoreChanged += HandleOnScoreChanged;
}
private void UnregisterEvents()
{
// Unregister the listener
ScoreManager.OnScoreChanged -= HandleOnScoreChanged;
}
private void HandleOnScoreChanged(int newScore)
{
scoreText.text = newScore.ToString();
}
}
And in your PickUps class:
void DisplayScore()
{
ScoreManager.Instance.SetScore(Score); // Maybe what you need is AddScore to not
// reset the value everytime
}
A simple singleton you can use (you can find more complete ones on the internet):
public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
static T instance;
public static T Instance
{
get
{
if (instance == null)
{
instance = (T)FindObjectOfType(typeof(T));
if (instance == null) Debug.LogError("Singleton of type " + typeof(T).ToString() + " not found in the scene.");
}
return instance;
}
}
}
But be careful, the singleton pattern can be a shot in the foot if not used correctly. You should only it them moderately for managers.

Meeting a condition before allowing level to change

I'm trying to add a coin to my game. If the coin isn't touched then the level won't be able to switch until the player touches the coin. My scripts are trying to set a value in a variable then when the value increases to 1 then it allowed the level to change.
How do I fix my scripts?
Coin script:
using UnityEngine;
using System.Collections;
public class Coin : MonoBehaviour {
public GameObject destroyCoin;
public static int coinWorth = 0;
void OnCollisionEnter(Collision other)
{
if (other.transform.tag == "Coin")
{
Destroy(destroyCoin);
coinWorth = 1;
}
}
}
GameManager script:
using UnityEngine;
using System.Collections;
public class GameManager4 : MonoBehaviour {
Coin coinValue = GetComponent<Coin>().coinWorth;
void Update ()
{
coinValue = Coin.coinWorth;
}
void OnCollisionEnter(Collision other){
if (other.transform.tag == "Complete" && coinValue > 0) {
Application.LoadLevel(1);
}
}
}
It might be simpler to have the Coin send its value directly to the GameManager upon collision.
Should your coin perhaps be searching for a 'Player' tag rather than a 'Coin' tag (I am assuming that the Coin.cs script will be attached to a coin object which will have the 'Coin' tag).
So in you scripts it would look like this:
using UnityEngine;
using System.Collections;
public class Coin : MonoBehaviour {
// Drag your Game Manager object into this slot in the inspector
public GameObject GameManager;
public static int coinWorth = 1;
void OnCollisionEnter(Collision other)
{
// If the coin is collided into by an object tagged 'player'
if (other.transform.tag == "Player")
{
// retrieve the gamemanager component from the game manager object and increment its value
GameManager.GetComponent<GameManager4>().coinValue++;
// Destroy this instance of the coin
Destroy(gameObject);
}
}
}
Then your second script
using UnityEngine;
using System.Collections;
public class GameManager4 : MonoBehaviour {
// Declare the coinValue as a public int so that it can be accessed from the coin script directly
public int coinValue = 0;
void Update ()
{
// This shouldn't be necessary to check on each update cycle
//coinValue = Coin.coinWorth;
}
void OnCollisionEnter(Collision other){
if (other.transform.tag == "Complete" && coinValue > 0) {
Application.LoadLevel(1);
}
}
}
Of course if you are instancing the coin from a prefab then you would need to do this differently as you wouldn't be able to drag the game menager in the inspector. If thats the case then it might be worthwhile to use a singleton class for the game manager. Let me know if that is the case and I'll show you how to do this :)

Categories