Files
mtgodot-poc/project/name_tail_layout.gd

151 lines
10 KiB
GDScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# name_tail_layout —— §8.8 seam ⑨ 收口:头顶名字尾标「有聊天气泡时上移贴气泡」1:1。
# CPythonTextTail::UpdateShowingTextTail 里,每条角色名字尾标投影完屏幕坐标后,
# 若该 VID 同时有一条 chat 尾标且 `pChatTail->bNameFlag`(= RegisterChatTail 注册的
# 「聊天」气泡,非 RegisterInfoTail 的「信息」气泡),就把名字尾标的屏幕 y 顶到
# `chatTail.y - 17.0f`(屏幕 y 向下,减 17px = 上移一行,正好贴在气泡上沿)。
# (与 name_color.gd / text_tail.gd / chat_tail.gd / name_show.gd / damage_effect.gd /
# target_board.gd / pick_show.gd 同一套纯静态镜像套路,本模块是第 28 个 canonical。)
#
# REF40250 ClientVS22 source/ 为唯一基线):
# UserInterface/PythonTextTail.cpp:19 const float c_TextTail_Name_Position = -10.0f
# UserInterface/PythonTextTail.cpp:509 RegisterCharacterTextTail(..., float fAddHeight=10.0f)
# :519 fHeight = GetHeight() + fAddHeight —— 名字尾标世界高=角色高 + 10
# UserInterface/PythonTextTail.cpp:581 RegisterChatTail:新建时 fHeight = GetHeight() + 10.0f、
# :603 / :618 pTextTail->bNameFlag = TRUE —— 「聊天」气泡(白)
# UserInterface/PythonTextTail.cpp:623 RegisterInfoTail:同高,
# :646 / :661 pTextTail->bNameFlag = FALSE —— 「信息」气泡(淡红),不顶名字
# UserInterface/PythonTextTail.cpp:88 UpdateShowingTextTail()
# :101 for (角色名字尾标 : m_CharacterTextTailList)
# :104 UpdateTextTail(pTextTail) —— 先投影出屏幕 x/y/z
# :106 itor = m_ChatTailMap.find(pTextTail->dwVirtualID)
# :110 if (m_ChatTailMap.end() != itor)
# :112 if (pChatTail->bNameFlag)
# :114 pTextTail->y = pChatTail->y - 17.0f —— 名字屏幕 y 顶到气泡上方 17px
# UserInterface/PythonTextTail.cpp:74 UpdateAllTextTail:同一个 bNameFlag 还驱动
# ShowCharacterTextTail(dwVID) 强显(增量 112/113 已接 chat_tail.gd / name_show.gd)。
# UserInterface/PythonTextTail.cpp:151 ArrangeTextTail()
# :211 for (pTextTail : m_CharacterTextTailList) —— 逐条角色名字尾标
# :228 pGuildNameInstance->SetPosition(x + iImageHalfSize, pTextTail->y - c_fyGuildNamePosition, z)
# :21 const float c_fyGuildNamePosition = 15.0f —— 公会名锚在名字 y 上方 15px
# :258 pTitle->SetPosition(x - iNameWidth/2 - fxAdd, pTextTail->y, z) —— 称号与名字同一行
# :283 pLevel->SetPosition(x - iNameWidth/2 - fxAdd - iTitleWidth, pTextTail->y, z) —— 等级同一行
# —— 公会名 / 称号 / 等级三个子标签的屏幕 y 全部取自 `pTextTail->y`,而这个 y 已在
# UpdateShowingTextTail :114 被聊天气泡顶过 -17。所以名字尾标一旦上移,子标签整体跟随。
#
# seam ⑨(已收口):参考端名字与气泡默认投影到同一世界点(GetHeight()+10),靠这条屏幕
# -17px 把名字从「和气泡重叠」顶成「贴气泡上沿」。poc 是每实体一个 billboard Label3D、
# 气泡默认在名字上方(局部 y 2.35 vs 2.1),本模块把屏幕 y 向下的 -17px 换成世界 y
# 向上的 +17px*pixel_size:有「聊天」气泡时名字世界 y 顶到气泡 y 之上 17px,气泡消失
# (或只是「信息」气泡)时回默认 y。像素 vs 世界的换算按名字 Label3D 的 pixel_size
# 与参考的字体无关常量 17 对齐。
# seam ⑦(部分收口 · 增量 119):子标签(GuildTag/TitleTag/LevelTag)随名字尾标纵向位移
# 已 1:1name_tail_lift_delta / subtag_world_y:名字上移多少子标签整体上移多少)。
# seam ⑦(水平排版 · 增量 121):ArrangeTextTail 角色块(PythonTextTail.cpp:211-320)非
# EUROPE 分支的逐像素水平排布也已 1:1(下方 name_x_shift / title_x_offset /
# level_x_offset / guild_name_x_offset / mark_x_offset / subtag_world_x):
# :236 fxAdd = 0 —— 无称号无等级
# :242 if (pTitle) fxAdd = 8.0f
# :258 pTitle->SetPosition(x - iNameWidth/2 - fxAdd, y, z) (称号,居中对齐)
# :263 if (pLevel) —— 有称号时等级在称号左侧
# :282 pLevel->SetPosition(x - iNameWidth/2 - fxAdd - iTitleWidth, y, z)(等级,右对齐)
# :288 else fxAdd = 4.0f —— 只有等级
# :312 pLevel->SetPosition(x - iNameWidth/2 - fxAdd, y, z)
# :320 pTextInstance->SetPosition(x + fxAdd, y, z) —— 名字本身右移 fxAdd
# :224 iImageHalfSize = pMarkInstance->GetWidth()/2 + c_fxMarkPosition(1.5)
# :227 pMarkInstance->SetPosition(x - guildW/2 - iImageHalfSize, y - c_fyMarkPosition(26))
# :228 pGuildNameInstance->SetPosition(x + iImageHalfSize, y - c_fyGuildNamePosition(15), z)
# —— 公会名的水平锚点只在「有公会徽记 pMarkInstance」时才被 ArrangeTextTail 改写。
# 仍近似(seam ⑦ 遗留):① poc 无公会徽记 mark 实体 —— 参考端 :220 的
# `if (pMarkInstance && pGuildNameInstance)` 不成立时公会名水平锚点不动,poc 亦让
# GuildTag 留在名字中线正上方(x 偏移 0),不做 +markW/2+1.5;② 文本宽度 poc 用
# 「字符数 * 约 7px」估,参考端是 GetTextSize 精确像素;③ 三子标签竖排 vs 参考同一
# 水平行(poc 3D billboard 里三条挤在一行会互相糊,保留竖排换 x 偏移的折衷)。
extends RefCounted
# PythonTextTail.cpp:114 的 `17.0f`。屏幕坐标下是「名字 y 减 17」(上移一行贴气泡)。
const NAME_OFFSET_ABOVE_BUBBLE_PX := 17.0
# PythonTextTail.cpp:21 的 `c_fyGuildNamePosition = 15.0f`:参考端公会名锚在名字尾标
# 屏幕 y 上方 15px(称号 / 等级则与名字同一行)。poc 竖排近似不用它做像素排版,仅作
# 1:1 记录——子标签真正跟随的是「名字尾标位移量」,见 subtag_world_y。
const GUILD_NAME_ABOVE_NAME_PX := 15.0
# UpdateShowingTextTail :110 `m_ChatTailMap.end() != itor` && :112 `pChatTail->bNameFlag`。
# has_chat_tail —— 该 VID 在 m_ChatTailMap 里有一条(聊天或信息);
# chat_name_flag —— 那条的 bNameFlagRegisterChatTail=TRUE / RegisterInfoTail=FALSE)。
static func name_follows_bubble(has_chat_tail: bool, chat_name_flag: bool) -> bool:
return has_chat_tail and chat_name_flag
# 参考端字面公式(屏幕坐标,y 向下):follows 时 `pChatTail->y - 17.0f`,否则名字投影原值。
static func name_tail_screen_y(default_y: float, bubble_y: float, follows: bool) -> float:
if follows:
return bubble_y - NAME_OFFSET_ABOVE_BUBBLE_PX
return default_y
# poc 3D 适配(世界坐标,y 向上):屏幕的 -17px 变成 +17px*pixel_size —— follows 时名字
# 世界 y 顶到气泡世界 y 之上 17 个名字像素,否则回默认世界 y。
static func name_tail_world_y(default_world_y: float, bubble_world_y: float,
follows: bool, px_size: float) -> float:
if follows:
return bubble_world_y + NAME_OFFSET_ABOVE_BUBBLE_PX * px_size
return default_world_y
# 名字尾标相对默认世界 y 的位移量(follows 时 = 顶到气泡上方后的净上移,否则 0)。
# ArrangeTextTail 里公会名 / 称号 / 等级都锚在 pTextTail->y 上,位移量就是子标签要跟随的量。
static func name_tail_lift_delta(default_world_y: float, bubble_world_y: float,
follows: bool, px_size: float) -> float:
return name_tail_world_y(default_world_y, bubble_world_y, follows, px_size) - default_world_y
# ArrangeTextTail :228 / :258 / :283:子标签屏幕 y 取自 pTextTail->y(已被聊天气泡顶过)。
# poc 里子标签各有自己的默认局部 y(竖排近似),名字尾标上移 lift_delta 时三者整体加同一段。
static func subtag_world_y(default_subtag_y: float, name_tail_lift_delta: float) -> float:
return default_subtag_y + name_tail_lift_delta
# --- seam ⑦ 水平排版(ArrangeTextTail 角色块,PythonTextTail.cpp:211-320 非 EUROPE 分支)---
# :242 `fxAdd = 8.0f`if pTitle)。屏幕像素,名字锚点 x 与三子标签公用。
const NAME_X_ADD_TITLE := 8.0
# :288 `fxAdd = 4.0f`else,只有等级)。
const NAME_X_ADD_LEVEL_ONLY := 4.0
# :20 `const float c_fxMarkPosition = 1.5f`。
const MARK_X_PAD := 1.5
# :22 `const float c_fyMarkPosition = 15.0f + 11.0f`。公会徽记锚在名字 y 上方 26px。
const MARK_ABOVE_NAME_PX := 26.0
# :320 `pTextInstance->SetPosition(pTextTail->x + fxAdd, ...)`:名字本身相对锚点右移 fxAdd。
# 有称号 -> 8;无称号只有等级 -> 4;都没有 -> 0。
static func name_x_shift(has_title: bool, has_level: bool) -> float:
if has_title:
return NAME_X_ADD_TITLE
if has_level:
return NAME_X_ADD_LEVEL_ONLY
return 0.0
# :258 `pTitle->SetPosition(pTextTail->x - (iNameWidth/2) - fxAdd, ...)`fxAdd = 8)。
# 返回称号中心相对名字锚点 x 的像素偏移(负 = 在名字左侧)。
static func title_x_offset(name_w: float) -> float:
return -(name_w / 2.0) - NAME_X_ADD_TITLE
# 等级相对名字锚点 x 的像素偏移(右对齐实例,故这是其右边缘位置):
# 有称号(:282fxAdd = 8):x - iNameWidth/2 - 8 - iTitleWidth —— 再往称号左边挪一个称号宽;
# 只有等级(:312fxAdd = 4):x - iNameWidth/2 - 4。
static func level_x_offset(name_w: float, title_w: float, has_title: bool) -> float:
if has_title:
return -(name_w / 2.0) - NAME_X_ADD_TITLE - title_w
return -(name_w / 2.0) - NAME_X_ADD_LEVEL_ONLY
# :224/:228 公会名中心 = x + iImageHalfSizeiImageHalfSize = markW/2 + c_fxMarkPosition(1.5)。
# 仅在有公会徽记时 ArrangeTextTail 才改写公会名 x;无徽记(poc 现状)应传 mark_w = 0
# 并按「参考端此路不改写」处理(调用方直接留 0 偏移),此函数仅供有徽记时用。
static func guild_name_x_offset(mark_w: float) -> float:
return mark_w / 2.0 + MARK_X_PAD
# :227 徽记位置 = x - guildW/2 - iImageHalfSize(相对名字锚点 x 的像素偏移,负 = 左侧)。
static func mark_x_offset(guild_w: float, mark_w: float) -> float:
return -(guild_w / 2.0) - (mark_w / 2.0 + MARK_X_PAD)
# poc 3D 适配:参考端在屏幕像素空间摆位(+x 向右),poc 子标签是 billboard Label3D ——
# billboard 本地 +x 恒等于屏幕右,按该 Label3D 的 pixel_size 把像素偏移折成世界本地 x。
static func subtag_world_x(px_offset: float, px_size: float) -> float:
return px_offset * px_size