Create a new instance and override the class - c#

My problem is that I have a plugin and on that plugin I need to get a specific boolean type variable. It has 2 script, here's the script.
RCC_SETTING : ScriptableObject
// Main Controller Settings
public bool useAutomaticGear = true;
RCC_CARCONTROLLERV3
public bool automaticGear{get{return RCCSettings.useAutomaticGear;}}
Now I created my own script called
MANUALTRANSMISSION
private void Start()
{
RCC_Settings RCCSettings = new RCC_Settings();
RCCSettings.useAutomaticGear = false;
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
this.GetComponent<RCC_CarControllerV3>().currentGear += 1;
}
}
What it does is that it doesn't change gear until I press the space. Now the problem is that all of gameobject that has a RCC_CARCONTROLLER script is affected. I want to something like override that so that only my player will be the one who's going for a MANUAL TRANSMISSION.

This should be done easily. First, create this flag bool in your RCC_CarControllerV3 like this:
public bool isPlayer;
Then, check it on the inspector of your Player (only on it).
And then, instead of this:
this.GetComponent<RCC_CarControllerV3>().currentGear += 1;
Do this:
var controller = this.GetComponent<RCC_CarControllerV3>();
if(controller.isPlayer)
controller.currentGear += 1;
But the weird fact here is that you mentioned that this value is changed for all your gameObjects (that has this Component). Because GetComponent will only retrieve the top-level Components of your main gameObject.
To do this, you would need to use GameObject.GetComponentInChildren. But you're not doing this...
Please, I would suggest you to edit your question and put more code. In this way, we could help you better.

Related

Error accessing property across classes: an object reference is required for the non-static field method or property

I have been dabbling in unity and have run into a problem as I an unable to figure out how to notify another class that a ability has been used and the countdown is active. I realize that it is because I need to be making a static reference but not quite sure how to use one while still being able to change the value. I will include just the important bits so that you don't have to waste your time. (I want to be able to have the usedAbilities.canFireballnow be equal to that as when I call it in the fireball script.)
fireball
float canuseFireballtimer = 0;
bool startCooldown = false;
// Update is called once per frame
void Update()
{
if (startCooldown) {
usedAbilities.canFireballnow = false; // error
canuseFireballtimer += Time.deltaTime;
if (canuseFireballtimer >= 5) {
usedAbilities.canFireballnow = true; //error
}
}
if (Input.GetKeyDown(KeyCode.Q) && enoughmana && usedAbilities.canFireballnow) { // error
startCooldown = true;
ManaBar.mana -= 10f;
Instantiate(fireballPrefab, fireballSpawn.position, fireballSpawn.rotation);
}
}
usedAbilities script
public bool canFireballnow = true;
Thanks,
A fellow Programmer
First of all, you need to add a reference to your object. You can do that by using [SerializeField] before creating a variable of type GameObject. Like this:
[SerializeField]
GameObject obj;
Then, in Unity, you can drag the GameObject from the Hierarchy to the Inspector.
This is what you should see in the Inspector:
Then, you need to get the script component of the GameObject to finally be able to read it's value.
obj.GetComponent<name_of_your_script>().value;
Your final code should look like this:
[SerializeField]
GameObject abilities;
void Update() {
if (canuseFireballtimer >= 5) {
abilities.GetComponent<usedAbilities>().canFireballnow = true;
}
Note: Your variable should be public.

null reference exception in level manager script

So I'm basically brand new to unity and C# and have been following along with tutorials online (N3K 2D Platformer, YouTube), I'm trying to create a basic UI to display score etc and I seem to have come across a null pointer exception which I can't seem to figure out as I have referenced the two objects that are causing this error, namely my scoreText object and my hitPointText object.
As I've said I did reference those very objects by dragging them from my hierarchy and into the fields I had created in my level manager script in the inspector and further to that I am simply following along with a tutorial and have done exactly as the video has instructed, but yet on the video it seems to work fine.
The offending lines of code are:
scoreText.text = score.ToString();
hitPointText.text = hitPoints.ToString();
This tutorial is now over 1 year old, is it possible that a unity update has changed that way things NEED to be referenced?
I'll post my level manager code below in the hopes that someone may be able to point out the error that I seem to be missing.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class LevelManager : MonoBehaviour
{
public static LevelManager Instance { set; get; }
public Transform spawnPosition;
public Transform playerTransform;
private int hitPoints = 3;
private int score = 0;
public Text scoreText;
public Text hitPointText;
private void Awake()
{
Instance = this;
scoreText.text = score.ToString();
hitPointText.text = hitPoints.ToString();
}
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
private void Update ()
{
if(playerTransform.position.y < (-10))
{
playerTransform.position = spawnPosition.position;
hitPoints--;
if(hitPoints <= 0)
{
Debug.Log("Your Dead!");
}
}
}
public void Win()
{
Debug.Log("Victory");
}
}
Snippets of screens below:
Scene view of unity engine
Game view of unity engine, with game running
So here is a snippet of code from my player class which uses Instance on the LevelManager script in order that it can have access to the win() method as can be seen in the last case of the switch "WinPost", not sure if that is what you are referring to when your mentioning singleton, other than that never is the term singleton used in any of the scripts I have.
switch (hit.gameObject.tag)
{
case "Coin":
Destroy(hit.gameObject);
break;
case "JumpPad":
verticalVelocity = jumpForce * 2;
break;
case "Teleporter_1":
controller.enabled = false;
transform.position = hit.transform.GetChild(0).position;
controller.enabled = true;
Debug.Log("This works!");
break;
case "Teleporter_2":
controller.enabled = false;
transform.position = hit.transform.GetChild(0).position;
controller.enabled = true;
Debug.Log("This works!");
break;
case "WinPost":
LevelManager.Instance.Win();
break;
default:
break;
}
My guess would be that the components aren't initialized when you call Awake. Awake gets called as a constructor-kind-of method as soon as the object is created. When it is called, you can't be sure if the other components got initialized already.
I would suggest you copy the assignments you make in Awake into Start and come back to see if it works. Start gets called after the GameObjects have their components initialized.
private void Awake()
{
Instance = this;
}
// Use this for initialization
void Start ()
{
scoreText.text = score.ToString();
hitPointText.text = hitPoints.ToString();
}
Thanks to everyone for trying to help and all the great suggestions.
Ultimately I ended up breaking my game in the process of trying to recreate the same UI in a new blank scene, I did manage to recreate the same error before breaking my game which at the time then left me none the wiser. However due to the fact I broke my game I had to step back at least two tutorials and recreate the level manager object and the empty child spawnPosition object, (the level manager script was ok, it was just the level manager object and its child that I broke), anyway in having to recreate both of those objects again everything now seems to work as intended and so this leads me to the conclusion that the problem was not the code but the objects themselves???
Thanks again to everyone that tried to help, another day another learning experience.
D.

Change color of multiple game objects in Unity 5

I would like to change the color of multiple gameobjects in Unity using a single script. I'm kinda lost in the way how to do it. I'm new to Unity and this is some sort of basic training for me.
Unity version: 5.3.4
Observed Behavior:
Added the same script to the other gameobjects and all change to the same color
Expected Behavior:
Change the color of the gameobjects individually
List of things tried:
Using the -FindGameObject-
Tried to acces the materials using the -GameObject-
Tried both at the same time
Thinking in multiple scripts to achieve the results I want
Here's the code
C#:
using UnityEngine;
using System.Collections;
public class ChangeColor : MonoBehaviour
{
//If I change these variables to -GameObject-
//It blocks me to access the renderer
//Making the variables public doesn't work either
private Renderer cube;
private Renderer sphere;
void Start ()
{
//Tried here the -FindGameObjectWithTag-
cube = GetComponent<Renderer>();
sphere = GetComponent<Renderer>();
}
void Update ()
{
if(Input.GetKeyDown(KeyCode.A))
{
//Tried here the -FindGameObjectWithTag-
cube.material.color = Color.red;
}
if(Input.GetKeyDown(KeyCode.S))
{
//Tried here the -FindGameObjectWithTag-
sphere.material.color = Color.green;
}
}
}
Maybe I'm doing something wrong, as I said I'm new to Unity, I kindly accept any help, if it is noobfriendly the better.
Thanks
There are a couple different ways you can go about doing this.
If they are all under the same parent without other objects there too you could loop through the children and change their colors
GameObject Parent = GameObject.Find("ParentObject");
for( int x = 0; x > Parent.transform.childCount; x++);
{
Parent.transform.GetChild(x).GetComponent<Renderer>().material.color = Color.red;
}
If there are less than say 20ish, you could create a list and simply drag and drop each transform into the inspector after changing the list's size to the number of objects you have.
/*Make sure you have Using "System.Collections.Generic" at the top */
//put this outside function so that the inspector can see it
public List<Transform> Objs;
// in your function put this (when changing the color)
foreach(Transform Tform in Objs){
Tform.GetComponent<Renderer>().material.color = Color.red;
}
Similarly to 2, if you want to do it all in code you can do
//Outside function
public List<Transform> Objs;
//inside function
Objs.Add(GameObject.Find("FirstObject").transform);
Objs.Add(GameObject.Find("SecondObject").transform);
//... keep doing this
//now do the same foreach loop as in 2
You could search by tag (if you have a lot of objects) (i would imagine that this would take a bit longer just because it is going through each component but I have no evidence to back that up)
//Outside function
public GameObject[] Objs;
//inside function
Objs = GameObject.FindGameObjectsWithTag("ATagToChangeColor");
foreach(Transform Tform in Objs){
Tform.GetComponent<Renderer>().material.color = Color.red();
}
And about this comment:
//If I change these variables to -GameObject-
//It blocks me to access the renderer
//Making the variables public doesn't work either
If you make them of type GameObject then you should easily be able to access the renderer simply by doing this:
public GameObject cube;
public void Start(){
cube.GetComponent<Renderer>().material.color = Color.red();
}
And making the variables public allows unity's inspector to see the variables so that you can change them in the unity editor without having to open the script.

Show dialog only once, not after level restart

I have my own dialog system which is basically a gameobject with a collider. After triggering collider, Canvas with a Text component should show up. So far, this works. Now, I want to make it happen only once. Here how its work: I start level trigger showing dialog. Game is pretty hardcore so player probably will die. When player dies, I call Application.LoadLevel(Application.loadedLevel); (so basically I restart level)
If I use something like this in scrip with collider
private static bool firstTimeText = true;
void OnTriggerEnter2D(Collider2D coll)
{
if (coll.tag == "Player" && firstTimeText)
{
GetComponent<BoxCollider2D>().enabled = false;
firstTimeText = false;
}
}
everything works like a charm. EXCEPT if I make copy of this gameobject, static variable in script will "handle" that every instantion of this object will have firstTimeText on false after trigger dialog first time. So basically I can use it only once.
So is there any sollution for making trigger which run only once and not reset after Application.LoadLevel?
Also this doesn't work
void Awake()
{
DontDestroyOnLoad(transform.gameObject);
}
Static variables are globally identical - therefore if you need to have multiple gameobjects exhibiting this behavior, they'll need to hook into different static values in some way.
One way to do this would be to have a key, and then keeping a static list of all "keys" already displayed. My recommendation would be a HashSet - thus
private static HashSet<string> firstTimeSet = new HashSet<string>();
public string singleRunKey;
void OnTriggerEnter2D(Collider2D coll)
{
if (coll.tag == "Player"
&& firstTimeSet.Add(singleRunKey))
{ GetComponent<BoxCollider2D>().enabled = false; }
}
Note that .Add returns true if the item wasn't in the collection (and adds it), but false if it already was (and does not add it, because no duplicates). All you have to do now is assign singleRunKey a unique value per object via the Inspector, and each one will run exactly once
Consider just having a static class that will set a flag to indicate if the dialog should appear or not. Note that I am not inheriting from MonoBehaviour here.
public static class ApplicationData {
public static bool ShowDialog = true;
}
Usage:
if (ApplicationData.ShowDialog)
{
ShowDialog();
ApplicationData.ShowDialog = false;
}
The static class will retain its values during the lifetime of your application. So, it will retain the FALSE value even if you reload your scene.

Unity3d: Adding gameobject to List from an array

Thanks for help in advance. Here is a short snippet of the code that I am having an issue with.
GameObject[] allMotor_array;
public List<GameObject> BrokenMotor_list = new List<GameObject>();
void Start()
{
allMotor_array = GameObject.FindGameObjectsWithTag ("Motors");
}
void Update()
{
foreach (GameObject motor in allMotor_array)
{
if(motor.GetComponent<Pump_event>().damaged)
{
BrokenMotor_list.Add(motor);
}
}
}
I have an array of Gameobjects that is created on Start, each of the gameobjects in the array have a script called Pump_event. What I want to do is add the gameobject with a true boolean (damaged) to the list so that I can create a GUI list of all the motors that are damaged (and then take further action on those motors).
With the current code it instantiates the array fine, but when One of the motors boolean changes to true the list tends to continuously add the motor gameobject to the list on each update cycle. So what I want is to figure out a way of adding the gameobject to the list ONCE.
Having it in the update() is probably not the best method but I really am stuck on how to approach this.
G
The Solution to my problem
Thanks for your answers, you all had well thought out responses. I appreciate it. I didn't go with 1 persons method but instead adapted logical approaches found here to work with my script/s.
Here is what I did.
In my pump_event script the events are sorted in a Case and switch as damage increased on the pump the event would escalate. So I added in a section to that script to include "reporting" the damage.
public class Pump_event : MonoBehaviour
//The damage has taken place and event_category=0\\
switch (event_category)
{
case 0:
Master_script.GetComponent<Control_room>().AddtoList (gameObject);
event_category = 1;
break;
I took advice not to insert these types of programing and placed it into its separate class which works out well.
public class Master_script: MonoBehaviour
public void AddtoList(GameObject motor_tobadded)
{
BrokenMotor_list.Add(motor_tobadded);
}
This also eliminated the need on having an array holding all of the pump event controllers as well.
Now the script all works fine. It may not be most efficient but it is doing its job.
Thank you again to all that helped.
In your Pump_event Script you can have a event Action which you register in this snippet and whenever damaged is set true you need to fire the event.
Example:
// in Pump_event Class
public static event Action<GameObject> OnDamagedValueChanged;
private bool _damaged;
public bool Damaged
{
get { return _damaged;}
set
{
_damaged = value;
if(_damaged)
{
if(OnDamagedValueChanged != null)
OnDamagedValueChanged(gameObject);
}
}
}
In your Current Class where you have array of GameObjects:
void OnEnable()
{
Pump_event.OnDamagedValueChanged += HandleOnDamagedValueChanged;
}
void OnDisable()
{
Pump_event.OnDamagedValueChanged -= HandleOnDamagedValueChanged;
}
void HandleOnDamagedValueChanged(GameObject obj)
{
if (!BrokenMotor_list.Contains (obj))
{
BrokenMotor_list.Add (obj);
}
}
Using Actions is a better approach than doing it in Update Method. It is not good for performance to keep checking for a bool in iteration in update method. and try to avoid GetComponent and Find/FindObjectWithTag Methods in Update. It is not good practice. I hope this is helpful.
According to the code you have posted, the problem lies within the fact that the damaged property is never reset. One solution would be to reset this property once you add it to the list, like so:
if(motor.GetComponent<Pump_event>().damaged)
{
motor.GetComponent<Pump_event>().damaged = false;
BrokenMotor_list.Add(motor);
}
However, multiple copies of the same object could still be added to your list if the motor is damaged again.
To go around this, you could use a HashSet. The hash set will allow only one copy of an object to exist within it, thus, if an object is already present is will not be added again.
The catch is that you will need to override the GetHashCode and Equals methods for your GameObject class since these will be used internally by the hash set to place items within itself and identify duplicates.
check if list already contains motor.
if(motor.GetComponent<Pump_event>().damaged)
{
if(BrokenMotor_list.Contains(motor))
{
BrokenMotor_list.Add(motor);
}
}
although on msdn describes how to implement IEquatable in case if you want compare different objects(with different references) https://msdn.microsoft.com/ru-ru/library/vstudio/bhkz42b3%28v=vs.100%29.aspx
if (!BrokenMotor_list.Contains (motor)) {
BrokenMotor_list.Add (motor);
}
You'd better do this after damage event occur by add a delegate.

Categories