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 :)
Related
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
I have created a game where when the user breaks all the blocks he is taken to the next scene but this is not happening despite adding all of the scenes I have in the build settings. I have no errors whatsoever and the scene is written correctly. Can someone help me resolve this, please?
This is the build settings
Bricks script : (where the scene is called)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bricks : MonoBehaviour {
public LevelManager myLevelManager;
public static int brickCount = 0;
public int maxNumberOfHits = 0;
int timesHit;
public AudioClip BlockBreaking;
// Use this for initialization
void Start () {
timesHit = 0;
if(this.gameObject.tag == "BrickHit")
{
brickCount++;
}
if(this.gameObject.tag == "BrickHitTwice")
{
brickCount++;
}
}
void OnCollisionEnter2D()
{
timesHit++;
if (timesHit == maxNumberOfHits)
{
brickCount--;
Destroy(this.gameObject);
}
if(brickCount == 0)
{
myLevelManager.LoadLevel("Level1.2"); //THIS SCENE IS NOT LOADING
}
if(this.gameObject.tag == "BrickHit") //If the gameObject (Block One Point) with the tag "BrickHit" is hit
{
Scores.scoreValue += 1;//The user will be rewarded 1 point
AudioSource.PlayClipAtPoint(BlockBreaking, transform.position);
}
if(this.gameObject.tag == "BrickHitTwice") //If the gameObject (Block Two Points) with the tag "BrickHitTwice" is hit
{
Scores.scoreValue += 2; //The user will be rewarded 2 points
AudioSource.PlayClipAtPoint(BlockBreaking, transform.position);
}
}
LevelManager Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class LevelManager : MonoBehaviour {
public void LoadLevel(string name)
{
print("Level loading requested for" + name);
SceneManager.LoadScene(name);
}
I suspect that your bug may lie in the fact that you're Destroy()ing the gameObject before it can load the next scene; you get a race condition on what will finish first; LoadScene or Destroy() - which would explain why it sometimes work. You should never assume it is a bug in the framework before understanding your problem.
Try putting the Destroy() after the LoadScene() or with a delay to understand if this is your issue.
Also, your LevelManager can be made static and doesn't need to inherit from MonoBehaviour since it doesn't use gameObject functionality.
public static class LevelManager {
public static void LoadLevel(string name)
{
print("Level loading requested for" + name);
SceneManager.LoadScene(name);
}
}
Used by doing LevelManager.LoadLevel("MyLevel");, but then you may question what is more effective, doing LevelManager.LoadLevel or SceneManager.LoadLevel, as they will do the exact same thing.
The main issue that you're having is not having a single source to check brickCount instead each individual brick is maintaining its own count. I would recommend moving the brick counting logic into a separate class. It would seem like LevelManager would a good place for it. So in LevelManager add:
private int brickCount = 0;
public void AddBrick()
{
brickCount++;
}
public void RemoveBrick()
{
brickCount--;
// Check if all bricks are destroyed
if (brickCount == 0)
{
LoadLevel("Level1.2");
}
}
And then in your brick script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bricks : MonoBehaviour {
public LevelManager myLevelManager;
public int maxNumberOfHits = 0;
int timesHit;
public AudioClip BlockBreaking;
// Use this for initialization
void Start () {
timesHit = 0;
myLevelManager.AddBrick();
// I'm not sure why you were checking the tag here, since the result was the same
}
void OnCollisionEnter2D()
{
timesHit++;
if (timesHit == maxNumberOfHits)
{
myLevelManager.RemoveBrick();
Destroy(this.gameObject);
}
/* This looks like the player is getting score whether the brick is destroyed or not. Also, it would appear the player won't get scored on the final brick */
if(this.gameObject.tag == "BrickHit") //If the gameObject (Block One Point) with the tag "BrickHit" is hit
{
Scores.scoreValue += 1;//The user will be rewarded 1 point
AudioSource.PlayClipAtPoint(BlockBreaking, transform.position);
}
if(this.gameObject.tag == "BrickHitTwice") //If the gameObject (Block Two Points) with the tag "BrickHitTwice" is hit
{
Scores.scoreValue += 2; //The user will be rewarded 2 points
AudioSource.PlayClipAtPoint(BlockBreaking, transform.position);
}
}
}
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
I writing simple game on Unity (C#)
I have player and want to make the destroyer, that will destroy player.
I create prefab of destroyer. And next, I create Quad.
I have spawn script:
using UnityEngine;
using System.Collections;
public class SpawnScript : MonoBehaviour {
public GameObject[] obj;
public float spawnMin = 1f;
public float spawnMax = 2f;
// Use this for initialization
void Start () {
Spawn();
}
void Spawn()
{
Instantiate(obj[Random.Range(0, obj.GetLength(0))], transform.position, Quaternion.identity);
Invoke("Spawn", Random.Range(spawnMin, spawnMax));
}
}
Also I write DestroyerScript:
using UnityEngine;
using System.Collections;
public class DestroyerScript : MonoBehaviour {
void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Player")
{
Application.LoadLevel(1);
return;
}
if (other.gameObject.transform.parent)
{
Destroy(other.gameObject.transform.parent.gameObject);
}
else
{
Destroy(other.gameObject);
}
}
}
My destroyer spawning, but when player get it, I don't have Game Over screen.
Add rigid body to both player and "player destroyer" and then set onTriggerEnter on your player destroyer like so:
void OnTriggerEnter(Collider other) {
Destroy(other.gameObject);
}
For some fine tuning, you can do some checks if the other object is in fact the Destroyer (you can compare the tag or something, I won't go into too much detail now).
EDIT: Uncheck "isTrigger" on your BoxColliders and try this:
void OnCollisionEnter (Collision col)
{
Destroy(col.gameObject);
}
Here is the player health script... It set's the players health from within Unity, and pushes it onto the GUI.
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class PlayerHealth : MonoBehaviour
{
public Text hpText; //HP Value Text Element.
public int PlayerHP; // Make it a property so you can alter its value in the editor
void Start()
{
SetHPText ();
}
void Update ()
{
SetHPText ();
}
void SetHPText ()
{
hpText.text = "Health: " + PlayerHP.ToString();
}
}
Then this one takes the grabs the players current health (and keeps it updated). If the players health is 0 (or lower) it loads a new scene. The problem is the tag tag check for the player, and apply damage aren't working.
using UnityEngine;
using UnityEngine.SceneManagement;
using System.Collections;
public class DamageAuroa : MonoBehaviour {
public int PHP; //PHP = Player Health from PlayerHealth.cs script.
public int Damage; //Amount of damage.
public string Level;
void Update()
{
PHP = GameObject.Find("Player").GetComponent<PlayerHealth>().PlayerHP;
}
void OnTriggerEnter(Collider coll)
{
if (coll.gameObject.tag == "Player")
PHP = PHP - Damage;
if (coll.gameObject.tag == "Ball")
{
gameObject.SetActive(false);
SceneManager.LoadScene(Level);
}
if (PHP <= 0)
SceneManager.LoadScene(Level);
}
}
The weirdest part ALL OF THIS was working prior to me updating Unity (I know newbie mistake). Anyone see what's the matter? Before anyone asks yes the triggers, and tags are set up properly. Also I realize I have to pass the updated HP value to the player health script for it to update on the GUI. Just trying to get these triggers working.
Following code doesn't work because you are creating new variable PHP that equals to player HP (but doesn't reference to it, because int is a value type, not a reference type) and when you change PHP it changes only this variable, not PlayerHP from PlayerHealth script.
void Update()
{
PHP = GameObject.Find("Player").GetComponent<PlayerHealth>().PlayerHP;
}
void OnTriggerEnter(Collider coll)
{
if (coll.gameObject.tag == "Player")
PHP = PHP - Damage;
....
}
If you want to change PlayerHealth you should change it directly from PlayerHealth script instance.
if (coll.gameObject.tag == "Player")
GameObject.Find("Player").GetComponent<PlayerHealth>().PlayerHP= PHP - Damage;
Or you can create an reference type variable references to PlayerHealth script.
public class DamageAuroa : MonoBehaviour {
PlayerHealth player;
void Start ()
{
player = GameObject.Find("Player").GetComponent<PlayerHealth>();
}
...
And then use this object to set players hp.
if (coll.gameObject.tag == "Player")
player.PlayerHP = player.PlayerHP- Damage;
Aye well I am not sure if this will work because i am not as advanced my self, but try using coll.tag, because the collier class has a tag variable it self.