I'm making a game in Unity3D and I have a 2 different scripts. One called Rays (it checks what I'm clicking on and lowers its hp) and a script called colorChange (it changes the color of the object that I clicked on depending on its hp). I created the hp variable in colorChange and I need to check hp in Ray.
So the "colorChange" script depends on the "Rays" script, yes?
Then you can define the "colorChange" script to expect a "Rays" component on the same GameObject by using the [RequireComponent] tag, which is described
here: https://docs.unity3d.com/ScriptReference/RequireComponent.html
Then in the "Awake" function of "colorChange" you retrieve a reference to "Rays". If the "hp" variable in "Rays" has public get access then in "colorChange" you can use the acquired reference to the "Rays" script to check its current value.
Example for script "Rays":
using UnityEngine;
public class Rays : MonoBehaviour {
private int hp = 0;
public int Hitpoints {
get { return hp; }
}
// ... other methods ...
}
Example for script "colorChange":
using UnityEngine;
[RequireComponent (typeof (Rays))]
public class colorChange : MonoBehaviour {
private Rays raysReference = null;
protected void Awake() {
raysReference = GetComponent<Rays>();
}
protected int getRaysHitpoints() {
return raysReference.Hitpoints;
}
// ... other methods that may use getRaysHitpoints ...
}
Related
I've been using Unity to create a simple 2D game but the problem is that even when the game object "player" gets destroyed, the gameobject "isDead" (text) doesn't appear.
This is my script.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class youDied_Text : MonoBehaviour
{
private Transform player;
private Text isDead;
// public static bool isDead;
// Start is called before the first frame update
private void Start() {
isDead = GetComponent<Text>();
}
void checkForDeath()
{
if (player==false)
{
isDead.gameObject.SetActive(true);
}
else
{
isDead.gameObject.SetActive(false);
}
}
// Update is called once per frame
void Update()
{
player = GameObject.FindWithTag("Player").transform;
checkForDeath();
}
}
This script is attached in the text which I need to display in UI element.
As was noted currently you would get a NullReferenceException which is definitely not what you want.
There is absolutely no need / redundancy going through Transform at all actually. Simply store the GameObject reference instead
You are currently setting the object to inactive which has the Text attached ... which is the same object your component is attached to as well!
=> As soon as you end up in the second case once you set it to inactive => from now on Update is never called anymore!
In general as it sounds like this should only happen once anyway I would use a more event driven approach and have a component on your player like e.g.
public class Player : MonoBehaviour
{
public UnityEvent onDied;
private void OnDestroy ()
{
onDied.Invoke();
}
}
And then simply attach a listener/callback to that event once without poll checking states. You can do this either via the Inspector directly (just like in e.g. Button.onClick) or via code like e.g.
public class youDied_Text : MonoBehaviour
{
// Already reference things via the Inspector if possible!
[SerializeField] private GameObject player;
[SerializeField] private Text isDead;
private void Awake()
{
if(!isDead) isDead = GetComponent<Text>();
isDead.gameObject.SetActive(false);
// If you want to rather set it via the Inspector remove all the rest here
//if(!player) player = GameObject.FindWithTag("Player"). GetComponent<Player>();
// or even simpler
if(!player) player = FindObjectOfType<Player>();
player.onDied.AddListener(OnPlayerDied);
}
// If you want to rather set it via the Inspector make this public
private void OnPlayerDied()
{
isDead.gameObject.SetActive(true);
}
}
How do I change one or two attribute values of a script so that it effects all the gameObjects that this script is attached to?
For example making attributes SphereSmall and SphereBig global
public Vector3 SphereSmall = new Vector3 (0.001f, 0.001f, 0.001f);
public Vector3 SphereBig = new Vector3 (0.0015f, 0.0015f, 0.0015f);
Two gameObjects has this script attached to and I changed the attribute of public variables SphereSmall and SphereBig on one GameObject. I want this value to be changed in second GameObject as well.
I'm new to unity as well, but here are some solutions:
1) If you're talking about multiple instances of the same object, simply create a prefab out of that object and update the properties of the prefab.
https://docs.unity3d.com/Manual/CreatingPrefabs.html
2) If you're talking about instances of different objects, you can try using the multi-select functionality of the unity editor, this will let you edit all common properties. This is easy if you have lower number if instances and are grouped under a parent object in the Hierarchy pane.
3) If you're talking about instances of different objects and you don't mind seeing the effect of your updates only at run-time: you can try using the ScriptableObject class:
[CreateAssetMenu]
public class CommonObjectProperties : ScriptableObject
{
public Vector3 SphereSmall = new Vector3(1, 0.001f, 0.001f);
public Vector3 SphereBig = new Vector3(0.0015f, 0.0015f, 0.0015f);
}
After you create this script, go to Assets > Create > Common Object Properties:
Now you can use this ScriptableObject instance to add the common values to your objects and after you update them inside the ScriptableObject instance, they will update across all objects.
ObjectScript is the MonoBehaviour script to put on your objects:
public class ObjectScript : MonoBehaviour
{
public CommonObjectPropertis commonProps;
public Vector3 ObjectScriptSmallSphere;
private void Start()
{
ObjectScriptSmallSphere = commonProps.SphereSmall;
}
}
How it should look in the designer:
I'm sure there are plenty of other ways to do this, best of luck!
You could add [ExecuteInEditMode] to your script so it runs while the editor is running. From there you could check if the values are being changed and then update them. Something like this:
[ExecuteInEditMode]
public class MyScript : MonoBehaviour
{
public int myValue;
private int oldValue;
void Update ()
{
if (oldValue != myValue)
{
MyScript[] objects = FindObjectsOfType<MyScript>();
foreach(MyScript myObject in objects)
{
myObject.myValue = myValue
}
oldValue = myValue;
}
}
}
This isn't best practice though so I would recommend looking into using prefab variants instead.
In Unity C# script I have a singleton game controller object in which the game variables are stored but I am getting odd behaviour when accessing them in a member function. It prints the initialized value, not the current one. In the update function however it prints the correct value each frame. I summarized the class below. The controller class has a static reference to itself. If you need to know additional details you can ask. I am new to C# and Unity so I might be lacking some obvious answer.
Thanks
public class controller : MonoBehaviour {
public int[] star = new int[64];
void Start(){ /* calls another function to set 0 for each star index */ }
void Update(){ // during gameplay star[0] gets a value of 1
print(star[0]); // prints correct value which is 1
}
public void checkValue(){
print(star[0]); // prints 0 incorrectly which should be 1
}
}
I've set up a little example. I created a button and an empty gameobject GameController. I added this code to the GameController:
using UnityEngine;
using System.Collections;
public class GameController : MonoBehaviour {
public static GameController instance;
[System.NonSerialized] public int[] star = new int[64];
private void Awake()
{
if(instance == null)
instance = this;
else if(instance != this)
Destroy(gameObject);
DontDestroyOnLoad(gameObject);
}
private void Start()
{
StartCoroutine(SetAllTo(1));
}
// for simulating some changes during the game
private IEnumerator SetAllTo(int value)
{
yield return new WaitForSeconds(2.0f);
for(int i = 0; i < star.Length; i++)
star[i] = value;
Debug.Log("Setting done");
}
public void PrintFirst()
{
Debug.Log(star[0]);
}
}
Now I added an OnClick event to the button, dragged the GameController gameobject into the slot and picked PrintFirst.
I start the game and click the button once before the Coroutine log and once after and the console gives the following:
0
Setting Done
1
Edit:
The gameobject for the OnClick event must be in the scene, it can't be a prefab in the assets folder.
It seems that's the call to the start function may also occurs in your external calls before the call for ckeckValue
Try debugging by putting breakpoint in each of these functions and you can understand what is going on.
The start function runs once in the beginning of the game and not again.
For that you have pattern - Singleton
The second thing why to call external function to initialize class member? do it in your default contractor.
- C# default constractor already initialize 0 in int[].
if you still what to run Start from other scope in your code make it public (c# makes variable/methods as private by default)
I made 2 scripts and assigned it to 2 cubes: "cube" and "cube 1".
Normally if you click on cube it sets a value so that when you click cube 1 it disappears.
If you click cube 1 first it's not gonna work.
So that's what I tried to make but it does not work and I don't understand why.
here are my scripts
cube:
using UnityEngine;
using System.Collections;
public class script : MonoBehaviour
{
public int test = 0; // make the variable for the value
public void OnMouseDown() // when the user click
{
test = 1; //make the value of test 1
}
}
cube 1:
using UnityEngine;
using System.Collections;
public class NewBehaviourScript1 : MonoBehaviour
{
public GameObject a; //make a gameobject
public script script; //make a variable where we put in the script
void OnMouseDown() // when the user click
{
script = a.GetComponent<script>(); // get script
if ( script.test == 1) //test or the variable test in the other script is 1
{
Destroy(gameObject); // destroy the object
}
}
}
Can someone please help me?
Change the name of the script class to be capitalised.
public class Script : MonoBehaviour
Then in the NewBehaviourScript1 change everything inside it to:
public class NewBehaviourScript1 : MonoBehaviour
{
public Script script; //Drag the other cube onto this in the inspector.
void OnMouseDown()
{
if ( script.test == 1)
{
Destroy(gameObject);
}
}
}
You should use more descriptive names for both your classes and their instances.
Note: For this to work you will have to have drag the other cube onto the script variable in the inspector and it will have to have a Script attached to it.
Try using a.GetComponent<script>();. You need to pass a Type to GetComponent in order for it to work. I'm not sure that your code even compiles, its very hard to read it because you did not format it properly.
I read many pages on google and everything else I could find but nothing helped me, so I have to ask here: I made a script attached to 100 cubes it says:
using UnityEngine;
using System.Collections;
public class IfClose:MonoBehaviour{
public bool Gravitronned=false;
// Use this for initialization
void Start(){
}
// Update is called once per frame
void Update(){
}
void OnTriggerEnter(Collider col)
{
if(col.gameObject.name =="IfInScreenGrv"){
Gravitronned=true;
}
else
{
Gravitronned=false;
}
}
}
and then I have another script that says:
using UnityEngine;
using System.Collections;
public class TimeFreeze:MonoBehaviour{
static bool GravitronedTwice;
// Use this for initialization
void Start(){
}
void Update()
{
GravitronedTwice= gameObject.GetComponent<IfClose>().Gravitronned;
if(GravitronedTwice=true){
if(Input.GetKeyDown(KeyCode.V)){
Physics.gravity =newVector3(0,3.0F,0);
}
}
}
}
so when I press V I want the cube only in this area to get Physics.gravity = new Vector3 (0, 3.0F, 0);
You're calling the value of the bool variable Gravitronned in the second script using GetComponent<>() which is not the right way of going about this.
How about instead of having two bool variables, Gravitronned and GravitronnedTwice, you only have 1 variable in the first script, make it public [even though make it public a bad idea - but that's another topic altogether] and have it access to both the scripts, instead of what you're doing. That way you can change the bool value, as well as access it in both scripts.
Alternatively, you can make the bool Gravitronned private in Script 1, and access it in any other script via C# property.
Script 1
private bool Gravitronned;
public BOOL GRAVITY
{
get Gravitronned;
set Gravitronned;
}