unity - how to update an object when a serialized field is changed? - c#

I'm sure the question is already out there but I cannot find it, sorry.
I'm trying to sync a Serialized field of an object with other of its components.
let's say I have a field "size" which should impact the object transform scale:
[SerializeField]
int _size;
I'm looking for an event handler or something that allow me to do:
void onSerializedPropertyChange() {
transform.localScale = new Vector3(_size,_size,_size);
}
Does a method like that exists ?
In the end the idea would be to work with more than one property and to tweak object properties while preview the result.

Update object based on serialized field?
You can update a variable that has SerializeField, when you add the OnChangedCall Element.
Member Variable:
[SerializeField]
[OnChangedCall("onSerializedPropertyChange")]
private int _size;
You should now be able to just add the function as a String in the brackets and it should be called on change.
The method called must be public or it will produce an Error!
Method:
public void onSerializedPropertyChange() {
transform.localScale = new Vector3(_size,_size,_size);
}
The OnChangedCall is a custom PropertyAttribute and needs to inherit from it.
OnChangedCall Class:
using System.Linq;
using UnityEngine;
using UnityEditor;
using System.Reflection;
public class OnChangedCallAttribute : PropertyAttribute
{
public string methodName;
public OnChangedCallAttribute(string methodNameNoArguments)
{
methodName = methodNameNoArguments;
}
}
#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(OnChangedCallAttribute))]
public class OnChangedCallAttributePropertyDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginChangeCheck();
EditorGUI.PropertyField(position, property, label);
if(EditorGUI.EndChangeCheck())
{
OnChangedCallAttribute at = attribute as OnChangedCallAttribute;
MethodInfo method = property.serializedObject.targetObject.GetType().GetMethods().Where(m => m.Name == at.methodName).First();
if (method != null && method.GetParameters().Count() == 0)// Only instantiate methods with 0 parameters
method.Invoke(property.serializedObject.targetObject, null);
}
}
}
#endif

Here's my version of the OnChangedCallAttributePropertyDrawer from IndieGameDev's answer.
The main change being the addition of the following line
property.serializedObject.ApplyModifiedProperties();
This will ensure that the SerializedField is updated before the function is called, fixing a bug where the scene would not be properly updated when the serialized field is changed.
OnChangedCallAttributePropertyDrawer :
#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(OnChangedCallAttribute))]
public class OnChangedCallAttributePropertyDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginChangeCheck();
EditorGUI.PropertyField(position, property, label);
if (!EditorGUI.EndChangeCheck()) return;
var targetObject = property.serializedObject.targetObject;
var callAttribute = attribute as OnChangedCallAttribute;
var methodName = callAttribute?.MethodName;
var classType = targetObject.GetType();
var methodInfo = classType.GetMethods().FirstOrDefault(info => info.Name == methodName);
// Update the serialized field
property.serializedObject.ApplyModifiedProperties();
// If we found a public function with the given name that takes no parameters, invoke it
if (methodInfo != null && !methodInfo.GetParameters().Any())
{
methodInfo.Invoke(targetObject, null);
}
else
{
// TODO: Create proper exception
Debug.LogError($"OnChangedCall error : No public function taking no " +
$"argument named {methodName} in class {classType.Name}");
}
}
}
#endif
Edit :
I'd just like to share a small tip for those who might not know, I'm not a fan of referencing functions with a string literal, it's usually prone to error and you most likely won't get help from your IDE.
You can instead use nameof() which will allow you to use your IDE autocompletion, Rider will also recognize the function as being used.
[SerializeField]
[OnChangedCall(nameof(UpdateHeuristic))]
private AStar.Heuristic heuristic;
public void UpdateHeuristic()
{
_pathfinding?.SetHeuristic(heuristic);
}

public class UIAnimatorGroup:MonoBehaviour
{
public UIAnimatorTransform _animatorTransform;
}
[System.Serializable]
public class UIAnimatorTransform
{
[HideInInspector] public Matrix4x4 LocalMatrix4X4; // 局部
[HideInInspector] public Matrix4x4 GobleMatrix4X4;
[HideInInspector] public UIAnimatorTransform parent;
[SerializeField]
[OnChangedCall("onSerializedPropertyChange","UIAnimatorTransform")]
private Vector3 position;
[SerializeField]
[OnChangedCall("onSerializedPropertyChange","UIAnimatorTransform")]
private Vector3 rotation;
[SerializeField]
[OnChangedCall("onSerializedPropertyChange","UIAnimatorTransform")]
private Vector3 scale;
public void onSerializedPropertyChange()
{
SetLocalMatrixByTransform();
CalculateGobleTransform();
}
}

How about [ExecuteInEditMode]?
Then you can use the normal Update() method.

Related

How do I pass a variable between scripts in Unity 2d C#

For example, I have a variable "Wisps" that I want to change when the player picks up an object. But I don't know how to do it. I tried to add a WispDisplay object to call the classes, like in Java, but it doesn't seem to work.
public class WispCode : MonoBehaviour
{
WispDisplay wd = new WispDisplay();
private void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Player")
{
wd.setWisp(wd.getWisp()+1);
Destroy(gameObject);
}
}
}
public class WispDisplay : MonoBehaviour
{
public int Wisp = 5;
public Text WispText;
void Start()
{
}
void Update()
{
WispText.text = "Wisp: " + Wisp.ToString();
}
public int getWisp()
{
return Wisp;
}
public void setWisp(int newWisp)
{
Wisp = newWisp;
}
}
Easiest (a tiny bit dirty) way is to use a static variable. Downside: you can only have exactly ONE.
Example:
public class MyClass: MonoBehaviour {
public static int wisps;
}
Then, in ANY class, just use this to access it:
MyClass.wisps = 1234;
The more elegant way, working with multiple class instances, is using references.
Example:
public class PlayerClass: MonoBehaviour {
public int wisps = 0;
}
public class MyClass: MonoBehaviour {
public PlayerClass player;
void Update(){
player.wisps += 1;
}
}
Then, you need to drag-drop (aka "assign") the "PlayerClass" Component (attached to the player) to the the Gameobject that should increase the Wisps count. You can duplicate these objects after assigning the reference.
Now, if you actually want to have some sort of collectible, I'd suggest this approach:
You Have a Player "PlayerClass" and some Objects that are collectible, which have Trigger Colliders.
The objects have this code:
public class Example : MonoBehaviour
{
private void OnTriggerEnter(Collider other)
{
// probably a good idea to check for player tag:
// other.compareTag("Player");
// but you need to create the "Player" Tag and assign it to Player Collider Object.
if(TryGetComponent(out PlayerClass player))
{
player.wisps += 1;
}
}
}

UnityEngine.MonoBehaviour:.ctor ()

I am trying to build a system that finds the nearest position of an object and uses it to transform the Player to a specific position. I understand the issue but I couldn't eliminate the yellow exclamation mark. The program is somehow working, but I'd like to see the solution.
The issue according to UnityConsole is: You are trying to create a MonoBehaviour using the 'new' keyword. This is not allowed. MonoBehaviours can only be added using AddComponent(). Alternatively, your script can inherit from ScriptableObject or no base class at all
UnityEngine.MonoBehaviour:.ctor ()
Scripts are:
#1
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
public class ScoreMultiplerFinder : MonoBehaviour
{
private static ScoreMultiplerFinder instance;
private List<GameObject> checkpoints = new List<GameObject>();
public List<GameObject> Checkpoints { get { return checkpoints; } }
public static ScoreMultiplerFinder Singleton
{
get
{
if (instance == null)
{
instance = new ScoreMultiplerFinder();
instance.Checkpoints.AddRange(
GameObject.FindGameObjectsWithTag("Checkpoint"));
instance.checkpoints = instance.checkpoints.OrderBy(waypoint => waypoint.name).ToList();
}
return instance;
}
}
}
#2(inPlayerObject)
public void FindClosestMultiplier()
{
float lastDist = Mathf.Infinity;
for (int i = 0; i < ScoreMultiplerFinder.Singleton.Checkpoints.Count; i++)
{
GameObject thisWP = ScoreMultiplerFinder.Singleton.Checkpoints[i];
float distance = Vector3.Distance(transform.position, thisWP.transform.position);
if (distance < lastDist)
{
currentIndex = i;
lastDist = distance;
lastScoreMultip.position = ScoreMultiplerFinder.Singleton.Checkpoints[currentIndex].transform.position;
}
}
}
Thanks in advance and have a great day!
The error/warning is pretty much telling you what to do instead. A correct way to lazy initialize the Singleton would be
private List<GameObject> checkpoints;
// First of all be consequent and let nobody change the content of this
public IReadOnlyList<GameObject> Checkpoints => checkpoints;
public static ScoreMultiplerFinder Singleton
{
get
{
if(instance) return instance;
// before creating one check if there maybe is one already first
instance = FindObjectOfType<ScoreMultiplerFinder>();
if(instance) return instance;
// GameObject is one of the very few UnityEngine.Object types where using
// "new" is actually okey
instance = new GameObject(nameof(ScoreMultiplerFinder)).AddComponent<ScoreMultiplerFinder>();
return instance;
}
}
private void Awake ()
{
// Without this your "Singleton" is not complete and you rather only have a
// lazy factory property.
// For a valid singleton pattern you have to make sure that there actually
// exists only one single instance at a time!
if(instance && instance != this)
{
Destroy (gameObject);
return;
}
instance = this;
checkpoints = GameObject.FindGameObjectsWithTag("Checkpoint").OrderBy(waypoint => waypoint.name).ToList();
}
And then if you already use Linq you are already familiar with OrderBy.
Your second script can be shrinked down to
public void FindClosestMultiplier()
{
// Simply get the waypoints
// - "OrderBy" them by distance. using the "sqrMagnitude" is faster and for ordering has exactly the same effect as
// "Distance" which uses the more expensive "magnitude"
// - use "FirstOrDefault" to get either the closest item or "null" if there wasn't any at all
var closest = ScoreMultiplerFinder.Singleton.Checkpoints.OrderBy(c => (transform.position - c.transform.position).sqrMagnitude).FirstOrDefault();
// Was there any at all?
if(!closest) return;
// Otherwise "closest" is the closest waypoint -> do something with it
lastScoreMultip.position = closest.position;
}
Actually as mentioned I don't think you need a MonoBehaviour at all.
You could as well simply have
public static class ScoreMultiplerFinder
{
private static List<GameObject> checkpoints;
public static IReadOnlyList<GameObject> Checkpoints
{
get
{
if(checkpoints == null) checkpoints = GameObject.FindGameObjectsWithTag("Checkpoint").OrderBy(waypoint => waypoint.name).ToList();
return checkpoints;
}
}
}
and then accordingly do
public void FindClosestMultiplier()
{
var closest = ScoreMultiplerFinder.Checkpoints.OrderBy(c => (transform.position - c.transform.position).sqrMagnitude).FirstOrDefault();
if(!closest) return;
lastScoreMultip.position = closest.position;
}

Unity 3d pass bool variable between two objects

how i can pass a simple boolean variable between two different object?
I can try this but didn't work...
First script:
public class CollisionController : MonoBehaviour
{
public PlayerMovement movement;
public bool active = false;
private void OnCollisionEnter(Collision collision)
{
if(collision.collider.tag == "Obstacle")
{
active = true;
}
}
}
Second script (that read the boolean variable "active")
public class EmptyControllerColl : MonoBehaviour
{
public CollisionController controller;
public PlayerMovement movement;
public bool activeLocal = false;
private void Start()
{
GetComponentInChildren<CollisionController>();
}
void Update()
{
activeLocal = controller.active;
if(activeLocal == false)
{
Debug.Log("Nothing...");
}
if(activeLocal == true)
{
Debug.Log("Game over");
}
}
}
When the variable bool "Active" change its status, the variable "activeLocal" don't change status.. How can I resolve this problem?
Collision Controller is "connect" to Cube Object.
EmptyControllerColl is "connect" to emptyGameObject (parent of Cube).
This line
_ = GameObject.Find("cubo Variant").GetComponent<CollisionController>().active;
makes no sense. First of all there is no field or variable declared with the name _ so this shouldn't even compile at all. And secondly what do you need this for? Rather store the according reference once in the controller field and reuse it later.
Then for your usecase there is no need at all to store the value in a local variable ... this makes things only more complicated. Simply where you need it get the value from controller.active.
Also do not use == for tags. Rather check via CompareTag. The problem is that == silently fails if you have any typo or the tag doesn't exist at all. CompareTag rather throws an error that the given tag is not valid.
public class EmptyControllerColl : MonoBehaviour
{
// Best already drag this in via the Inspector in Unity
[SerializeField] private CollisionController controller;
public PlayerMovement movement;
// As fallback get it ONCE on runtime
private void Awake()
{
// since you say the cube is a child of this empty object you do not use
// Find at all but can simply use GetComponentInChildren
if(!controller) controller = GetComponentInChildren<CollisionController>(true);
}
void Update()
{
// No need to store this in a local field at all
if(!controller.active)
{
Debug.Log("Nothing...");
}
// use if else since both cases are exclusive and you don't even need to check the value twice
else
{
Debug.Log("Game over");
}
}
}
Event Driven - part A
In general you should avoid poll checks for a bool value in Update and rather come up with a more event driven solution! An example could look like:
public class CollisionController : MonoBehaviour
{
public PlayerMovement movement;
// Here everyone who wants can add listeners that get called as soon as
// we invoke this event. We will do it everytime the 'active' value is changed
public event Action<bool> OnActiveStateChanged;
// Backing field for 'active'
private bool _active;
// Property that reads and writes '_active'
// Everytime it is assigned it also invokes 'OnActiveStateChanged'
private bool active
{
get { return _active; }
set
{
_active = value;
OnActiveStateChanged?.Invoke(_active);
}
}
private void OnCollisionEnter(Collision collision)
{
if(collision.collider.CompareTag("Obstacle"))
{
active = true;
}
}
}
Now you would register a listener for this event like
public class EmptyControllerColl : MonoBehaviour
{
// Best already drag this in via the Inspector in Unity
[SerializeField] private CollisionController controller;
public PlayerMovement movement;
// As fallback get it ONCE on runtime
private void Awake()
{
// since you say the cube is a child of this empty object you do not use
// Find at all but can simply use GetComponentInChildren
if(!controller) controller = GetComponentInChildren<CollisionController>(true);
// register a callback. It is allowed an save to unregister first
// which makes sure this is only registered exactly once
controller.OnActiveStateChanged -= HandleControlerActiveStateChanged;
controller.OnActiveStateChanged += HandleControlerActiveStateChanged;
}
private void HandleGameOver()
{
Debug.Log("Game over");
}
private void HandleControlerActiveStateChanged(bool value)
{
if(!value)
{
Debug.Log("Nothing...");
}
else
{
Debug.Log("Game over");
}
}
private void OnDestroy()
{
// always clean up listeners
controller.OnActiveStateChanged -= HandleControlerActiveStateChanged;
}
}
This now is way more efficient since you don't all time run an Update method. Instead the HandleControlerActiveStateChanged is only called when the value of active is actually changed.
Event Driven - part B
And then actually in your case there is need to use a bool at all you could use a simple event Action instead and remove all the bools entirely:
public class CollisionController : MonoBehaviour
{
public PlayerMovement movement;
public event Action OnGameOver;
private void OnCollisionEnter(Collision collision)
{
if(collision.collider.CompareTag("Obstacle"))
{
OnGameOver?.Invoke();
}
}
}
Now you would register a listener for this event like
public class EmptyControllerColl : MonoBehaviour
{
[SerializeField] private CollisionController controller;
public PlayerMovement movement;
private void Awake()
{
if(!controller) controller = GetComponentInChildren<CollisionController>(true);
controller.OnGameOver -= HandleGameOver;
controller.OnGameOver += HandleGameOver;
}
private void HandleGameOver()
{
Debug.Log("Game over");
}
private void OnDestroy()
{
controller.OnGameOver -= HandleGameOver;
}
}
using UnityEngine;
public class CollisionController : MonoBehaviour
{
void Start()
{
// Calls the function ApplyDamage with a value of 5
// Every script attached to the game object
// that has an ApplyDamage function will be called.
gameObject.SendMessage("ApplyDamage", 5.0);
}
}
public class EmptyControllerColl : MonoBehaviour
{
public void ApplyDamage(float damage)
{
print(damage);
}
}
https://docs.unity3d.com/ScriptReference/GameObject.SendMessage.html

Access Serialized List Object for Custom Unity Editor Window

I am trying to create a Custom EditorWindow (TransporterToolKit.cs) with buttons of my game's fast-travel points.
I have a GameObject (TransporterSystem.cs, a singleton, the manager):
that has a LIST of child GameObjects that are Nodes (The GameObjects fast travel points). Each node has a Serializable TransporterLocation that holds details about the actual location.
I get null object error:
NullReferenceException: Object reference not set to an instance of an
object
whether I am running the game or not using my current TransporterToolKit.cs file
How do I access the list of nodes so I can get their Serializable TransporterLocation?
EDITOW WINDOW:
What my problem question is about.
TransporterToolKit.cs
public class TransporterToolKit : EditorWindow {
[MenuItem("Project ToolKits/Transporter ToolKit")]
public static void ShowWindow() {
GetWindow<TransporterToolKit>("Transporter ToolKit");
}
public List<TransporterNode> nodes;
private void OnEnable() {
//ERROR COMES FROM THIS LINE
nodes = TransporterSystem.s_Instance.GetAllTransporterNodes();
}
private void OnGUI() {
GUILayout.Label("Transporter System", EditorStyles.boldLabel);
//Create a list of buttons with the location name
foreach (TransporterNode node in nodes) {
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
GUILayout.BeginHorizontal();
if (GUILayout.Button(node.ThisLocation.locationName)) {
//Do something
}
GUILayout.EndHorizontal();
EditorGUILayout.EndVertical(); //end section outline
}
}
}
The other classes.
TransporterSystem.cs
public class TransporterSystem : Singleton<TransporterSystem> {
[Header("Transporter Nodes")]
[SerializeField]
private List<TransporterNode> nodeList;
public List<TransporterNode> GetAllTransporterNodes() {
return nodeList;
}
}
TransporterNode.cs
public class TransporterNode : MonoBehaviour {
[SerializeField]
private TransporterLocation thisLocation;
public TransporterLocation ThisLocation {
get {
return thisLocation;
}
set {
thisLocation = value;
}
void Awake() {
ThisLocation.locationName = gameObject.name;
ThisLocation.transporterLocation = transform.position;
}
}
TransporterNode.cs
public enum TRANSPORTER_NODE_STATE {
OFFLINE,
ONLINE
}
[Serializable]
public class TransporterLocation {
public Vector3 transporterLocation;
public TRANSPORTER_NODE_STATE locationState;
public string locationName;
public TransporterLocation() {
transporterLocation = Vector3.zero;
locationName = "NOT SET";
locationState = TRANSPORTER_NODE_STATE.OFFLINE;
}
}
It looks like s_Instance is null. The problem is, that you are asking for the TransporterSystem static instance in OnEnable of the EditorWindow, however, the static instance will only be set in Awake during play mode. (At least this is what I assume after testing your code in my project).
I would fix this by actively searching for the TransporterSystem from within the editor window:
TransporterToolKit.cs
private void OnEnable()
{
TransporterSystem system = FindObjectOfType<TransporterSystem>();
if (system == null)
{
Debug.LogError("No TransporterSystem in scene.");
}
else
{
nodes = system.GetAllTransporterNodes();
}
}
Alternatively, you could also make your singleton implementation lazy, similar to this:
public class MonoSingleton
{
public static TransporterSystem instance
{
get
{
if (m_Instance == null)
m_Instance = Object.FindObjectOfType<TransporterSystem>();
if (m_Instance == null)
Debug.LogError("Unable to find TransporterSystem instance in scene.");
return m_Instance;
}
}
private static TransporterSystem m_Instance;
}
To fix the problem, that the Node is only updated in play mode:
// Reset is called when the component is added to a GameObject or when Reset is selected from the inspector.
void Reset() {
#if UNITY_EDITOR
UnityEditor.Undo.RecordObject(gameObject, "Update LocationNode");
#endif
ThisLocation.locationName = gameObject.name;
ThisLocation.transporterLocation = transform.position;
}
Instead of assigning the values in Awake, you need to do it at edit time. The simplest example would be via the Reset callback (but you could trigger it from your editor window or a special button as well). The important part is, that you want to not only set the values, but actually serialize the data to disk. This means, marking the scene as dirty. Unity recommends, to use the Undo class, to not only record an undoable action, but also set the scene as dirty. Alternatively, you can just do:
UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(gameObject.scene);
Beware, that the editor code needs to be either within a file that is placed in the Editor folder or surrounded by the compilation symbols UNITY_EDITOR.

Accessing boolean from a different class in C#

I have one collision script in which I set a boolean to true or false
using UnityEngine;
using System.Collections;
public class IsTriggerLockCamera : MonoBehaviour {
public bool CameraLock = false;
public void OnTriggerStay2D(Collider2D other) {
CameraLock = true;
Debug.Log ("Im inside");
}
public void OnTriggerExit2D(Collider2D other) {
CameraLock = false;
Debug.Log ("I exited");
}
}
I want to access this boolean from my camera script, I tried this
if (CameraLock == true) {
Debug.Log ("Im locked");
}
However, I get an error saying that CameraLock doesn't exist in the current context. The boolean is public so I'm very confused.
EDIT: I feel like I didn't give good enough info so I'll start by posting the whole camera script and then clarifying.
using System;
using UnityEngine;
public class CameraFollowLockY : MonoBehaviour
{
public Transform target;
public float damping = 1;
public float lookAheadFactor = 3;
public float lookAheadReturnSpeed = 0.5f;
public float lookAheadMoveThreshold = 0.1f;
private float m_OffsetZ;
private Vector3 m_LastTargetPosition;
private Vector3 m_CurrentVelocity;
private Vector3 m_LookAheadPos;
private void Start()
{
m_LastTargetPosition = target.position;
m_OffsetZ = (transform.position - target.position).z;
transform.parent = null;
}
private void Update()
{
float xMoveDelta = (target.position - m_LastTargetPosition).x;
bool updateLookAheadTarget = Mathf.Abs(xMoveDelta) > lookAheadMoveThreshold;
if (updateLookAheadTarget)
{
m_LookAheadPos = lookAheadFactor*Vector3.right*Mathf.Sign(xMoveDelta);
}
else
{
m_LookAheadPos = Vector3.MoveTowards(m_LookAheadPos, Vector3.zero, Time.deltaTime*lookAheadReturnSpeed);
}
Vector3 aheadTargetPos = target.position + m_LookAheadPos + Vector3.forward*m_OffsetZ;
Vector3 newPos = Vector3.SmoothDamp(transform.position, aheadTargetPos, ref m_CurrentVelocity, damping);
transform.position = newPos;
transform.position = new Vector3(transform.position.x, 0, transform.position.z);
m_LastTargetPosition = target.position;
if (CameraLock == true) {
Debug.Log ("Im locked");
}
}
The IsTriggerLockCamera is a script I used for an invisible collider in Unity. My camera is focused on the player at all times, but I want it to stop moving when the player is close to reaching the edge of the map, so he can notice that the map is ending. The original plan was, that the collider would send out information when player enters it and then instead of Debug.Log ("Im Locked"); would be some code that would lock the camera in place. I don't know if this solution is very elegant and I'd like to apologize for not clarifying everything properly beforehand, but I started coding probably 2 months ago (I did only Rails websites) and I got into C# game development about a week ago so I'm still missing the terminology required to properly describe the problems I encounter. So far, no suggestion has worked. The closest working suggestion was OnoSendai's suggestion, but apparently it's not allowed to create MonoBehaviour using "new".
Edit2: Making the boolean static didn't work at first, but then I realized that I had to make some changes in my camera script as well, so it works now, but Philip said that it's a bad advice - I personally have no idea why, I assume that it's something like using !important in CSS, you just use it as a last resort because it makes the code not that flexible - so I'm still open to ideas.
You may want to try a full reference to the CameraLock property based on the object instance - as in
var objRef = new IsTriggerLockCamera(); // Just an example of object reference -
// You may already have one
// on your code.
if (objRef.CameraLock) {
Debug.Log ("Im locked");
}
That happens because CameraLock is marked as public, but not as static - it only exists on a instantiated object.
If your camera needs access to the IsTriggerLockCamera then dependency injection is good way to make it clear :
class Camera{
private readonly IsTriggerLockCamera _locker;
public Camera(IsTriggerLockCamera locker){
if (locker== null)
{
throw new ArgumentNullException("locker");
}
_locker = locker;
}
public void whatevermethod(){
if (_locker.CameraLock){
...
}
}
}
You need to set the variable you want to access from other scripts, static as well as public.
using UnityEngine;
using System.Collections;
public class IsTriggerLockCamera : MonoBehaviour {
public static bool CameraLock = false;
public void OnTriggerStay2D(Collider2D other) {
CameraLock = true;
Debug.Log ("Im inside");
}
public void OnTriggerExit2D(Collider2D other) {
CameraLock = false;
Debug.Log ("I exited");
}
}
Then you can access CameraLock :
if (CameraLock == true) {
Debug.Log ("Im locked");
}
I would like to suggest some approach,
Make CameraLock variable as protected.
Create a new class and make IsTriggerLockCamera class as base class.
consume the CameraLock variable and work on it.
Thanks,
C# has a function called { get; set } that you can use with a variable
This program is an example
Static Type
public static class AYO
{
public static string Variable1 { get; set; }
}
public class B
{
public void LOL()
{
string foo;
AYO.Variable1 = "Variable is now set";
foo = AYO.Variable1;
Console.WriteLine(foo);
}
}
Non Static
public class AYO
{
public string Variable1 { get; set; }
}
public class B
{
AYO ayo = new AYO();
public void LOL()
{
string foo;
ayo.Variable1 = "Variable is now set";
foo = ayo.Variable1;
Console.WriteLine(foo);
}
}

Categories