diff --git a/README.md b/README.md index 8fc8cb2..5e66281 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,32 @@ $ go get -u github.com/kercylan98/minotaur - 更多的 **[示例](./examples)** 参考可在 [examples](./examples) 目录查阅; - 项目文档可访问 **[pkg.go.dev](https://pkg.go.dev/github.com/kercylan98/minotaur)** 进行查阅; +### 本地文档 +可使用 `godoc` 搭建本地文档服务器 +#### 安装 godoc +```shell +git clone golang.org/x/tools +cd tools/cmd +go install ... +``` +#### 使用 `godoc` 启动本地文档服务器 +```shell +godoc -http=:9998 -play +``` +#### Windows +```shell +.\local-doc.bat +``` + +#### Linux or MacOS +```shell +chmod 777 ./local-doc.sh +./local-doc.sh +``` + +#### 文档地址 +**[http://localhost:9998/pkg/github.com/kercylan98/minotaur/](http://localhost:9998/pkg/github.com/kercylan98/minotaur/)** + ### 简单示例 创建一个基于Websocket的回响服务器。 ```go diff --git a/component/components/lockstep.go b/component/components/lockstep.go index 9df1c5b..4a98f69 100644 --- a/component/components/lockstep.go +++ b/component/components/lockstep.go @@ -34,6 +34,13 @@ func NewLockstep[ClientID comparable, Command any](options ...LockstepOption[Cli } // Lockstep 锁步(帧)同步默认实现 +// - 支持最大帧上限 WithLockstepFrameLimit +// - 自定逻辑帧频率,默认为每秒15帧(帧/66ms) WithLockstepFrameRate +// - 自定帧序列化方式 WithLockstepSerialization +// - 从特定帧开始追帧 +// - 兼容各种基于TCP/UDP/Unix的网络类型,可通过客户端实现其他网络类型同步 +// +// 可在 examples 目录下找到示例,示例项目:simple-server-lockstep type Lockstep[ClientID comparable, Command any] struct { clients *synchronization.Map[ClientID, component.LockstepClient[ClientID]] // 接受广播的客户端 frames *synchronization.Map[int, []Command] // 所有帧指令 @@ -73,6 +80,8 @@ func (slf *Lockstep[ClientID, Command]) LeaveClient(clientId ClientID) { } // StartBroadcast 开始广播 +// - 在开始广播后将持续按照设定的帧率进行帧数推进,并在每一帧推进时向客户端进行同步,需提前将客户端加入广播队列 JoinClient +// - 广播过程中使用 AddCommand 将该帧数据追加到当前帧中 func (slf *Lockstep[ClientID, Command]) StartBroadcast() { if slf.running.Swap(true) { return @@ -82,7 +91,7 @@ func (slf *Lockstep[ClientID, Command]) StartBroadcast() { slf.frameMutex.Lock() currentFrame := slf.currentFrame if slf.frameLimit > 0 && currentFrame >= slf.frameLimit { - slf.Stop() + slf.StopBroadcast() return } slf.currentFrame++ @@ -100,8 +109,8 @@ func (slf *Lockstep[ClientID, Command]) StartBroadcast() { }) } -// Stop 停止广播 -func (slf *Lockstep[ClientID, Command]) Stop() { +// StopBroadcast 停止广播 +func (slf *Lockstep[ClientID, Command]) StopBroadcast() { if !slf.running.Swap(false) { return } diff --git a/component/doc.go b/component/doc.go index bf58a33..e73bc0a 100644 --- a/component/doc.go +++ b/component/doc.go @@ -1,4 +1,4 @@ -// Package component 通用组件的接口定义 -// - lockstep.go 帧同步组件接口定义 -// - lockstep_client.go 帧同步组件客户端接口定义 +// Package component 定义了通用组件的接口 +// - lockstep.go:帧同步组件接口定义 +// - lockstep_client.go:帧同步组件客户端接口定义 package component diff --git a/component/lockstep.go b/component/lockstep.go index 854cc52..f43af88 100644 --- a/component/lockstep.go +++ b/component/lockstep.go @@ -1,6 +1,13 @@ package component -// Lockstep 帧同步组件接口定义 +// Lockstep 定义了帧同步组件的接口,用于处理客户端之间的同步操作。 +// 每个客户端需要拥有可比较的ID,同时需要定义帧数据的数据格式。 +// - ClientID:客户端ID类型 +// - Command:帧数据类型 +// +// 客户端ID类型通常为玩家ID类型,即通常将玩家作为帧同步客户端使用。 +// - 内置实现:components.Lockstep +// - 构建函数:components.NewLockstep type Lockstep[ClientID comparable, Command any] interface { // JoinClient 加入客户端 JoinClient(client LockstepClient[ClientID]) @@ -10,8 +17,8 @@ type Lockstep[ClientID comparable, Command any] interface { LeaveClient(clientId ClientID) // StartBroadcast 开始广播 StartBroadcast() - // Stop 停止广播 - Stop() + // StopBroadcast 停止广播 + StopBroadcast() // AddCommand 增加指令 AddCommand(command Command) // GetCurrentFrame 获取当前帧 diff --git a/examples/simple-server-lockstep/main.go b/examples/simple-server-lockstep/main.go index d9d7ddf..70fa992 100644 --- a/examples/simple-server-lockstep/main.go +++ b/examples/simple-server-lockstep/main.go @@ -33,7 +33,7 @@ func main() { players.Delete(conn.GetID()) lockstep.LeaveClient(conn.GetID()) if players.Size() == 0 { - lockstep.Stop() + lockstep.StopBroadcast() } }) srv.RegConnectionReceiveWebsocketPacketEvent(func(srv *server.Server, conn *server.Conn, packet []byte, messageType int) { diff --git a/game/actor.go b/game/actor.go index bac6c6f..2c4ddaa 100644 --- a/game/actor.go +++ b/game/actor.go @@ -1,6 +1,11 @@ package game -// Actor 表示游戏中的对象,具有唯一标识符 +// Actor 表示游戏中的可以放到游戏场景中的游戏对象的基本类型 +// - 需要注意 Actor 不等于 Player +// - 在 Minotaur 中,每个网络连接可以表示一个 Player,而每个玩家可以拥有多个 Actor +// - Actor 并非 Player 独有,场景中也可包含各类无主的 Actor +// - 内置实现:builtin.Actor +// - 构建函数:builtin.NewActor type Actor interface { // SetGuid 设置对象的唯一标识符 // - 需要注意的是该函数不应该主动执行,否则可能产生意想不到的情况 diff --git a/game/aoi2d.go b/game/aoi2d.go index 64f6ae9..d6421a5 100644 --- a/game/aoi2d.go +++ b/game/aoi2d.go @@ -1,6 +1,10 @@ package game -// AOI2D 感兴趣的领域(Area Of Interest)接口定义 +// AOI2D 基于2D定义的AOI功能接口 +// - AOI(Area Of Interest)翻译过来叫感兴趣的区域,是大型多人在线的游戏服务器中一个非常重要的基础模块,用于游戏对象在场景中的视野管理 +// - 透过 AOI 系统可以在其他玩家或怪物进入视野时得到感知,从而进行相应处理 +// - 内置实现:builtin.AOI2D +// - 构建函数:builtin.NewAOI2D type AOI2D interface { // AddEntity 添加对象 AddEntity(entity AOIEntity2D) diff --git a/game/aoi2d_entity.go b/game/aoi2d_entity.go index a8c2a44..debe2d8 100644 --- a/game/aoi2d_entity.go +++ b/game/aoi2d_entity.go @@ -1,5 +1,7 @@ package game +// AOIEntity2D 基于2D定义的AOI对象功能接口 +// - AOI 对象提供了 AOI 系统中常用的属性,诸如位置坐标和视野范围等 type AOIEntity2D interface { Actor // GetPosition 获取对象位置 diff --git a/game/attrs.go b/game/attrs.go index 23f637b..ce78d95 100644 --- a/game/attrs.go +++ b/game/attrs.go @@ -2,7 +2,8 @@ package game import "github.com/kercylan98/minotaur/utils/huge" -// Attrs 属性 +// Attrs 游戏属性接口定义 +// - 属性通常为直接读取配置,是否合理暂不清晰,目前不推荐使用 type Attrs interface { SetAttrInt(id int, value int) SetAttrInt8(id int, value int8) diff --git a/game/doc.go b/game/doc.go new file mode 100644 index 0000000..cd0c1df --- /dev/null +++ b/game/doc.go @@ -0,0 +1,10 @@ +// Package game 定义了通用游戏相关的接口 +// - actor.go:游戏通用对象接口定义 +// - aoi2d.go:基于2D的感兴趣领域(Area Of Interest)接口定义 +// - aoi2d_entity.go:基于2D的感兴趣领域(Area Of Interest)对象接口定义 +// - attrs.go:游戏属性接口定义,属性通常为直接读取配置,是否合理暂不清晰,目前不推荐使用 +// - fsm.go:有限状态机接口定义 +// - fsm_state.go:有限状态机状态接口定义 +// +// 其中 builtin 包内包含了内置的实现 +package game diff --git a/game/fsm.go b/game/fsm.go index c2a8e8b..ddacc01 100644 --- a/game/fsm.go +++ b/game/fsm.go @@ -1,10 +1,26 @@ package game -// FSM 有限状态机 +// FSM 有限状态机接口定义 +// - 有限状态机(Finite State Machine,简称FSM),它将系统看做一系列状态,而每个状态都有其对应的行为和转换条件 +// - 在游戏中,可以将各种游戏对象和游戏系统抽象为状态和转移,使用有限状态机来描述它们之间的关系,来实现游戏的逻辑和行为 +// +// 使用场景 +// - 角色行为控制:游戏角色的行为通常会根据不同状态来变化,例如走、跑、跳、攻击等。通过使用有限状态机来描述角色的状态和状态之间的转移,可以实现角色行为的流畅切换和控制 +// - NPC行为控制:游戏中的 NPC 通常需要有一定的 AI 行为,例如巡逻、追击、攻击等。通过使用有限状态机来描述 NPC 的行为状态和转移条件,可以实现 NPC 行为的智能控制 +// - 游戏流程控制:游戏的各个流程可以看做状态,例如登录、主界面、游戏场景等。通过使用有限状态机来描述游戏的流程状态和转移条件,可以实现游戏流程的控制和管理 +// +// 在服务端中使用 FSM 可以使游戏状态管理更加清晰和简单,清晰各状态职责 +// - 内置实现:builtin.FSM +// - 构建函数:builtin.NewFSM type FSM[State comparable, Data comparable] interface { + // Update 执行当前状态行为 Update() + // Register 注册一个状态到当前状态机中 Register(state FSMState[State, Data]) + // Unregister 取消一个状态的注册 Unregister(state State) + // HasState 检查是否某状态已注册 HasState(state State) bool + // Change 改变当前状态为输入的状态 Change(state State) } diff --git a/game/fsm_state.go b/game/fsm_state.go index 1de3a91..9bc2c73 100644 --- a/game/fsm_state.go +++ b/game/fsm_state.go @@ -6,10 +6,19 @@ type ( FSMStateExitHandle[Data any] func(data Data) ) -// FSMState 有限状态机状态 +// FSMState 有限状态机状态接口定义 +// - 描述了 FSM 中的状态行为 +// +// 需要一个可比较的状态类型及相应的数据类型,数据类型在无需使用时支持传入 nil +// - 内置实现:builtin.FSMState +// - 构建函数:builtin.NewFSMState type FSMState[State comparable, Data any] interface { + // GetState 获取当前状态 GetState() State + // Enter 状态开始行为 Enter(data Data) + // Update 当前状态行为 Update(data Data) + // Exit 状态退出行为 Exit(data Data) }