关于创建新类型桌游

关于创建新类型桌游#

在cpp中我们实现了基本的room,里面保存了人数、人员、房间设置的基本信息,客户端中与之相关的是房间内等待界面。游戏的进一步实际运行交给了服务端Lua、客户端Lua、该游戏实际页面。

我们可以把这些想象成桌游店:在游戏开始之前,只是一堆人坐在桌子周围,桌上有即将交给店主的本局游戏信息(至少是想玩哪种桌游)。人员集齐并决定开始游戏后,店主再把会用到的游戏配件送过来,具体怎么去玩就留给玩家自己了;在程序中还有一个“发牌员”般的存在负责发牌、记录数据、处理具体结算等。

因此,一种桌游应该有以下要素:

  • engine : 静态游戏配件

  • abstract_room_klass, player_klass : 发牌员需要记住的数据

  • logic_klass : 发牌员需要遵循的结算规则,即GameLogic

  • client_klass, room_page : 发牌员的“发牌”如何让客户端处理,即command+data

架构和API设计#

整体分析后,通用架构应该如下图:

@startuml
!theme plain

hide empty members
skinparam linetype ortho

package "Core" <<Frame>> {
  class Engine {
    内含该游戏需要的数据
    类似于桌游中固定配件的作用
    也可以什么也没有
    .. 例如一般可以有:..
    + packages
    + cards
  }

  abstract class RoomBase<T extends Player> {
    + int id
    + T[] players
    + getPlayer()
    + getBanner()
    + setBanner()
  }

  abstract class Player {
    + int id
    + getMark()
    + setMark()
  }

  abstract class GameLogicBase {
    + virtual run()
    + addTriggerSkill()
    + trigger()
    .. 事件相关 ..
    - resumeEvent()
    - ...()
  }

  Player -r-* RoomBase
  Player -l[hidden]- Engine
}

package "Server" <<Frame>> {
  class Room {
    - Cpp.Room
    - commonMethods(mixin)
    - callbacks
    + logic
  }

  interface RoomInterface {
    + resume()
    + checkNoHuman()
    + run()
    + delay()
    + gameOver()
    .. 询问支持相关 ..
    + Request:ask()
  }

  interface ServerPlayerInterface {
    + doNotify()
    + doRequest()
    + waitForReply()
    + kick()
    + thinking
    + died
  }

  class ServerPlayer {
    - Cpp.ServerPlayer
    - commonMethods(mixin)
    - AI -todo-
  }

  class GameLogic {
    + run()
    + ...()
  }

  Room -d-|> RoomBase: T = ServerPlayer
  ServerPlayer -d-|> Player
  ServerPlayer ..l..|> ServerPlayerInterface
  ServerPlayer -r-* Room
  Room ..r..|> RoomInterface
  GameLogic -l-* Room
  GameLogic --|> GameLogicBase
}

package "Client" <<Frame>> {
  class Client {
    - Cpp.Client
    - commonMethods(mixin)
    - callbacks
    - requestHandlers
  }

  class ClientPlayer {
    - Cpp.ClientPlayer
  }

  interface ClientInterface {
    + notifyUI()
    + sendDataToUI()
    .. Command回调 ..
    + chat()
    + ... 其他通用回调 ... ()
  }

  Client -u-|> RoomBase: T = ClientPlayer
  Client ..r..|> ClientInterface
  ClientPlayer -u-|> Player
  ClientPlayer -r-* Client
}

note right of Core
  Server负责
  1. 运行结算
  2. 处理client发来的reply
  3. 处理client发来的notify
  4. AI
  5. 其他通用功能
  ----
  Core负责
  1. 为Server和Client提供基类
  2. 定义若干该游戏需要的类
  3. 提供Engine管理游戏概念等
  ----
  Client负责
  1. 处理server发来的数据
  2. 向GUI发送相关信号
  3. 为部分GUI提供ui逻辑
  4. 其他通用功能
end note

@enduml

其中,用户应该要做以下的事情才能拓展自己的新桌游:

  • 派生Core中的Player和RoomBase类,增添数据成员

  • 定义一堆自己觉得有必要的类,然后派生Core中的Engine类来管理类以及实例

  • 派生自己的Player和RoomBase类,分别对应图中Client侧和Server侧

    • 派生后都需要include一下mixin来实现图中的接口,参见已有例子

  • 对于server侧,派生GameLogicBase,重写run()方法

  • 对于server侧,可以向Room中添加自己的API了

  • 对于client侧,向Client中编写若干新方法来处理自定义新command

  • 对于客户端,编写新QML页面作为游戏页面。详见“QML重构”篇

这份文档仍在试水中。也有一个试水的repo,详见 https://gitee.com/notify-ctrl/chess-games

欢迎提出建议