Trigger not working properly with GetComponent. What is wrong? - c#

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.

Related

How can I make it so that the player loses health when an enemy collides with a different object?

Here an image of what my game looks like so far so that you can get a better idea but I need it so that when one of the outer capsules touches the red box the player (middle capsule) loses health.
I have tried creating a new script which checks for collisions but I couldn't get it to work and am unsure where to go from here. Below is my code for how the health bar works and pressing the space bar reduces health for demonstration purposes.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PlayerHealth : MonoBehaviour
{
public float MaxHealth;
public Slider _slide;
private float currentHealth;
void Start()
{
currentHealth = MaxHealth;
_slide.maxValue = MaxHealth;
_slide.value = MaxHealth;
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
TakeDamage(25f);
if(currentHealth <=0)
{
//move to game over
}
}
void TakeDamage(float Damage)
{
currentHealth = currentHealth - Damage;
_slide.value = currentHealth;
}
}
At one point I tried using
void Update()
{
(collision.collider.name == "Barrier");
TakeDamage(25f);
if(currentHealth <=0)
{
//move to game over
}
}
but realised this is completely wrong, as well as trying to add a box collider to the red "barrier" to aid this but it didn't fix anything.
Update 2:
Also tried changing it so that the enemies move towards the barrier and not the player and added the code:
private void OnTriggerEnter(Collider other) {
TakeDamage(25f);
if(currentHealth <=0)
{
//move to game over
}
}
which doesn't present any errors but rather just doesn't do anything. The enemy capsules just go through it and to the centre, with no health being lost.
You need to check for collisions using OnCollisionEnter3D and then use the TakeDamage function inside of it. Here is an example:
public class PlayerHealth: MonoBehaviour
{
void OnCollisionEnter3D(Collision3D col) //Check for collision
{
TakeDamage(25f);
}
}
Note that for this function to work, both objects need a 3d collider and a rigid body. If you don't want your character to fall, just set gravity to 0.

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

OnTriggerEnter2D (Collider2D other) ... accessing mutiple outside script functions

So I have this script that affects another script just fine. It's attached to a gameobject (an attack box) that damages another gameobject (an enemy). It makes the enemy GameObject perform an animation (it getting hurt) and takes away a certain amount of health. That's all working fine.
What I'm stuck on is that I'm trying to get it to do the same for more than one type of enemy, therefore, accessing multiple scripts. The scripts are relatively the same and i've tested those out individually and both work fine. But when I try to have my attack box the script is attached to, affect more than one script, I get nothing. I figure it's just the way it's typed out and I've tried several ways already. But I've reverted it back to its most simple form to display it here. How do I get this script to work for both, so I don't have to have multiple scripts attached to one hitbox?
I should mention that in this script, it does access the first script mentioned in the OnTriggerEnter2D function. It just doesn't do it for any other scripts mentioned afterwards.
using UnityEngine;
using System.Collections;
public class slicer : MonoBehaviour {
public int damage = 5;
private foeHP foe;
private goblin gobby;
public float timer;
void Update()
{
Destroy ();
timer -= Time.deltaTime;
}
public void OnTriggerEnter2D (Collider2D other)
{
if (other.gameObject.tag == "Enemy") {
other.gameObject.GetComponent<foeHP> ().takeDamage (damage);
var foe = other.GetComponent<foeHP> ();
other.gameObject.GetComponent<goblin> ().takeDamage (damage);
var gobby = other.GetComponent<goblin> ();
}
if (foe == null) {
return;
}
if (gobby == null) {
return;
}
}
public void Destroy(){
if (timer <=0)
Destroy(gameObject);
}
}
Declare a generic Enemy class that all enemy types derive from.
public class Enemy : MonoBehaviour
{
int health;
public void TakeDamage(int amount)
{
health -= amount;
}
}
Change your enemy classes such that they all derive from Enemy
public class Goblin : Enemy
{
// Extra fields/methods
}
public class Foe : Enemy
{
// Extra fields/methods
}
Now you can simplify your checks into:
public void OnTriggerEnter2D (Collider2D other)
{
if (other.gameObject.tag == "Enemy")
{
other.GetComponent<Enemy>().TakeDamage(5);
}
}
Since both Goblin and Foe are type Enemy, GetComponent<Enemy>() will return their respective derived type and you can call TakeDamage() on them.

Unity Collision Detection - Adding GUI Score on Collision?

I am making a pinball game in Unity, and I have an issue. When the pinball collides with a cylinder to add points to the score, it does not work. I have tagged the cylinders in Unity and have attached this script to the pinball. It doesn't even show up in the debug log.
Thanks for any advice.
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class Score : MonoBehaviour {
public int scorePoint = 10;
public int MaxScore;
public Text ScoreText;
// Use this for initialization
void Start () {
ScoreText = GetComponent<Text>();
ScoreText.text = "Score: " + scorePoint;
}
void OnTriggerEnter (Collider other)
{
if (other.gameObject.tag == "Cylinder")
{
Debug.Log("Collision detected");
scorePoint+=10;
}
}
// Update is called once per frame
void Update()
{
}
}
Make sure you have a box collider on each object. OnTriggerEnter is only called when two box collider hit each other. This is the most likely culprit of why its not working but without more information I can't guarantee it.

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