How to edit variables in another game object.(Unity C#) [duplicate] - c#

This question already has answers here:
Accessing a variable from another script C# [duplicate]
(3 answers)
Closed 4 years ago.
Do keep in mind that I am not good at Unity.
I have a Game Object with a variable called hp. I have another Game Object with a trigger collider. When the trigger runs, I want it to edit the variable hp but I don't know how to edit variables from another game object.
Please may I have some help.

In Unity, the OnTriggerEnter(Collider other) function is called when a collision is triggered.
In argument of the function, you get a collider named other, which is a reference to the collider script your object collided with. As any script in unity, you can call other.gameObject to retrieve the colliding gameObject. From then, you can use the GetComponent function to find a script on the object.
In your case, lets say you have an object on which you put this script:
public class Player : MonoBehaviour {
public float hp;
}
You need to create another script that handles the collision. Put this on the object that collides with your player
public class Obstacle : MonoBehaviour
{
public float damages;
private void OnTriggerEnter(Collider other)
{
if(!other.gameObject.HasComponent<Player>())
return;
var player = other.gameObject.GetComponent<Player>();
player.hp -= damages;
}
}

Related

Unity c# how to properly use GetComponent [duplicate]

This question already has answers here:
How to access a variable from another script in another gameobject through GetComponent?
(3 answers)
Closed 25 days ago.
I am in no way a coding novice but I just picked up unity and I'm trying "get it"
My question involves this code. it is not part of an active project. it is simply an attempt to understand the system
private SpriteRenderer beans2;
public Sprite beanimmage;
// Start is called before the first frame update
void Start()
{
beans2 = gameObject.GetComponent<SpriteRenderer>();
beans2.sprite = beanimmage;
}
from what I understand this code allows me to manipulate the SpriteRenderer of the game object this code is attached to by assigning it to beans2 and then changing the Sprite of beans2 to beanimmage and works fine in the system
My question is -
Is their a way to assign beans2 to the spriterenderer of a diffident game object? The object i have this code attached to is just a game object called test is their a way to assign the beans2 variable to the SpriteRenderer of my test2 object instead ?
something like this ?
beans2 = test2.gameObject.GetComponent<SpriteRenderer>();
beans2 = gameObject.test2.GetComponent<SpriteRenderer>();
The GetComponent() Function is apart of every gameobject so to get components on other gameobjects you need to reference that gameobject in a variable, something like this:
public GameObject test2;
private SpriteRenderer test2Renderer;
public Sprite beanImage;
void Awake()
{
test2Renderer = test2.GetComponent<SpriteRenderer>();
test2Renderer.sprite = beanImage;
}
Alternatively, you can just get the component of the test2 object from the inspector because you are using public variables. To do this make a sprite renderer variable field and make it public so it is shown in the inspector, then drag the test2 object into the field and it will automatically get the sprite renderer component off that object.
Finally, you could also just do this with one field. This method would be used when you only want to access the GameObject and nothing else:
public GameObject test2;
public Sprite beansImage;
void Awake
{
test2.GetComponent<SpriteRenderer>().sprite = beansImage;
}
Any way works and you should do it the second way if you want to work with public variables and rely on the inspector but if you only need the gameobject then go with method 3. Method 1 is probably the best way to do it so you can change the sprite later if you want.

How do you create a default player for an enemy AI script in Unity? [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
In Unity (C#), why am I getting a NullReferenceException and how do I fix it? [duplicate]
(1 answer)
Closed 1 year ago.
I have an enemy AI script working that basically follows my player. Right now I have a "public GameObject player" that I have to assign manually by dragging my player prefab onto the slot. But I want to have a lot of enemies in the scene, so I don't want to have to do this manually for each one. How Can I give the EnemyController script a default player to follow?
I have a PlayerManager which I use to pass the position of my player to the enemy with:
public class EnemyController : MonoBehaviour
{
Transform target;
// Start is called before the first frame update
void Start()
{
target = PlayerManager.instance.player.transform;
}
That part works fine. So my thinking was, just make a public variable for the player like this:
public GameObject player = PlayerManager.instance.player;
But that didn't work. I got this error: "NullReferenceException: Object reference not set to an instance of an object"
Thank you so much for any help you can provide!
With public GameObject player = PlayerManager.instance.player; your field is initialized before the call of EnemyController's constructor, and you provided no control over the value / definition state of PlayerManager.instance.player (PlayerManager or instance or player which can be null and is null in your case). So it's "too early" to use it.
Instead, you can use the event playerJoinedEvent in the PlayerInputManager to assign the enemy to the played which just joined with an event handler, which checks that PlayerManager and instance and player are not null and then assign the player to the target.

Instantiate creates multiple clones in Unity

I have the following code:
public Rigidbody2D ball;
Vector2 sp = new Vector2(0f, 2.1f);
void Update() {
if (Input.GetKeyDown("w")) {
SpawnBall();
DestroyBall();
}
}
void SpawnBall()
{
Instantiate(ball, sp, transform.rotation);
}
void DestroyBall()
{
if (ball.transform.position.y >= -5.7f)
{
Destroy(ball);
}
}
and the code is supposed to generate a new ball every time when "w" is pressed, but for some reason it creates multiple clones and it crashes the engine. How can I create a single clone only?
And also the destroy method doesn't do anything, although it should remove the clone when it passes -5.7 on the y-axis.
Thanks in advance
Create a new script named "SpawnRigidbody" and copy and paste the below code.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpawnRigidbody : MonoBehaviour
{
public Rigidbody2D ball;
Vector2 sp = new Vector2(0f, 2.1f);
void Update()
{
if (Input.GetKeyDown("w")) {
SpawnBall();
}
}
void SpawnBall()
{
Debug.Log ("spawn");
GameObject go = Instantiate(ball, sp, transform.rotation).gameObject;
go.AddComponent<DestroyAfterPosition> ();
}
}
Now create another script named "DestroyAfterPosition" and copy and paste the below code.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DestroyAfterPosition : MonoBehaviour
{
void Update ()
{
if (transform.position.y <= -5.7f)
{
Destroy(gameObject);
}
}
}
Create an empty game object and attach the SpawnRigidbody and then assign your ball in the inspector.
Hope this help you.
There are a couple problems with your Destroy() statement. First, it is destroying ball which is the Rigidbody2D. You will instead want to destroy the gameobject attached to the ball:
Destroy(ball.gameObject);
Second, you are trying to destroy the ball immediately after it is created, but only if y>=-5.7f. I think instead what you are looking to do is continuously check if the ball is above that point and destroy it if it is. Since you are creating multiple balls, they will all need their own check, which means you need to create a script for the ball prefab and in the Update() check its position and Destroy(gameObject) as necessary.
I think you may want to declare ball as a GameObject at the beginning of your script as well, so you are instantiating a gameobject and not just a Rigidbody2D:
public GameObject ball;
Object.Instantiate creates a clone of the provided object, so each time it is called a new object is created. MonoBehaviour.Update is called every frame, which means it's called at least 30 times per second (usually 60 or more on a PC).
So 30+ times per second, your code checks if the w key is held down, and, if so:
A clone of ball is created
Destroy the original ball if it is beyond -5.7 on the y-axis.
Thus, you're creating 30+ ball clones per second, and none will be deleted (because the DestroyBall method only looks at the original ball, not the clones).
If you want to work with the cloned object, assign the result of Instantiate to a field:
ballClone = Instantiate(ball, sp, transform.rotation);
Then you can check if ballClone exists and skip the SpawnBall call if the clone already exists. You can also use ballClone in the DestroyBall method.
ryemoss' answer seems like it's
also important. This answer is just based on looking at your code and the public Unity docs; I don't have a lot of experience with Unity.
Your destroy call is being called once, and only immediately after creating the object.
So it's currently doing this...
User clicks button...
Create ball...
Check to see if the ball is a certain height. It's not, so ignore...
Ball drops down based on gravity or whatever force compels it.
... and is never deleted.
If you want the ball to be destroyed when it reaches a certain point, either...
Have SpawnBall return the game object, which you store and check / delete later in Update,
...or...
Create a script that just checks the object's transform.position and blows up if it's where it needs to be. Attach that to the prefab of the ball you're creating a duplicate of.

Unity3D optimize code

I have 2 objects that do the same thing in terms of the behavior but the only thing that differs is the damage dealt. Right now i have 2 scripts that are a copy paste from each other. Same functions same everything. How can i make 1 script to optimize my work and not duplicate my stuff? Thanks.
using UnityEngine;
using System.Collections;
public class Script1 : MonoBehaviour {
private float attackDamage = 5;
void OnCollisionEnter (Collision item)
{
item.gameObject.GetComponent().Damage(attackDamage);
disableObs();
}
public void disableObs()
{
gameObject.SetActive(false);
}
}
Script 2 is the same thing. I just change the damage variable
Decorate your variable with:
[SerializeField] private int damage;
Now this is a private variable with exposure in the Inspector.
Concerning the workflow, you can drag as many of Script1 onto many objects, they will have their own Script1 set of actions. But the purpose is that you can have infantry with damage value as 1 and tank with damage as 100. All you need to do is set the value for the prefab. One place to set them all. Then you can instantiate the prefabs and they will use the given values.
You can change the damage variable to public and when you add the script to different objects set that variable via inspector. Or if you are doing that change by code on instantiation just call the setDamage(damage) function to the specific object:
gameobject.GetComponent<Script1>().setDamage(damage1);
gameobject2.GetComponent<Script1>().setDamage(damage2);

Shared variables in Unity 3D [duplicate]

This question already has answers here:
Accessing a variable from another script C# [duplicate]
(3 answers)
Closed 6 years ago.
I have 2 c# scripts in my game. On of them is in my "main player object" and the other script is in "my main camera". I want to declare a float variable in the script of my main player, and in every game second i want to record the x position of my player in that variable and at the same time passing this value to the my main camera's script and assigning this value into the x position of my main camera in every game second. How can I pass a variable to a script from another one ? Or how can i create a variable which can be used by any script in my game ?
There's an answer here that explains this problem in great detail, but the simplest way that is included in that answer would be to do something like the following:
public class Speed: MonoBehaviour
public float speed;
// maybe you want restrict this to have read access, then you should use a property instead
And then in other scripts:
GameObject gameObject = GameObject.Find ("Some object");
Speed theSpeed = gameObject.GetComponent <Speed> ();
float mySpeed= theSpeed.speed;

Categories