Reputation: 4249
I have a Game Manager, which is used to manage the execution order of specific Unity callbacks (FixedUpdate
, Update
and LateUpdate
) in all the other scripts.
Specifically, I wrote these 3 interfaces:
public interface IFixedAt {
bool IsActive { get; }
void FixedAt();
}
public interface IUpdateAt {
bool IsActive { get; }
void UpdateAt();
}
public interface ILateUpdateAt {
bool IsActive { get; }
void LateUpdateAt();
}
These interfaces are implemented in game objects' scripts, where needed, like this for example:
using UnityEngine;
using System.Collections;
public class NewBehaviourScript : MonoBehaviour, IUpdateAt, ILateUpdateAt {
[SerializeField]
bool isActive = true;
public bool IsActive {
get {
return (isActive && gameObject.activeInHierarchy);
}
}
public void UpdateAt() {
// Do stuff in Update
}
public void LateUpdateAt() {
// Do stuff in Late Update
}
}
The Game Manager script gets at Awake the reference to all scripts which implement the interfaces, creating a List<Interface>
and then uses the list at runtime to execute the callbacks only where needed:
using UnityEngine;
using System.Collections.Generic;
public class GameManager : MonoBehaviour {
public List<GameObject> GameObjectsWithScripts;
List<IFixedAt> fixedAtList { get; set; }
List<IUpdateAt> updateAtList { get; set; }
List<ILateUpdateAt> lateUpdateAtList { get; set; }
private void Awake() {
PopulateAllLists();
}
private void FixedUpdate() {
if (fixedAtList != null) {
for (int i = 0; i < fixedAtList.Count; i++) {
if (fixedAtList[i].IsActive)
fixedAtList[i].FixedAt();
}
}
}
private void Update() {
if (updateAtList != null) {
for (int i = 0; i < updateAtList.Count; i++) {
if (updateAtList[i].IsActive)
updateAtList[i].UpdateAt();
}
}
}
private void LateUpdate() {
if (lateUpdateAtList != null) {
for (int i = 0; i < lateUpdateAtList.Count; i++) {
if (lateUpdateAtList[i].IsActive)
lateUpdateAtList[i].LateUpdateAt();
}
}
}
void PopulateAllLists() {
fixedAtList = PopulateList<IFixedAt>(GameObjectsWithScripts);
updateAtList = PopulateList<IUpdateAt>(GameObjectsWithScripts);
lateUpdateAtList = PopulateList<ILateUpdateAt>(GameObjectsWithScripts);
}
List<T> PopulateList<T> (List<GameObject> goScripts) {
//Scans the GOs list and adds existent interface elements to the list
var list = new List<T>();
for (int i = 0; i < goScripts.Count; i++) {
if (goScripts[i].GetComponent<T>() != null) {
list.Add(goScripts[i].GetComponent<T>());
}
}
//Returns list (null if list is empty)
if (list.Count > 0) {
return list;
}
else {
return null;
}
}
}
Now, the question for which I'm having trouble in understanding if it's possible to do, and if yes, how.
As you can see, the code inside FixedUpdate
, Update
and LateUpdate
is basically the same: it iterates on the specific List
, checks if the current element is active, and if true it executes the proprietary callback.
What I want to know is if it's possible to create a generic method that can be called from inside the three callbacks, and passing to it the List
to iterate on and the specific method to call for that List
, something like this in pseudo-code:
private void FixedUpdate() {
Method (fixedAtList, FixedAt() );
}
private void Update() {
Method (updateAtList, UpdateAt() );
}
private void LateUpdate() {
Method (lateUpdateAtList, LateUpdateAt() );
}
private void Method<T> (List<T> list, Action method) {
if (list != null) {
for (int i = 0; i < list.Count; i++) {
if (list[i].IsActive)
list[i].method();
}
}
}
I've tried different things, to no success, and atm I'm clueless about how to do that. Any help will be very appreciated.
Upvotes: 0
Views: 88
Reputation: 32266
First you need an interface that covers the IsActive
method.
public interface IActive {
bool IsActive { get; }
}
public interface IFixedAt : IActive {
void FixedAt();
}
public interface IUpdateAt : IActive {
void UpdateAt();
}
public interface ILateUpdateAt : IActive {
void LateUpdateAt();
}
Then you need to use the generic Action<T>
and then you can pass in lambdas
private void FixedUpdate() {
Method (fixedAtList, f => f.FixedAt() );
}
private void Update() {
Method (updateAtList, u => u.UpdateAt() );
}
private void LateUpdate() {
Method (lateUpdateAtList, l => l.LateUpdateAt() );
}
private void Method<T> (List<T> list, Action<T> method) where T : IActive {
if (list != null) {
for (int i = 0; i < list.Count; i++) {
if (list[i].IsActive)
method(list[i]);
}
}
}
Upvotes: 3