2017-05-05 138 views
2

我想让网络代码与我的游戏逻辑分开。我不仅需要这样做才能在单人游戏模式和多人游戏模式之间共享游戏逻辑,我还希望能够分离关注事物。让Unity网络代码与游戏逻辑分开

我目前的做法是为我的网络相关类生成代码,使其具有在线和离线版本。我用T4模板做这个。

产生的阶级是这样的:

单机/单人版本:

// T4 GENERATED CODE 
// Head (Singleplayer version) 
class StandaloneHelloWorld : MonoBehaviour, IHelloWorld 
{ 
    private string name; 

    public void SayHello() 
    { 
     SayHelloInternal(); 
    } 

// Body 
    public string Name 
    { 
     get { return name; } 
     set { name = value; } 
    } 

    void SayHelloInternal() 
    { 
     Debug.Log(Name + ": Hello World"); 
    } 
} 

多人版本:

// T4 GENERATED CODE 
// Head (Multiplayer version) 
class NetworkedHelloWorld : NetworkBehaviour, IHelloWorld 
{ 
    [SyncVar] 
    private string name; 

    public void SayHello() 
    { 
     CmdSayHello(); 
    } 

    [Command] 
    void CmdSayHello() 
    { 
     RpcSayHello(); 
    } 

    [ClientRpc] 
    void RpcSayHello() 
    { 
     SayHelloInternal(); 
    } 

// Body 
    public string Name 
    { 
     get { return name; } 
     set { name = value; } 
    } 

    void SayHelloInternal() 
    { 
     Debug.Log(Name + ": Hello World"); 
    } 
} 

它们共用一个接口来隐藏从呼叫者的实现:

interface IHelloWorld 
{ 
    string Name { get; set; } 
    void SayHello(); 
} 

因此,您可以看到,两个实现使用相同的主体,共享大部分代码,而入口点取决于是否联网。 另请注意,这两个实现继承了不同的基类。

优点:

  • 单人代码具有朝向联网代码没有依赖关系和(手动保持没有具有至少)反之亦然
  • 无重复码

缺点:

  • Unity中对接口的支持是有限的。我无法从编辑器内部引用IHelloWorld的场景实例。
  • 用户必须为单人/多人游戏模式
  • 独立的预制件经与T4 /代码生成

你知道的更好的方法来处理这个染指?你是如何解决这个问题的?

回答

0

您可以以基于事件的方式构造代码。这将允许系统注册他们感兴趣的事件。这自然地将逻辑从网络代码中分离出来。

举一个例子,假设你想发射一颗子弹。 你可以通过调用火了:

new Event(EventType.FireProjectile, pos, dir, template)

然后,您可以注册一个有兴趣在此事件系统:

CollisionSystem.Register(EventType.FireProjectile, (e) => { 
    CollisionSystem.AddCollider(e.template.bounds); 
}); 

AudioSystem.Register(EventType.FireProjectile, (e) => { 
    AudioSystem.PlaySound("Woosh"); 
}); 

AISystem.Register(EventType.FireProjectile, (e) => { 
    AISystem.AlertAtPosition(e.pos); 
}); 

什么是酷接下来就是你可以将此事件向NetworkSystem注册将将其序列化,将其移动通过网络,将其反序列化,然后在客户机上将其烧掉。所以就客户而言,这个事件在当地被称为。

NetworkSystem.Register(EventType.FireProjectile, (e) => { 
    NetworkSystem.Broadcast(e, Channel.Reliable); 
}); 

这是相当不错的,只是你很快就会意识到这将导致无限循环的事件。当你向另一个客户端发送一个FireProjectile事件时,他们会捕获并释放它。他们的NetworkSystem立即捕获并通过网络触发它。

为了解决这个问题,你需要为每一个动作两个事件 - 一个请求:FireProjectile和响应:ProjectileFired

前段时间,我曾为一个个人项目使用过这样的代码库。它使用C++,但如果你有兴趣,你可以阅读更多here。注意服务器和客户端是如何注册某些事件的,他们会转发。