| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- #!/usr/bin/env python3
- """
- 996传奇客户端 LabelBatchNode / LabelBatchString 接口契约
- 来源: 二进制 LabelBatchNode / LabelBatchString 8 + 14 = 22 个 tolua 方法
- + cocos2d-x SpriteBatchNode / Label 文档对照
- 职责: 批量文本渲染 (伤害数字 / 血条 / 称号等高频文本)
- 原理: 所有 LabelBatchString 共享同一张字体纹理图集 (font atlas),
- 一次 draw call 渲染几百个文字 → 性能优于 Label × N
- 完整文档见 label_batch_doc.md (本目录)
- """
- from __future__ import annotations
- from dataclasses import dataclass, field
- from typing import Optional, List
- # ============== 二进制接口契约 (22 个 tolua 方法) ==============
- # class LabelBatchNode (8 方法)
- # create() - 静态创建, 返回节点指针
- # getFontAltas() - 获取共享字体图集
- # hasOutline() - 是否有描边
- # setAliasTexParameters() - 设置纹理抗锯齿 (默认就近)
- # refCameraFontScale() - 根据相机缩放调整字号
- # addLabelString(string_id) - 关联一个 string
- # createLabelString(text) - 创建 string 实例, 返回 id
- # removeLabelString(string_id) - 移除
- # destroyLabelString(string_id) - 销毁
- # class LabelBatchString (14 方法)
- # LabelBatchString(text) - 构造
- # cleanup() - 释放纹理引用
- # get/setColor / Opacity / LocalZ - 视觉属性
- # get/setPosition / ContentSize - 几何
- # get/setString / Alignment - 内容
- # isVisible() - 可见性
- # ============== 数据结构 (Python 等价, 纯数据) ==============
- @dataclass
- class LabelBatchString:
- """
- 单个文本单元 (对应 LabelBatchString C++ 类)
- 真实实现中会被编入 LabelBatchNode 的 VBO 批渲染
- """
- text: str = ""
- x: float = 0.0
- y: float = 0.0
- color: tuple = (255, 255, 255, 255) # RGBA
- opacity: int = 255
- local_z: int = 0
- visible: bool = True
- font_size: int = 14
- alignment: int = 0 # 0=left, 1=center, 2=right
- _id: int = field(default=0, init=False) # 由 LabelBatchNode 分配
- @dataclass
- class LabelBatchNode:
- """
- 批量文本节点 (对应 LabelBatchNode C++ 类)
- 一个 Node 实例可容纳多个 LabelBatchString, 共享一张字体图集
- """
- font_atlas_path: str = "" # 字体纹理图集路径
- has_outline: bool = False # 描边开关
- use_alias: bool = True # 纹理抗锯齿
- ref_camera_scale: bool = True # 是否随相机缩放
- strings: List[LabelBatchString] = field(default_factory=list)
- _next_id: int = 1
- def create(self) -> "LabelBatchNode":
- """LabelBatchNode:create() 等价 (静态工厂)"""
- return self
- def get_font_atlas(self) -> str:
- return self.font_atlas_path
- def has_outline_q(self) -> bool:
- return self.has_outline
- def set_alias_tex_parameters(self) -> None:
- """设置 GL_TEXTURE_MIN/MAG_FILTER 为 GL_LINEAR (替代默认 NEAREST)"""
- self.use_alias = True
- def ref_camera_font_scale(self) -> None:
- """当相机缩放变化时同步字号 (用于 720p/1080p 切换)"""
- self.ref_camera_scale = True
- def add_label_string(self, string: LabelBatchString) -> int:
- """addLabelString 关联一个 string 实例, 返回其 id"""
- string._id = self._next_id
- self._next_id += 1
- self.strings.append(string)
- return string._id
- def create_label_string(self, text: str) -> int:
- """createLabelString 内部创建并 add, 返回 id"""
- s = LabelBatchString(text=text)
- return self.add_label_string(s)
- def remove_label_string(self, sid: int) -> None:
- for s in self.strings:
- if s._id == sid:
- self.strings.remove(s)
- return
- def destroy_label_string(self, sid: int) -> None:
- self.remove_label_string(sid)
- # ============== 单元自测 ==============
- if __name__ == "__main__":
- print("=== LabelBatchNode 接口自测 ===")
- node = LabelBatchNode(font_atlas_path="fonts/arial_14.png")
- print(f" font_atlas: {node.get_font_atlas()}")
- print(f" has_outline: {node.has_outline_q()}")
- s1 = LabelBatchString(text="-100", x=100, y=200, color=(255, 80, 80, 255))
- s2 = LabelBatchString(text="+50", x=120, y=200, color=(80, 255, 80, 255))
- s3 = LabelBatchString(text="HP: 100/100", x=0, y=0)
- id1 = node.add_label_string(s1)
- id2 = node.add_label_string(s2)
- id3 = node.add_label_string(s3)
- print(f" created 3 strings: ids={id1}, {id2}, {id3}")
- print(f" total strings: {len(node.strings)}")
- # 模拟伤害数字更新
- s1.text = "-250"
- s1.color = (255, 50, 50, 255)
- print(f" updated s1: text={s1.text}, color={s1.color}")
- # 删除
- node.remove_label_string(id2)
- print(f" after remove id2: {len(node.strings)} strings left")
- # 真实实现: 一次 draw call 渲染所有 string
- # 实际 C++ 端把每个 string 编码成 6 顶点 (quad), 写进共享 VBO
- print(f"\n [实际 C++ 渲染]: batch.draw({len(node.strings)} strings)")
- print(f" [实际 GPU 调用]: 1 draw call + {len(node.strings) * 6} vertices")
|