例如,假设我有一个附加了Manager脚本的GameObject A,开始时会生成x个附加了B脚本的GameObjects。
当脚本B的GameObject这样说时,脚本C的另一个GameObject应该会做某事。
问题是,这三个人最好的交流方式是什么?
很明显,脚本B只能调用脚本C,但是我觉得这种方法缺乏结构和组织。
脚本A也可以引用脚本C,脚本B可以告诉脚本A对脚本C进行操作。
我觉得我应该遵循某种规则,但是我还没有遇到。任何帮助深表感谢!
答案 0 :(得分:3)
很明显,脚本B可以调用脚本C,但是我感觉像这样 方法缺乏结构和组织。
是的。这就是GameObject.SendMessage
函数的用途。不幸的是,它很慢,我不推荐它,但是值得一提。
如果您有许多需要与其他对象进行通信的对象,请使用event
和delegate
来实现事件管理器。这是正确的方法。您可以找到完整的EventManager
实现here。
通过它,您可以通过以下方式向事件注册任意数量的功能:
EventManager.StartListening("jump", someFunction);
使用以下方法取消注册事件中的任何功能:
EventManager.StopListening("jump", someFunction);
从那里,您可以在侦听该事件的任何对象上调用该事件:
EventManager.TriggerEvent("jump");
答案 1 :(得分:2)
如果A已经具有对脚本C的引用,则可以在创建A时将此引用传递给B。因此,B可以与C通信,而无需经过A。
即
Script A:
// variables
public ScriptC c;
// methods
void SpawnB(){
// spawn B
B.setC(c); // B's variable for script C is passed in from A
}
Script B:
// variables
ScriptC c;
// methods
void setC(ScriptC v){
c = v;
}
类似的事情。
答案 2 :(得分:0)
您还可以使用不是特定于Unity的ID CustId CustName Status
1 a1 A 1
2 a1 A 2
3 a2 B 1
4 a3 B 1
5 a4 C 1
6 a4 C 2
7 a4 D 2
8 a6 E 1
委托。我喜欢为此使用静态类,但您也可以在现有的一个类中实现它(只要您使用Action
成员和方法)
例如
static
这使您的类完全独立(好吧,它们共享MyEvents类)并且易于模块化。
在脚本public static class MyEvents
{
public static event Action SomeEvent;
public static void InvokeSomeEvent()
{
// Make sure event is only invoked if someone is listening
if (SomeEvent == null) return;
SomeEvent.Invoke();
}
}
中添加“监听器”,例如
C
然后在脚本private void Start()
{
// It is save to remove a listener also if it wasn't there yet
// This makes sure you are not listening twice by accident
MyEvents.SomeEvent -= OnSomeEvent;
// Add the listener for that event
MyEvents.SomeEvent += OnSomeEvent;
}
private void OnSomeEvent ()
{
// Do something if SomeEvent is invoked
}
中的某个地方调用
B
因此MyEvents.InvokeSomeEvent();
类不必知道或关心谁监听该事件;它只是调用它并关心它自己的事。
另一方面,B
或(为事件添加侦听器的任何其他类)不必知道/关心调用来自何处;它只是处理它并执行其工作。
但是请注意,这也使调试变得更加困难,因为要知道调用的来源不再那么容易了;)
注意:您还可以将参数添加到C
中,例如
Action
在这种情况下,所有方法都必须同时实现该参数
public static event Action<int> SomeParameterEvent;
在public static InvokeSomeParameterEvent(int value)
{
if(SomeParameterAction == null) return;
SomeParameterEvent.Invoke(value);
}
(侦听器)中,您还必须接收参数
C
当然也可以使用// name can be changed
private void OnSomeParameterEvent(int value)
{
//...
}
B
然后您甚至可以更进一步地使用它,而不用值或引用传递完整的MyEvents.InvokeSomeParameterEvent(someInt);
方法作为参数。查看示例here
答案 3 :(得分:0)
如程序员所写,代表和事件通常用于通信。
为了获得更好的结构和组织性,我建议使用MVC模式或您喜欢的任何其他设计模式。在这里,您可以找到一个简单而强大的通知系统的Unity3D MVC实现的绝佳示例:
Unity with MVC by Eduardo Dias da Costa
在该示例中,您无需使用委托/事件进行通信,并且可以使一切井井有条。
引用的教程中使用的一些通信功能,以防不赞成使用该链接:
1。
// Iterates all Controllers and delegates the notification data
// This method can easily be found because every class is “BounceElement” and has an “app”
// instance.
public void Notify(string p_event_path, Object p_target, params object[] p_data)
{
BounceController[] controller_list = GetAllControllers();
foreach(BounceController c in controller_list)
{
c.OnNotification(p_event_path,p_target,p_data);
}
}
// Fetches all scene Controllers.
public BounceController[] GetAllControllers() { /* ... */ }
2。
// This class will give static access to the events strings.
class BounceNotification
{
static public string BallHitGround = “ball.hit.ground”;
static public string GameComplete = “game.complete”;
/* ... */
static public string GameStart = “game.start”;
static public string SceneLoad = “scene.load”;
/* ... */
}
3。
// Handles the ball hit event
public void OnNotification(string p_event_path,Object p_target,params object[] p_data)
{
switch(p_event_path)
{
case BounceNotification.BallHitGround:
app.model.bounces++;
Debug.Log(“Bounce ”+app.model.bounce);
if(app.model.bounces >= app.model.winCondition)
{
app.view.ball.enabled = false;
app.view.ball.GetComponent<RigidBody>().isKinematic=true; // stops the ball
// Notify itself and other controllers possibly interested in the event
app.Notify(BounceNotification.GameComplete,this);
}
break;
case BounceNotification.GameComplete:
Debug.Log(“Victory!!”);
break;
}
}
4。
// Callback called upon collision.
void OnCollisionEnter() { app.Notify(BounceNotification.BallHitGround,this); }
当然,您仍然可以实现MVC并使用“委托和事件”。这只是显示另一种做事方式。