2017-07-02 42 views
0

我有一个游戏管理器,它用于管理所有其他脚本中特定Unity回调(FixedUpdate,UpdateLateUpdate)的执行顺序。如何通过列表<Interface>和从另一个类实现的方法

具体来说,我写了这3个接口:

public interface IFixedAt { 
    bool IsActive { get; } 
    void FixedAt(); 
} 

public interface IUpdateAt { 
    bool IsActive { get; } 
    void UpdateAt(); 
} 

public interface ILateUpdateAt { 
    bool IsActive { get; } 
    void LateUpdateAt(); 
} 

这些接口在游戏对象的脚本,在需要的地方实现,像这样的例子:

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 
    } 
} 

的游戏管理器脚本获得的唤醒对实现接口的所有脚本的引用,创建一个List<Interface>,然后在运行时使用该列表仅在需要时执行回调:

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; 
     } 
    } 
} 

现在,我有什么麻烦了解是否有可能做的问题,如果是的话,如何。

正如你可以看到,里面FixedUpdateUpdateLateUpdate代码基本上是一样的:它遍历具体List,检查当前元素处于活动状态,如果为真则执行专有的回调。

我想知道的是,如果有可能创建一个通用的方法,可以从三个回调内部调用,并传递给它的List遍历和具体的方法来调用该List,这样的事情在伪代码:

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(); 
     } 
    } 
} 

我已经尝试过不同的事情,没有成功,并atm我很无知如何做到这一点。任何帮助将非常感激。

回答

3

首先您需要一个涵盖IsActive方法的接口。

public interface IActive { 
    bool IsActive { get; } 
} 

public interface IFixedAt : IActive { 
    void FixedAt(); 
} 

public interface IUpdateAt : IActive { 
    void UpdateAt(); 
} 

public interface ILateUpdateAt : IActive { 
    void LateUpdateAt(); 
} 

然后,你需要使用通用Action<T>,然后你可以在lambda表达式

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]); 
     } 
    } 
} 
+0

的解决方案是如此简单,我觉得愚蠢没有想到这一点,谢谢通过。 :>顺便说一句,为清楚起见,你使用'f','l'和'u'作为lambda参数,对吧?我可以在所有三个参数中使用'x',它的工作原理是一样的,还是在这个选择背后还有其他的东西? – Galandil

+1

您已为lambda表使用任何参数名称。我只是选择这些来匹配类/方法的第一个字母。 – juharr

相关问题