I have a "Player" gameObject that spawn OnServerInitialized().
It's tag "Enemy" change to "Player" when GetComponent<NetworkView>().isMine.
I'd like to make something like:
void OnTriggerEnter (Collider Enemy){
if (ScoreManager.score > Enemy.Score) {
ScoreManager.score = ScoreManager.score + Enemy.Score;
}
else if (ScoreManager.score < Enemy.Score) {
Destroy (gameObject);
}
}
But I don't know how to access to spawned enemy player's points.
My ScoreManager Script:
public static int score;
Text text;
void Awake () {
text = GetComponent <Text> ();
score = 0;
}
void Update () {
text.text = "Score: " + score;
}
}
It is attached to GUI text gameObject named ScoreText.
1)when you're using GetComponent always check for null.
2)Don't use GetComponent. Serialize the variable (or make it public) by addding [System.Serializable] above Text text; and drag and drop in the inspector, the text component.
3)You don't have to refresh the score every frame, only when it changes. This should be done using events.
In order to access the enemy's points, you can use GameObject.FindWithTag, and use the "Enemy" provided that the enemy has this tag. You can get a reference to the enemy game object that way. Then access its score component.
For example:
ScoreManager enemyScoreManager = null;
GameObject enemyReference = GameObject.FindWithTag("Enemy");
if (enemyReference !=null)
enemyScoreManager = enemyReference.GetComponent<ScoreManager>();
if (enemyScoreManager != null)
{
enemyScoreManager.score -=5; //steal 5 points
myScore.score +=5; //assuming myScore is a reference to your score manager
}
else
Debug.LogError("Enemy not found");
Related
I am working on a simple game where the goal is to help a Player catch specific objects with a tag "Present".
After taking care of the models, animations I am now working on the collisions and counting UI.
For the collisions, on my Player Controller (I am using the ThirdPersonUserController from the player Unity Standard Assets - which simplified the whole animation process), I added the following functions:
void OnCollisionEnter(Collision other)
{
if (other.gameObject.tag == "Present")
{
Destroy(gameObject);
count = count - 1;
SetCountText();
}
}
void SetCountText()
{
countText.text = "Count: " + count.ToString();
if (count == 0)
{
winText.text = "Thanks to you the Christmas will be memorable!";
}
}
However, like this, when the Player hits an object with the tag "Present", even though the counting is working properly, the player disappears.
I have tried to change the OnCollisionEnter to an OnTriggerEnter, like this:
void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("Present"))
{
Destroy(gameObject);
count = count - 1;
SetCountText();
}
}
However when the Player hits the objects with the tag "Present", they don't disappear.
My Player has a Capsule Collider and a Rigidbody.
The objects with the tag "Present" have a Box Collider and a Rigidbody.
Any guidance on how to make my Player stay in scene while removing the other objetcs and reducing the count is appreciated.
Few things. You are destroying the incorrect game object:
void OnCollisionEnter(Collision other)
{
if (other.gameObject.tag == "Present")
{
Destroy(gameObject); // this is destroying the current gameobject i.e. the player
count = count - 1;
SetCountText();
}
}
Update to:
void OnCollisionEnter(Collision other)
{
if (other.gameObject.CompareTag("Present"))
{
Destroy(other.gameObject); // this is destroying the other gameobject
count = count - 1;
SetCountText();
}
}
Always use CompareTag() which is optimized for performance.
Setting the Collider IsTrigger property will then make use of the OnTriggerEnter events and not the OnCollisionEnter anymore.
On the first physics update where the collision is detected, the
OnCollisionEnter function is called. During updates where contact is
maintained, OnCollisionStay is called and finally, OnCollisionExit
indicates that contact has been broken. Trigger colliders call the
analogous OnTriggerEnter, OnTriggerStay and OnTriggerExit functions.
See the docs
Your present object is using a non-trigger collider, so you should use OnCollisionEnter. The CompareTag call you tried in OnTriggerEnter is preferable. You should use that.
Also, you are currently trying to destroy the gameobject that the ThirdPersonUserController is attached to (gameObject). Instead, destroy the gameobject of the colliding collider (other.gameObject) with Destroy(other.gameObject);:
void OnCollisionEnter(Collision other)
{
if (other.gameObject.CompareTag("Present"))
{
Destroy(other.gameObject);
count = count - 1;
SetCountText();
}
}
I've searched around and I just can't get this to work. I think I just don't know the proper syntax, or just doesn't quite grasp the context.
I have a BombDrop script that holds a public int. I got this to work with public static, but Someone said that that is a really bad programming habit and that I should learn encapsulation. Here is what I wrote:
BombDrop script:
<!-- language: c# -->
public class BombDrop : MonoBehaviour {
public GameObject BombPrefab;
//Bombs that the player can drop
public int maxBombs = 1;
// Update is called once per frame
void Update () {
if (Input.GetKeyDown(KeyCode.Space)){
if(maxBombs > 0){
DropBomb();
//telling in console current bombs
Debug.Log("maxBombs = " + maxBombs);
}
}
}
void DropBomb(){
// remove one bomb from the current maxBombs
maxBombs -= 1;
// spawn bomb prefab
Vector2 pos = transform.position;
pos.x = Mathf.Round(pos.x);
pos.y = Mathf.Round(pos.y);
Instantiate(BombPrefab, pos, Quaternion.identity);
}
}
So I want the Bomb script that's attached to the prefabgameobject Bombprefab to access the maxBombs integer in BombDrop, so that when the bomb is destroyed it adds + one to maxBombs in BombDrop.
And this is the Bomb script that needs the reference.
public class Bomb : MonoBehaviour {
// Time after which the bomb explodes
float time = 3.0f;
// Explosion Prefab
public GameObject explosion;
BoxCollider2D collider;
private BombDrop BombDropScript;
void Awake (){
BombDropScript = GetComponent<BombDrop> ();
}
void Start () {
collider = gameObject.GetComponent<BoxCollider2D> ();
// Call the Explode function after a few seconds
Invoke("Explode", time);
}
void OnTriggerExit2D(Collider2D other){
collider.isTrigger = false;
}
void Explode() {
// Remove Bomb from game
Destroy(gameObject);
// When bomb is destroyed add 1 to the max
// number of bombs you can drop simultaneously .
BombDropScript.maxBombs += 1;
// Spawn Explosion
Instantiate(explosion,
transform.position,
Quaternion.identity);
In the documentation it says that it should be something like
BombDropScript = otherGameObject.GetComponent<BombDrop>();
But that doesn't work. Maybe I just don't understand the syntax here. Is it suppose to say otherGameObject? Cause that doesn't do anything. I still get the error : "Object reference not set do an instance of an object" on my BombDropScript.maxBombs down in the explode()
You need to find the GameObject that contains the script Component that you plan to get a reference to. Make sure the GameObject is already in the scene, or Find will return null.
GameObject g = GameObject.Find("GameObject Name");
Then you can grab the script:
BombDrop bScript = g.GetComponent<BombDrop>();
Then you can access the variables and functions of the Script.
bScript.foo();
I just realized that I answered a very similar question the other day, check here:
Don't know how to get enemy's health
I'll expand a bit on your question since I already answered it.
What your code is doing is saying "Look within my GameObject for a BombDropScript, most of the time the script won't be attached to the same GameObject.
Also use a setter and getter for maxBombs.
public class BombDrop : MonoBehaviour
{
public void setMaxBombs(int amount)
{
maxBombs += amount;
}
public int getMaxBombs()
{
return maxBombs;
}
}
use it in start instead of awake and dont use Destroy(gameObject); you are destroying your game Object then you want something from it
void Start () {
BombDropScript =gameObject.GetComponent<BombDrop> ();
collider = gameObject.GetComponent<BoxCollider2D> ();
// Call the Explode function after a few seconds
Invoke("Explode", time);
}
void Explode() {
//..
//..
//at last
Destroy(gameObject);
}
if you want to access a script in another gameObject you should assign the game object via inspector and access it like that
public gameObject another;
void Start () {
BombDropScript =another.GetComponent<BombDrop> ();
}
Can Use this :
entBombDropScript.maxBombs += 1;
Before :
Destroy(gameObject);
I just want to say that you can increase the maxBombs value before Destroying the game object. it is necessary because, if you destroy game object first and then increases the value so at that time the reference of your script BombDropScript will be gone and you can not modify the value's in it.
I'm pretty new to Unity and I've had a look around for similar problems, but I suck at transferring it over into my program.
Anyway, I basically have a class called Scoring that will keep track of how many enemies there are on the level. I want to pass this value into another class called Bullet_explosive. In this class, it will remove one from that total when an enemy has been hit with the bullet. After it has removed one from the total, I want this value to be passed back into Scoring so that it can be displayed on the screen to the player.
Probably been answered a million times, but I'm sick of not knowing how to implement it into my own program.
Thanks in advance.
Here's the Scoring class:
public class Scoring : MonoBehaviour {
// Create gameobject to store the text object within
public GameObject textObject;
// Holds the text displayed on screen
Text actualText;
// Holds the remaining number of enemies
public static int enemiesRemaining = 12;
// Use this for initialization
void Start ()
{
// Stores the gameobject called EnemiesRemaining
textObject = GameObject.Find ("EnemiesRemaining");
// Gets the text component of that gameobject
actualText = textObject.GetComponent<Text> ();
// Stores what text the display will actually show
actualText.text = "Enemies Remaining: " + enemiesRemaining;
}
// Update is called once per frame
void Update ()
{
// Updates the display
actualText.text = "Enemies Remaining: " + enemiesRemaining;
}
Here's the Bullet_explosive class:
public class Bullet_explosive : MonoBehaviour {
// Lifespan of the bullet
float lifespan = 1.5f;
// Setting up game objects
public GameObject fireEffect;
public GameObject explosion;
public GameObject theGate;
//Passing through the enemies remaining
private static int score;
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
score = Scoring.enemiesRemaining;
lifespan -= Time.deltaTime;
// Once the lifespan reaches 0, bullet is destroyed
if (lifespan <= 0)
{
Explode ();
}
}
void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.tag == "Enemy")
{
// Reduces the remaining enemies
score -= 1;
// Checks for no remaining enemies
if (score <= 0)
{
// Removes the gate
Destroy(GameObject.FindWithTag ("Gate"));
}
// Changes the tag of the target hit
collision.gameObject.tag = "Untagged";
// Applies visual effects at the position and rotation of the target
Instantiate (fireEffect, collision.transform.position, Quaternion.identity);
Instantiate (explosion, collision.transform.position, Quaternion.identity);
// Removes bullet and target
Explode();
Destroy (collision.gameObject);
}
}
void Explode()
{
Destroy (gameObject);
}
I find it to be too much effort to have two static fields that mean exactly the same thing. You should only make one field for that and always refer to that same field in the Scoring class.
public class Bullet_explosive : MonoBehaviour {
// Lifespan of the bullet
float lifespan = 1.5f;
// Setting up game objects
public GameObject fireEffect;
public GameObject explosion;
public GameObject theGate;
// Use this for initialization
void Start () { }
// Update is called once per frame
void Update ()
{
/* no "score" updating needed here in Update() */
lifespan -= Time.deltaTime;
// Once the lifespan reaches 0, bullet is destroyed
if (lifespan <= 0)
{
Explode ();
}
}
void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.tag == "Enemy")
{
// Reduces the remaining enemies
//Directly modify that one static field
Scoring.enemiesRemaining -= 1;
// Checks for no remaining enemies
if (Scoring.enemiesRemaining <= 0) //here too
{
// Removes the gate
Destroy(GameObject.FindWithTag ("Gate"));
}
// Changes the tag of the target hit
collision.gameObject.tag = "Untagged";
// Applies visual effects at the position and rotation of the target
Instantiate (fireEffect, collision.transform.position, Quaternion.identity);
Instantiate (explosion, collision.transform.position, Quaternion.identity);
// Removes bullet and target
Explode();
Destroy (collision.gameObject);
}
}
void Explode()
{
Destroy (gameObject);
}
And that should be it.
Hey guys I am getting this error as i mentioned in the title Ive been trying to debug since last night and finally got down to this one error left i cant seem to beat. here is the code please have a look if you get the chance the error is saying its on line (107,16) and sorry for the link i just joined here don't know how to put it in code.
using UnityEngine;
using System.Collections;
using UnityEngine.UI; //Allows us to use UI.
namespace Completed
{
public class Player
{
public float restartLevelDelay = 1f;
public int pointsPerFood = 10;
public int pointsPerSoda = 20;
public int wallDamage = 1;
public Text foodText;
public AudioClip moveSound1;
public AudioClip moveSound2;
public AudioClip eatSound1;
public AudioClip eatSound2;
public AudioClip drinkSound1;
public AudioClip drinkSound2;
public AudioClip gameOverSound;
private Animator animator;
private int food;
private Vector2 touchOrigin = -Vector2.one;
//Start overrides the Start function of MovingObject
protected override void Start ()
{
//Get a component reference to the Player's animator component
animator = GetComponent<Animator>();
//Get the current food point total stored in GameManager.instance between levels.
food = GameManager.instance.playerFoodPoints;
//Set the foodText to reflect the current player food total.
foodText.text = "Food: " + food;
//Call the Start function of the MovingObject base class.
base.Start ();
}
//This function is called when the behaviour becomes disabled or inactive.
private void OnDisable ()
{
GameManager.instance.playerFoodPoints = food;
}
private void Update ()
{
//If it's not the player's turn, exit the function.
if(!GameManager.instance.playersTurn) return;
int horizontal = 0; //Used to store the horizontal move direction.
int vertical = 0; //Used to store the vertical move direction.
//Check if we have a non-zero value for horizontal or vertical
if(horizontal != 0 || vertical != 0)
{
AttemptMove<Wall> (horizontal, vertical);
}
}
protected override void AttemptMove <T> (int xDir, int yDir)
{
//Every time player moves, subtract from food points total.
food--;
//Update food text display to reflect current score.
foodText.text = "Food: " + food;
//Call the AttemptMove method of the base class, passing in the component T (in this case Wall) and x and y direction to move.
base.AttemptMove <T> (xDir, yDir);
//Hit allows us to reference the result of the Linecast done in Move.
RaycastHit2D hit;
//If Move returns true, meaning Player was able to move into an empty space.
if (Move (xDir, yDir, out hit))
{
//Call RandomizeSfx of SoundManager to play the move sound, passing in two audio clips to choose from.
SoundManager.instance.RandomizeSfx (moveSound1, moveSound2);
}
{
//Since the player has moved and lost food points, check if the game has ended.
CheckIfGameOver ();
//Set the playersTurn boolean of GameManager to false now that players turn is over.
GameManager.instance.playersTurn = false;
}
//OnCantMove overrides the abstract function OnCantMove in MovingObject.
//It takes a generic parameter T which in the case of Player is a Wall which the player can attack and destroy.
public override void OnCantMove <T> (T component)
{
//Set hitWall to equal the component passed in as a parameter.
Wall hitWall = component as Wall;
//Call the DamageWall function of the Wall we are hitting.
hitWall.DamageWall (wallDamage);
//Set the attack trigger of the player's animation controller in order to play the player's attack animation.
animator.SetTrigger ("playerChop");
}
//OnTriggerEnter2D is sent when another object enters a trigger collider attached to this object (2D physics only).
private void OnTriggerEnter2D (Collider2D other)
{
//Check if the tag of the trigger collided with is Exit.
if(other.tag == "Exit")
{
//Invoke the Restart function to start the next level with a delay of restartLevelDelay (default 1 second).
Invoke ("Restart", restartLevelDelay);
//Disable the player object since level is over.
enabled = false;
}
//Check if the tag of the trigger collided with is Food.
else if(other.tag == "Food")
{
//Add pointsPerFood to the players current food total.
food += pointsPerFood;
//Update foodText to represent current total and notify player that they gained points
foodText.text = "+" + pointsPerFood + " Food: " + food; //nothing
//Call the RandomizeSfx function of SoundManager and pass in two eating sounds to choose between to play the eating sound effect.
SoundManager.instance.RandomizeSfx (eatSound1, eatSound2);
//Disable the food object the player collided with.
other.gameObject.SetActive (false);
}
//Check if the tag of the trigger collided with is Soda.
else if(other.tag == "Soda")
{
//Add pointsPerSoda to players food points total
food += pointsPerSoda;
//Update foodText to represent current total and notify player that they gained points
foodText.text = "+" + pointsPerSoda + " Food: " + food;
//Call the RandomizeSfx function of SoundManager and pass in two drinking sounds to choose between to play the drinking sound effect.
SoundManager.instance.RandomizeSfx (drinkSound1, drinkSound2);
//Disable the soda object the player collided with.
other.gameObject.SetActive (false);
}
}
//Restart reloads the scene when called.
private void Restart ()
{
//Load the last scene loaded, in this case Main, the only scene in the game.
Application.LoadLevel (Application.loadedLevel);
}
//LoseFood is called when an enemy attacks the player.
//It takes a parameter loss which specifies how many points to lose.
public void LoseFood (int loss)
{
//Set the trigger for the player animator to transition to the playerHit animation.
animator.SetTrigger ("playerHit");
//Subtract lost food points from the players total.
food -= loss;
//Update the food display with the new total.
foodText.text = "-" + loss + " Food: " + food;
//Check to see if game has ended.
CheckIfGameOver ();
}
//CheckIfGameOver checks if the player is out of food points and if so, ends the game.
private void CheckIfGameOver ()
{
//Check if food point total is less than or equal to zero.
if (food <= 0)
{
//Call the PlaySingle function of SoundManager and pass it the gameOverSound as the audio clip to play.
SoundManager.instance.PlaySingle (gameOverSound);
//Stop the background music.
SoundManager.instance.musicSource.Stop();
//Call the GameOver function of GameManager.
GameManager.instance.GameOver ();
}
}
}
}
In the function protected override void AttemptMove , remove the open {
// ... previous code ...
if (Move (xDir, yDir, out hit))
{
//Call RandomizeSfx of SoundManager to play the move sound, passing in two audio clips to choose from.
SoundManager.instance.RandomizeSfx (moveSound1, moveSound2);
}
// { REMOVE THIS ONE!
//Since the player has moved and lost food points, check if the game has ended.
CheckIfGameOver ();
//Set the playersTurn boolean of GameManager to false now that players turn is over.
GameManager.instance.playersTurn = false;
I'm having a bit of trouble getting the Vector3 wayPointPosition to my other script called Walking and changing it into the Transform target. My troubles lie in the fact that I'm trying to grab this dynamic variable from WayPointPositioner (it changes depending on what object is clicked in the stage and whether the player overlaps with this waypoint) and import and use it in another script.
Below is the code I'm using.
WayPointPositioner
using UnityEngine;
using System.Collections;
public class WayPointPositioner : MonoBehaviour {
public Vector3 wayPointPosition = Vector3.zero;
private bool checkPlayerWaypointCollision;
void Start()
{
}
void OnTriggerStay2D (Collider2D other)
{
// Check if collision is occuring with player character.
if (other.gameObject.name == "Player")
{
checkPlayerWaypointCollision = true;
}
else
{
checkPlayerWaypointCollision = false;
}
}
//Check if object is clicked
void OnMouseDown ()
{
// If its the player, then return a new position for the player to move to for walking
// Else debug that its not so
if (checkPlayerWaypointCollision == false)
{
Debug.Log ("Object not colliding and retrieving position");
Debug.Log (wayPointPosition);
Debug.Log (gameObject.name);
wayPointPosition = new Vector3 (transform.position.x, transform.position.y, 10);
wayPointPosition = Camera.main.ScreenToWorldPoint(wayPointPosition);
}
else
{
Debug.Log ("Object is colliding, no movement needed");
}
}
}
Walking
using UnityEngine;
using System.Collections;
public class Walking : MonoBehaviour {
public Transform target;
public WayPointPositioner wayPointPosition;
public bool walkingAnimation = false;
private Animator anim;
void Awake ()
{
anim = GetComponent<Animator> ();
wayPointPosition = GameObject.FindGameObjectWithTag ("Waypoint").GetComponent<WayPointPositioner> ();
}
void Start ()
{
}
void Update ()
{
Debug.Log ("This is in Walking, WPP =" + wayPointPosition);
}
}
As you can see I'm trying to import the wayPointPosition from the seperate class which is attached to the gameobjects called "Waypoint" (In my current layout those are empty objects with circle colliders to check if they have been clicked). However when I run this, I am not getting my Vector, but I'm getting the name of the last waypoint in the hierarchy (I have currently 6 waypoints which can be clicked) and not a Vector.
I hope someone is able to help me / point out my mistake. I'm still learning C# so I might've made a strange / odd assumption which isn't working.
Kind regards,
Veraduxxz.
It looks like invoking GameObject.FindGameObjectWithTag("Waypoint").GetComponent<WayPointPositioner>(); retrieves a component from the game object which matches the specified tag, as well as a type argument T which derives from MonoBehavior.
Calling this should actually give you an instance of your WayPointPositioner class, which you can then pass to whichever methods you want, and interact with its Vector3 however you would like.