Documentation
¶
Overview ¶
Package timeline 提供帧索引事件时间线原语,解决"逻辑计算瞬间完成、表现播放 需要时间"的表现与逻辑分离问题。
解决的问题:回合制/策略战斗中,服务器 1ms 算完"英雄 A 造成 500 伤害 → 目标 B 死亡 → 胜利结算",但客户端播放技能动画 + 受击特效 + 死亡动画需要 5 秒。如果 服务器算完就下一步,前端还在播第一步的动画;如果服务器硬等客户端播完,浪费资源 且容易被外挂利用。
框架方案:服务器一次算完所有结果,但打上**时间偏移**(offset ticks),组成一条 有序的事件时间线下发。客户端按时间线顺序消费,策划调整动画时长时不需要改服务端。
核心机制:
- Timeline[E]:事件时间线,事件按 offset(相对起始的帧偏移)排序;
- Append(offset, event):添加事件,可指定"在第 N 帧播放";
- After(prevDuration):自动累加偏移,实现"上一步播完后再开始下一步";
- Drain(tick):推进时间线到 tick,返回到期的事件(客户端消费);
- Snapshot():导出整条时间线(一次性下发给客户端)。
与相邻原语的关系:
- ability 管理"施法阶段"(蓄力→释放→命中),timeline 管理"计算结果的播放时序";
- delayqueue/timerqueue 是墙钟定时器(cron 任务、超时踢人),timeline 是游戏帧 时间线(战斗回放);
- eventbus 是发布-订阅(异步解耦),timeline 是有序时序(同步播放)。
并发安全:Timeline 不加锁(由单个计算 goroutine 构造,构造完后只读下发)。 零值可用:直接声明即可使用。
Index ¶
- type Entry
- type Player
- type Timeline
- func (t *Timeline[E]) After(duration int, event E)
- func (t *Timeline[E]) Append(offset int, event E)
- func (t *Timeline[E]) At(offset int, event E)
- func (t *Timeline[E]) Duration() int
- func (t *Timeline[E]) Len() int
- func (t *Timeline[E]) Snapshot() []Entry[E]
- func (t *Timeline[E]) Stagger(interval int, events ...E)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Entry ¶
type Entry[E any] struct { // Offset 相对时间线起始的帧偏移(tick 数)。0 = 立即生效。 Offset int // Event 事件内容(由业务定义:伤害结果、buff 变化、表现提示等)。 Event E }
Entry 是时间线上的一个事件条目。
type Player ¶
type Player[E any] struct { // contains filtered or unexported fields }
Player 按帧推进消费时间线事件(客户端侧或服务端延迟生效)。 非并发安全。
func NewPlayerFromEntries ¶
NewPlayerFromEntries 从已排序的条目列表创建播放器(如从网络反序列化)。
type Timeline ¶
type Timeline[E any] struct { // contains filtered or unexported fields }
Timeline 是一条帧索引事件时间线。E 是事件类型。 零值可用。构造完成后通常一次性下发客户端,或由 Player 逐帧消费。
func (*Timeline[E]) After ¶
After 在"当前累计偏移 + duration"处添加事件,并推进内部光标。 用于链式构造:"第一步 → 等 30 帧 → 第二步 → 等 20 帧 → 第三步"。
tl.After(0, hitA) // offset=0 tl.After(30, hitB) // offset=30 tl.After(20, victory) // offset=50