feat(ui): 小人立体感批+素材路径共识(2026-09-26 用户二裁/立约):①棋盘小人 1.5× 档(HERO_SPRITE_SCALE 1.0→1.5,明示裁决压 §8.2 一般规则——豁免注记归 art-bible 批)+脚锚落格高 75% 线(HERO_GROUND_FRAC,「脚踩格子 1/4 处·自底边量」——不完全居中+头越上格沿造立体,锚点与缩放解耦);②脚下椭圆影=Godot 组件合成(GradientTexture2D 径向渐变×黑色 modulate 压扁,挂英雄子件 z=-1 随父同步位移/翻转/弹跳,LINEAR 保渐变平滑,贴图零改动)+英雄/影补挂 use_parent_material(结算期随世界去饱和与格面同口径——基批漏挂补齐);③素材路径分工约定 design/art/asset-path-map.md 落盘(candidates=源档禁运行时引用/game-assets-art=唯一落地处/ui-icons=已入库特例/mockups=评审产物;素材流五步+禁 preload+基准朝向/锚点备查);④ui_input_probe case⑦ 期望值随脚锚公式换挡;冒烟 557/0+三探针绿
This commit is contained in:
1 parent
ce9c2c15d7
commit
6cbb3a566f
4 files changed
+85
-20
No files matched your search
@@ -0,0 +1,35 @@
|
||||
# 素材路径分工约定(asset-path-map)
|
||||
|
||||
- 定立:2026-09-26(用户立约指令「把哪些路径、哪些位置是干什么的确定好」——台账 161)
|
||||
- 效力:全仓素材批的路径判据单点;新素材批开工前对照,违例=实施缺陷
|
||||
|
||||
## 1. 目录分工总表
|
||||
|
||||
| 路径 | 角色 | 入 git | 游戏运行时引用 |
|
||||
|---|---|---|---|
|
||||
| `design/art/candidates/**` | 设计侧源档(母版 PNG/.pxo/GIF/对比图/验收留底)——**素材的原产地与档案库,游戏禁直接引用** | 否(`.gitignore` 三行规则;`*.md` 指引例外) | **禁**(res:// 路径禁指 candidates) |
|
||||
| `game/assets/art/**` | **游戏运行时素材唯一落地处**(res://assets/art/...)——定稿素材从 candidates 拷贝入此,改名按圣经 §8.3 | 否(untracked,勿 git add;worktree 间需脚本拷贝同步) | **唯一合法引用源** |
|
||||
| `game/assets/ui/icons/**` | UI 图标(状态图标批特例——唯一已提交入 git 的素材目录) | **是**(2026-09-24 批特例) | 是 |
|
||||
| `production/mockups/**` | 混合样张/版式对比图(设计评审产物,非游戏素材) | 否 | 禁 |
|
||||
|
||||
## 2. 素材流(新素材批标准路径)
|
||||
|
||||
1. **产出/候选**:candidates 对应子目录(如 `hero-idle/`)
|
||||
2. **验收定稿**:用户拍板(候选目录留档不动)
|
||||
3. **入包**:拷贝 → `game/assets/art/<语义子目录>/`,改名 `§8.3` 域键式(如 `character_hero_portrait.png`)
|
||||
4. **接线**:代码 `res://assets/art/...` 引用(路径常量单点归 `UiKit.TEX_*`);装载一律 `UiKit.load_tex`(exists 守卫——素材不入 git,缺位树回退),**禁 preload**
|
||||
5. **提交**:只提交代码/文档;PNG 与 `.import`(全局忽略)均不入 git
|
||||
|
||||
## 3. game/assets/art 语义子目录
|
||||
|
||||
| 子目录 | 内容 | 现役 |
|
||||
|---|---|---|
|
||||
| `character/` | 角色棋盘帧 + B 区立绘 | character_hero_idle/walk(棋盘 32×32 朝左基准)、character_hero_portrait(B 区立绘 48×48) |
|
||||
| `fx/` | 特效帧 | shovel_swing_f0/f1/f2(挥铲三帧,握把锚 (18,12)) |
|
||||
| `board/` | 砖面/墙/地板(beast-cave 复用包,地砖复用批) | board_floor/wall/pillar_dungeon_* |
|
||||
|
||||
## 4. 坐标/朝向等工程侧约定备查
|
||||
|
||||
- 素材基准朝向:角色/铲帧一律朝**左**入库,右向=运行时 `flip_h`(镜像帧不入包,right 变体留 candidates)
|
||||
- 挥铲握把锚:画布 (18,12)(三帧同位——以手为圆心旋转的预烤相位)
|
||||
- 缩放纪律:圣经 §8.2 整数缩放为一般规则;棋盘小人 1.5× 系 2026-09-26 用户明示裁决(豁免注记归 art-bible 批另落)
|
||||
@@ -57,14 +57,17 @@ const DEPTH_BEVEL := 0.6 # 顶面倒角强度
|
||||
|
||||
# 英雄单位演出参数(棋盘小人贴图批 2026-09-25——计划书 §3.B/C 时长档)
|
||||
const HERO_FRAME_PX := 32.0 # 英雄帧画布边长(素材 32×32 锁定——缩放比分母)
|
||||
const HERO_SPRITE_SCALE := 1.0 # 整数 1× 档、32×32 盒格内居中(2026-09-25 用户裁决:不要求覆盖
|
||||
# 格子——圣经 §8.2「禁非整数缩放」硬规则,v1.9 注记 45px 格 1× 占
|
||||
# ≈71% 合规;格边 <32 板溢出 ≤(32−cell)px 接受;计划书原 cell_edge/32
|
||||
# 填充公式作废)
|
||||
const HERO_SPRITE_SCALE := 1.5 # 1.5× 档(2026-09-26 用户二裁:实机看 1× 偏小放大 1.5 倍——明示
|
||||
# 裁决压圣经 §8.2「禁非整数缩放」一般规则,§8.2 豁免注记归 art-bible
|
||||
# 批另落;头可越格上沿不裁剪)
|
||||
const HERO_GROUND_FRAC := 0.75 # 脚锚纵向落点 = 格高 75%(自格顶起;即「脚在格子 1/4 处」自底边量——
|
||||
# 2026-09-26 用户裁决:不完全居中、脚踩 1/4 线,头越上格沿造立体感)
|
||||
const HERO_MOVE_S := 0.14 # 位移时长(~140ms)
|
||||
const HERO_STEP_S := 0.18 # 走路帧周期 = 原地撞墙帧闪时长(~180ms)
|
||||
const HERO_DIG_S := 0.15 # 挖掘弹跳总时长(~150ms,半程压半程回)
|
||||
const HERO_BOUNCE := 0.82 # 弹跳压缩比(scale.y 1→0.82→1 脚底收敛)
|
||||
const HERO_SHADOW_PX := Vector2(32, 12) # 脚下椭圆影屏幕尺寸(Godot 组件合成——径向渐变纹理压扁,
|
||||
# 贴图零改动,2026-09-26 用户裁决走引擎侧)
|
||||
|
||||
var _wrap: CenterContainer
|
||||
var _svp_container: SubViewportContainer
|
||||
@@ -254,7 +257,7 @@ func _update_hero(hero: Vector2i) -> void:
|
||||
if _hero_tex_idle == null:
|
||||
return
|
||||
if _world.hero == null:
|
||||
var sp: Sprite2D = _world.ensure_hero(_hero_tex_idle)
|
||||
var sp: Sprite2D = _world.ensure_hero(_hero_tex_idle, HERO_SHADOW_PX, HERO_SPRITE_SCALE)
|
||||
sp.scale = Vector2.ONE * HERO_SPRITE_SCALE
|
||||
sp.position = _hero_feet(hero)
|
||||
_hero_last = hero # 首建/随 rebuild 重建——即时落位无演出
|
||||
@@ -339,18 +342,21 @@ func cell_origin(c: Vector2i) -> Vector2:
|
||||
return _svp_container.position + Vector2(c) * (_cell + float(SEP))
|
||||
|
||||
|
||||
# 英雄 32×32 盒格内居中的脚底锚点——**世界坐标**(精灵在 SubViewport 世界内:格原点 = 格×步距,
|
||||
# 禁带壳层居中偏移。2026-09-26 修正:上批误用壳层 cell_origin(含 _svp_container.position 居中
|
||||
# 偏移)定位世界内精灵,实测整体右偏 ~7 格+偏离格心——实机截图用户报缺陷)
|
||||
# 英雄脚底锚点——**世界坐标**(精灵在 SubViewport 世界内:格原点 = 格×步距,禁带壳层居中偏移。
|
||||
# 2026-09-26 修正:上批误用壳层 cell_origin(含 _svp_container.position 居中偏移)定位世界内精灵,
|
||||
# 实测整体右偏 ~7 格+偏离格心——实机截图用户报缺陷)。
|
||||
# 纵向 = 格高 75% 线(脚踩格子 1/4 处·自底边量——2026-09-26 用户二裁);横向格中线。身体向上延伸,
|
||||
# 头越上格沿不裁剪(立体感裁决);锚点与精灵缩放解耦(缩放只改身体向上长多少)。
|
||||
func _hero_feet(c: Vector2i) -> Vector2:
|
||||
var m := (_cell - HERO_FRAME_PX) * 0.5
|
||||
return Vector2(c) * (_cell + float(SEP)) + Vector2(m + HERO_FRAME_PX * 0.5, m + HERO_FRAME_PX)
|
||||
return Vector2(c) * (_cell + float(SEP)) + Vector2(_cell * 0.5, _cell * HERO_GROUND_FRAC)
|
||||
|
||||
|
||||
# 英雄持握手位(fx 同层坐标系 = 壳层坐标——fx 在 SubViewport 之外,须含 _svp_container.position
|
||||
# 居中偏移:世界脚底锚 + 壳层偏移即得)。手 = 盒底往上 1/4 盒高、水平居中(2026-09-25 用户裁决)
|
||||
# 居中偏移:世界脚底锚 + 壳层偏移即得)。手 = 盒底往上 1/4 盒高、水平居中(2026-09-25 用户裁决;
|
||||
# 盒高随 HERO_SPRITE_SCALE——手位钉在身体上不随缩放漂移)
|
||||
func hero_hand_point() -> Vector2:
|
||||
return _svp_container.position + _hero_feet(_hero_last) + Vector2(0.0, -HERO_FRAME_PX * 0.25)
|
||||
return _svp_container.position + _hero_feet(_hero_last) \
|
||||
+ Vector2(0.0, -HERO_FRAME_PX * 0.25 * HERO_SPRITE_SCALE)
|
||||
|
||||
|
||||
# 英雄精灵缩放档(fx 挥铲同档出口——两演出比例恒一致)
|
||||
|
||||
@@ -18,17 +18,42 @@ var hero: Sprite2D = null # 英雄单位精灵(棋盘小人贴图批 2026-
|
||||
|
||||
# 英雄精灵惰性创建(幂等):脚底锚(offset 上移半高——scale.y 弹跳向脚底收敛不悬空)+ z_index=1
|
||||
# 压格面之上(挥铲特效在 SubViewport 之外恒更上层,满足「格面之上、特效之下」叠序);NEAREST =
|
||||
# SubViewport 缩放下像素清晰(默认 Linear 会糊)。返回值便于 BoardView 即时落位。
|
||||
func ensure_hero(tex: Texture2D) -> Sprite2D:
|
||||
# SubViewport 缩放下像素清晰(默认 Linear 会糊);use_parent_material = 随世界去饱和材质灰化
|
||||
#(结算期与 CellUnit 同口径——基批漏挂,本批补齐)。返回值便于 BoardView 即时落位。
|
||||
# 脚下椭圆影(2026-09-26 用户裁决走 Godot 组件合成、贴图零改动):径向渐变纹理 ×黑色半透明
|
||||
# modulate 压扁,挂英雄子件(z_index=-1 相对回落格面之上、英雄之下——位移/翻转/弹跳随父件
|
||||
# 同步免费拿;尺寸换算归 BoardView.HERO_SHADOW_PX 常量)。纹理 filter 用 LINEAR 保渐变平滑
|
||||
#(NEAREST 会把渐变打回条带)。
|
||||
func ensure_hero(tex: Texture2D, shadow_px: Vector2, scale: float) -> Sprite2D:
|
||||
if hero != null:
|
||||
return hero
|
||||
var grad := Gradient.new()
|
||||
grad.set_color(0, Color(1, 1, 1, 1))
|
||||
grad.set_color(1, Color(1, 1, 1, 0))
|
||||
var shadow_tex := GradientTexture2D.new()
|
||||
shadow_tex.gradient = grad
|
||||
shadow_tex.width = 64
|
||||
shadow_tex.height = 64
|
||||
shadow_tex.fill = GradientTexture2D.FILL_RADIAL
|
||||
shadow_tex.fill_from = Vector2(0.5, 0.5)
|
||||
shadow_tex.fill_to = Vector2(0.5, 0.0)
|
||||
var shadow := Sprite2D.new()
|
||||
shadow.texture = shadow_tex
|
||||
shadow.modulate = Color(0, 0, 0, 0.35)
|
||||
shadow.texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR
|
||||
shadow.scale = shadow_px / (64.0 * scale) # 子件缩放叠父件 scale——目标屏幕尺寸 ÷ (纹理边 × 父档)
|
||||
shadow.position = Vector2(0.0, 2.0) # 脚线下 2px——贴地接触感
|
||||
shadow.z_index = -1 # 相对父件回落:格面(z=0 树序在先)之上、英雄本体之下
|
||||
shadow.use_parent_material = true # 随英雄链世界去饱和材质
|
||||
hero = Sprite2D.new()
|
||||
hero.texture = tex
|
||||
hero.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST
|
||||
hero.centered = true
|
||||
hero.offset = Vector2(0.0, -16.0) # 纹理中点上移半高——position = 脚底中点
|
||||
hero.z_index = 1
|
||||
hero.use_parent_material = true
|
||||
add_child(hero)
|
||||
hero.add_child(shadow)
|
||||
return hero
|
||||
|
||||
# ── 立体悬崖(BoardView.set_cell_area / _update_world_size 单点驱动;厚度定稿 8px=中档 2026-09-24)──
|
||||
|
||||
@@ -122,15 +122,14 @@ func _ready() -> void:
|
||||
if not ms.is_revealed(dig_t):
|
||||
_problems.append("case⑥ 核心揭格未落位(目标=%s)" % dig_t)
|
||||
# ---- case⑦ 英雄精灵世界落位(棋盘小人贴图批回归闸 2026-09-26):精灵在 SubViewport 世界内,
|
||||
# 落位 = 格×步距 + 居中脚底锚(禁带壳层 _svp_container.position 居中偏移——上批误用壳层
|
||||
# cell_origin 实测右偏 ~7 格+偏离格心,实机截图用户报缺陷)。素材缺位树(hero==null,
|
||||
# 字形「人」回退在役)跳过;断言前等 0.3s 墙钟——headless 帧率无上限,帧数等待 < 位移
|
||||
# Tween 140ms 时会采到半途位置(首跑实证),必须按墙钟等到位。 ----
|
||||
# 落位 = 格×步距 + 脚底锚(横=格中线/纵=格高 75% 线——2026-09-26 二裁「脚踩格子 1/4 处」;
|
||||
# 禁带壳层 _svp_container.position 居中偏移——上批误用壳层 cell_origin 实测右偏 ~7 格+偏离
|
||||
# 格心,实机截图用户报缺陷)。素材缺位树(hero==null,字形「人」回退在役)跳过;断言前等
|
||||
# 0.3s 墙钟——headless 帧率无上限,帧数等待 < 位移 Tween 140ms 时会采到半途位置(首跑实证)。 ----
|
||||
if bv._world.hero != null:
|
||||
await get_tree().create_timer(0.3).timeout
|
||||
var hm: float = (bv.cell_size - bv.HERO_FRAME_PX) * 0.5
|
||||
var expect: Vector2 = Vector2(ms.hero_pos()) * (bv.cell_size + float(bv.SEP)) \
|
||||
+ Vector2(hm + bv.HERO_FRAME_PX * 0.5, hm + bv.HERO_FRAME_PX)
|
||||
+ Vector2(bv.cell_size * 0.5, bv.cell_size * bv.HERO_GROUND_FRAC)
|
||||
if bv._world.hero.position.distance_to(expect) > 0.5:
|
||||
_problems.append("case⑦ 英雄精灵世界落位偏移 pos=%s expect=%s" % [str(bv._world.hero.position), str(expect)])
|
||||
if _problems.is_empty():
|
||||
|
||||
Reference in new issue
Block a user