I'm learning OOP in Unity and i found game with code build with oop, the problem is that i can't figure out what does line "private bool IsInitialized => _bulletPool != null;" stand for.
I've read about lambda expression and as i understood its used like an UnityAction or for writing shorter functions.
using System;
using UnityEngine;
using UnityEngine.Events;
[RequireComponent(typeof(CapsuleCollider2D))]
[RequireComponent(typeof(ShipAudio))]
public abstract class Ship : MonoBehaviour
{
[SerializeField] private Vector2 _shootDirection;
private BulletPool _bulletPool;
protected CapsuleCollider2D Collider;
private bool IsInitialized => _bulletPool != null; //this line
public event UnityAction Shooted;
public event UnityAction TookDamage;
public event UnityAction Died;
private void Awake()
{
if (_shootDirection == Vector2.zero)
throw new ArgumentException(nameof(_shootDirection));
Collider = GetComponent<CapsuleCollider2D>();
Collider.isTrigger = true;
}
public void Init(BulletPool bulletPool)
{
_bulletPool = bulletPool;
}
public void TakeDamage()
{
OnTakeDamage();
TookDamage?.Invoke();
}
public void Die()
{
OnDie();
Died?.Invoke();
}
public void Shoot()
{
if (IsInitialized == false)
throw new Exception("Impossible to shoot. Bullet pool is not stated");
if (_bulletPool.TryGetObject(out Bullet bullet) == false)
throw new Exception("Impossible to spawn bullet");
bullet.Show();
bullet.transform.position = transform.position;
bullet.Init(_shootDirection);
Shooted?.Invoke();
}
protected abstract void OnTakeDamage();
protected abstract void OnDie();
}
It's a shortcut syntax for a function or property getter.
private bool IsInitialized => _bulletPool != null;
Does exactly the same thing as this.
private bool IsInitialized
{
get
{
return _bulletPool != null;
}
}
It is not lambda expression it is expression bodied property. Basically it is equivalent for:
private bool IsInitialized
{
get
{
return _bulletPool != null;
}
}
You can see the decompilation #sharplab yourself.
See more - Expression-bodied members.
In my opinion, a lambda expression is a shorter version of conditional statements. In the code, the condition is bulletpool!=null.
Since the result is true/false, the resulted value is assigned to the IsInitialized bool.
Hope you understand
Related
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.
I have a ObjectController script that looking for game objects and adding them to an array and another script that draws outline around those game objects. There're few tasks that I'm trying to achieve:
From ObjectController script List array I want to check what object is currently selected (clicked) so i won't be able to select (click) on other objects.
onMouseButtonDown(1) i want to clear selections (outline) from those objects.
Can you please guide me in the right direction?
I'm new to coding so please, go easy on me :D
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class ObjectController : MonoBehaviour
{
public List<SpriteOutline> objects;
private void Start()
{
List<SpriteOutline> objectList = FindObjectsOfType<SpriteOutline>().ToList<SpriteOutline>();
for (int i = 0; i < objectList.Count; i++)
{
objects.Add(objectList[i]);
}
}
public List<SpriteOutline> GetList()
{
return objects;
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
public class SpriteOutline : MonoBehaviour {
public Color OutlineColor = Color.white;
private Color _currentColor = Color.clear;
[Range(0, 16)]
public int outlineSize = 1;
private bool clicked = false;
private SpriteRenderer spriteRenderer;
ObjectController objController;
IEnumerator Start()
{
objController = GameObject.Find("ObjectController").GetComponent<ObjectController>();
yield return new WaitForEndOfFrame();
for (int i = 0; i < objController.GetList().Count; i++)
{
Debug.Log(i);
}
}
void OnEnable() {
spriteRenderer = GetComponent<SpriteRenderer>();
UpdateOutline(true);
}
void OnDisable() {
UpdateOutline(false);
}
void Update() {
UpdateOutline(true);
onMouseDown();
}
private void onMouseDown()
{
Vector3 mousePos;
mousePos = Input.mousePosition;
mousePos = Camera.main.ScreenToWorldPoint(mousePos);
CapsuleCollider2D coll = GetComponent<CapsuleCollider2D>();
if (Input.GetMouseButtonDown(0))
{
if (coll.OverlapPoint(mousePos))
{
_currentColor = Color.clear;
if (!clicked)
{
_currentColor = OutlineColor;
clicked = true;
}
else
{
clicked = false;
}
}
}
if (Input.GetMouseButtonDown(1))
{
_currentColor = Color.clear;
}
}
void UpdateOutline(bool outline) {
MaterialPropertyBlock mpb = new MaterialPropertyBlock();
spriteRenderer.GetPropertyBlock(mpb);
mpb.SetFloat("_Outline", outline ? 1f : 0);
mpb.SetColor("_OutlineColor", _currentColor);
mpb.SetFloat("_OutlineSize", outlineSize);
spriteRenderer.SetPropertyBlock(mpb);
}
}
hatebin
hatebin
A bit strange for me that you go through a controller class just to again find all instances of the actual class ;)
First you could simplify your code a lot:
public class ObjectController : MonoBehaviour
{
// The list is already public so no need to have a getter method ...
public List<SpriteOutline> objects;
private void Start()
{
// FindObjectsOfType returns an SpriteOutline[]
// so the easiest way of converting it to a list is
objects = FindObjectsOfType<SpriteOutline>().ToList();
}
}
Then you would later simply do
FindObjectOfType<ObjectController>().objects
However this isn't even necessary!
Instead of this manager/Singleton pattern here I would rather use a static and let your object instances register themselves and let your class handle it completely itself:
public class SpriteOutline : MonoBehaviour
{
[SerializeField] private Color OutlineColor = Color.white;
[SerializeField] [Range(0, 16)] private int outlineSize = 1;
[SerializeField] private SpriteRenderer _spriteRenderer;
// Here you actually register and unregisters instances
private static readonly List<SpriteOutline> _instances = new List<SpriteOutline>();
// If even needed public read-only access
public ReadOnlyCollection<SpriteOutline> Instances => _instances.AsReadOnly();
// The current selection
private static readonly HashSet<SpriteOutline> _currentSelection = new HashSet<SpriteOutline>();
// Again if needed a public read-only access
public static HashSet<SpriteOutline> CurrentSelection => new HashSet<SpriteOutline>(_currentSelection);
// backing field for storing the actual value of selected
private bool _isSelected;
// Property which additionally updates the outline when changed
public bool IsSelected
{
get => _isSelected;
set
{
if(value == _isSelected) return;
_isSelected = value;
if(value)
{
_currentSelection.Add(this);
}
else
{
_currentSelection.Remove(this);
}
UpdateOutline(enabled, value);
}
}
private void Awake()
{
if(!_spriteRenderer) _spriteRenderer = GetComponent<SpriteRenderer>();
// Register yourself
_instances.Add(this);
}
private void OnEnable()
{
UpdateOutline (true, _isSelected);
}
private void OnDisable()
{
UpdateOutline (false, _isSelected);
}
private void OnDestroy ()
{
// Unregister yourself
_instances.Remove(this);
if(_currentSelection.Contains(this)) _currentSelection.Remove(this);
}
// This simplifies your query a lot since this is anyway only called
// If the mouse is hovering the collider of this object
private void OnMouseDown()
{
// Toggle selection of this
if (Input.GetMouseButtonDown(0))
{
IsSelected = !IsSelected;
}
}
private void Update()
{
// Deselect this
if (Input.GetMouseButtonDown(1))
{
IsSelected = false;
}
}
void UpdateOutline(bool outline, bool selected)
{
var mpb = new MaterialPropertyBlock();
_spriteRenderer.GetPropertyBlock(mpb);
mpb.SetFloat("_Outline", outline ? 1f : 0);
mpb.SetColor("_OutlineColor", selected ? OutlineColor : Color.clear);
mpb.SetFloat("_OutlineSize", outlineSize);
spriteRenderer.SetPropertyBlock(mpb);
}
}
If you rather want to select only exactly one object at a time then I would exchange the HashSet<SpriteOutline> _currentSelection by something like
// The current selection
private static SpriteOutline _currentSelection;
// Again if needed a public read-only access
public static SpriteOutline CurrentSelection => _currentSelection;
accordingly change
public bool IsSelected
{
get => _isSelected;
set
{
if(value == _isSelected) return;
// assuming that if you set this via property it should
// overwrite the current selection
// otherwise you would here do
//if(_currentSelection && _currentSelection != this) return;
if(_currentSelection && _currentSelection != this) _currentSelection.IsSelected = false;
_isSelected = value;
_currentSelection = value ? this : null;
UpdateOutline(enabled, value);
}
}
and finally you wanted to block the input on objects that are not the selection:
private void OnMouseDown()
{
// Toggle selection of this
if (Input.GetMouseButtonDown(0))
{
if(_currentSelection && _currentSelection != this) return;
IsSelected = !IsSelected;
}
}
Note: Typed on smartphone but I hope the idea gets clear
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
I have TCP client (Unity c#) and server (WinForms app c#). I need my server sending some JSON commands, like this:
{ ""ObjName"": ""Cube_2"", ""Method"":""MoveLeft"", ""Delay"":0}
This certain command says to find GameObject "Cube_2" and fire method "MoveLeft".
When i recieve this from server, i convert it into my AOSCommand class:
public class AOSCommand
{
public string ObjName;
public string Method;
public int delay;
}
And then i do the following (which i think is not the best solution, so here is a question):
private void ProcessCommand(AOSCommand command)
{
GameObject cube = GameObject.Find(command.ObjName);
MonoBehaviour script = cube.GetComponent(command.ObjName.Split(new string[] {"_"}, StringSplitOptions.None)[0]) as MonoBehaviour;
script.Invoke(command.Method, command.delay);
}
How can i fire some method from AOSCommand.Method string in a better way?
The script attached to Cube_2 (and Cube_1 and may be attached to unknown count of other objects):
using UnityEngine;
public class Cube : MonoBehaviour {
private GameObject thisObj;
private void Start()
{
thisObj = this.gameObject;
}
public void MoveLeft()
{
thisObj.transform.Translate(new Vector3(1,0,0));
}
public void MoveRight()
{
thisObj.transform.Translate(new Vector3(-1, 0, 0));
}
}
It depends what you consider wrong.
You should have a single script that takes care of the parsing of the incoming data, this would remove the need to search for a component, it would always be the same.
Then you can have a dictionary of to replace the invoke call.
So your snippet turns into:
private void ProcessCommand(AOSCommand command)
{
GameObject cube = GameObject.Find(command.ObjName);
AOSDispatch dispatch = cube.GetComponent<AOSDispatch>()
if(dispatch == null){ return; } // or debug or exception
dispatch.Call(command);
}
this is on the main receiver. Then comes the script on the cubes:
public class AOSDispatch : MonoBehaviour
{
Dictionary<string, Action> dict;
void Start()
{
dict.Add("MoveLeft", MoveLeft);
dict.Add("MoveRight", MoveRight);
}
public void Call(AOSCommand command)
{
if(dict.Contains(command.Method) == false){ return; } //Or debug
// use the delay as well as you wish
dict[command.Method]();
}
private void MoveLeft(){}
private void MoveRight(){}
}
This is not necessarily better, just my two cents on it.
EDIT: there was comment mentioning the json could contain the script type to know what script to use. I would not go this way. AOSDispatch will take care of the dispatching of the message.
Message says MoveLeft, AOSDispatch can either treat the info or forward to a movement controller:
public class AOSDispatch : MonoBehaviour
{
[SerializeField] private MoveController moveCtrl = null;
Dictionary<string, Action> dict;
void Start()
{
dict.Add("MoveLeft", this.moveCtrl.MoveLeft);
dict.Add("MoveRight", this.moveCtrl.MoveRight);
}
public void Call(AOSCommand command)
{
if(dict.Contains(command.Method) == false){ return; } //Or debug
// use the delay as well as you wish
dict[command.Method]();
}
}
public class MoveController: MonoBehaviour
{
private void MoveLeft(){}
private void MoveRight(){}
}
there you go, message is forward and cleanly, the AOSDispatch does only the job it is meant to do, dispatch the AOS.
SECONDARY EDIT:
On second thought, here is an improved version.
Create a DispatchManager game object and add the following script:
public class AOSDispatch:MonoBehaviour
{
private IDictionary<string, AOSController> dict;
void Awake(){
this.dict = new Dictionary<string, AOSController>();
AOSController.RaiseCreation += ProcessCreation;
AOSController.RaiseDestruction += ProcessDestruction;
}
void OnDestroy()
{
AOSController.RaiseCreation -= ProcessCreation;
AOSController.RaiseDestruction -= ProcessDestruction;
}
private void ProcessCreation(AOSController controller){
this.dict.Add(controller.name, controller);
}
private void ProcessDestruction(AOSController controller){
AOSController temp= null;
if(this.dict.TryGetValue(controller.name, out temp) == true){
this.dict.Remove(name);
}
}
private void ProcessCommand(AOSCommand command)
{
AOSController controller = null;
if(this.dict.TryGetValue(command.ObjName, out controller) == true){
controller.Call(command);
return;
}
}
}
and then on the objects you have the AOSController that forwards the info as before (just renaming):
public class AOSController: MonoBehaviour
{
public static event Action<AOSController> RaiseCreation;
public static event Action<AOSController> RaiseDestruction;
[SerializeField] private MoveController moveCtrl = null;
Dictionary<string, Action> dict;
void Start()
{
if(RaiseCreation != null) { RaiseCreation(this); }
dict.Add("MoveLeft", this.moveCtrl.MoveLeft);
dict.Add("MoveRight", this.moveCtrl.MoveRight);
}
void OnDestroy()
{
if(RaiseDestruction != null) { RaiseDestruction(this); }
}
public void Call(AOSCommand command)
{
if(dict.Contains(command.Method) == false){ return; } //Or debug
// use the delay as well as you wish
dict[command.Method]();
}
}
public class MoveController: MonoBehaviour
{
private void MoveLeft(){}
private void MoveRight(){}
}
On Awake, the Dispatch registers to the static event from the AOSController. In the AOSController.Start, the object triggers the event and passes itself to the AOSDispatch. That one adds it to the dictionary. On destruction, the AOSDispatch gets the event and removes the AOSController.
Now you have a collection that at any given time contains all the AOSController in the scene.
As a result, you don't need to perform a GameObject.Find since you can get the object from the dictionary (real fast process).
I have been attempting to use event handling for a game's input. When seeing others use similar methods, they are able to add a void function to the delegate variable without an error.
Whenever I try to add the Move() function to OnAxisChange, I receive the following error:
Cannot implicitly convert type 'void' to 'CharacterView.InputAction'
public class CharacterView : MonoBehaviour {
public delegate void InputAction();
public static event InputAction OnAxisChange;
public Vector2 InputAxis
{
get
{
float x = Input.GetAxisRaw("Horizontal");
float y = Input.GetAxisRaw("Vertical");
return (new Vector2(x, y));
}
}
private void Update()
{
Vector2 input = InputAxis;
if (input.x != 0 || input.y != 0)
{
if (OnAxisChange != null)
{
OnAxisChange();
}
}
}
}
The following is the class that handles the event.
public class CharacterController : MonoBehaviour {
private void OnEnable()
{
CharacterView.OnAxisChange += Move();
}
private void OnDisable()
{
CharacterView.OnAxisChange -= Move();
}
public void Move()
{
Debug.Log("Entered the move function!");
}
}
Using delegates for event handling is still a bit foreign to me, so I assume I am misunderstanding something.
You need to remove () after Move. Like that you are calling your method and try to add the return type of it which is nothing. Just change it to the following.
CharacterView.OnAxisChange += Move;
CharacterView.OnAxisChange -= Move;