영웅 목록 신규 유닛 크기 = 기존 20종 기준에 맞춤 + 대기 그림 보는 방향 오른쪽 통일(#1108 · PD 2026-11-10)

PD: 「강유, 서황과 같이 새로 추가된 유닛의 크기가 이전에 제작된 유닛과 달리 큰 것 같아 · 이전에 유닛 크기를 조정한 기준에 맞게 크기나 위치도 조정」 · 「유닛의 기본 보는 방향을 오른쪽으로 통일」
- 원인: 크기 표가 눈 간격 하나 기준 → 새 그림은 투구·관이 커서 머리 덩어리가 커짐(카드 위 머리 폭 기존 202~283 · 신규 180~349)
- art_size.csv: lock 1 = PD 확인 기존 20종 크기 고정(기준점) · 신규 = 네 지표(눈 간격 · 얼굴 폭 · 머리 실루엣 폭 · 정수리 높이) 가운데 값 × adjust(영웅 목록 카드 시뮬레이션 눈 확인 · 78종) · Tools/unit_art_size.py 측정 추가
- 대기 그림 23종 좌우 반전(왼쪽 보던 유비·관우·제갈량·주유·곽가·장합·동탁·축융 등 · 눈 가운데 ↔ 머리 가운데 치우침 판정 + 눈 확인 · 피벗 = 프레임 가운데라 발 위치 그대로) · 출발·돌진은 원래 오른쪽
- 테스트(고친 부분만): UnitArt_SizeTable(크기 표 키 = 표준 키 · 기마 > 1.2 · lock 행) 1/1 · Lobby_Tabs_Back_ComingSoon 1/1 · error 0 · 캡처 hero_list

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
깃 관리자 2026-11-10 12:19:58 +09:00
parent 9718b99a00
commit 5edd87badb
26 changed files with 239 additions and 155 deletions

View File

@ -1,128 +1,128 @@
art,mounted,eye_px,body_px,size_px,note art,mounted,eye_px,face_px,head_px,crown_px,body_px,size_px,lock,adjust,note
cc_archer,0,125.1,744,736.3, cc_archer,0,125.1,250,444.0,249.0,744,736.3,1,,
cc_boss_bianxi,0,172.1,835,1013.0, cc_boss_bianxi,0,172.1,471,556.0,266.0,835,1010.0,,1.05,
cc_boss_caiyang,1,91.1,847,536.2, cc_boss_caiyang,1,91.1,184,352.0,198.0,847,556.4,,,
cc_boss_caocao,0,135.0,808,794.6, cc_boss_caocao,0,135.0,288,446.0,260.0,808,794.6,1,,
cc_boss_caohong,0,155.4,843,914.7, cc_boss_caohong,0,155.4,335,546.0,304.0,843,1013.1,,1.12,
cc_boss_caoren,0,148.1,829,871.7, cc_boss_caoren,0,148.1,303,519.0,282.0,829,984.4,,1.15,
cc_boss_chezhou,0,133.1,804,783.4, cc_boss_chezhou,0,133.1,304,424.0,249.0,804,772.1,,,
cc_boss_chunyudao,0,125.6,829,739.3, cc_boss_chunyudao,0,125.6,264,497.0,256.0,829,874.9,,1.15,
cc_boss_gaolan,0,119.4,772,702.8, cc_boss_gaolan,0,119.4,251,462.0,229.0,772,806.5,,1.15,
cc_boss_hanfu,0,131.8,815,775.8, cc_boss_hanfu,0,131.8,316,525.0,246.0,815,808.5,,,
cc_boss_kongxiu,0,159.0,875,935.8, cc_boss_kongxiu,0,159.0,326,725.0,317.0,875,1066.5,,1.12,
cc_boss_lidian,0,124.7,814,734.0, cc_boss_lidian,0,124.7,260,451.0,258.0,814,846.8,,1.15,
cc_boss_liudai,0,118.3,774,696.3, cc_boss_liudai,0,118.3,258,487.0,227.0,774,778.4,,1.12,
cc_boss_lvkuang,1,92.2,903,542.7, cc_boss_lvkuang,1,92.2,193,372.0,201.0,903,576.0,,,
cc_boss_lvxiang,1,89.7,863,528.0, cc_boss_lvxiang,1,89.7,185,340.0,202.0,863,542.5,,,
cc_boss_maojie,0,139.3,804,819.9, cc_boss_maojie,0,139.3,330,448.0,292.0,804,849.2,,,
cc_boss_mengtan,1,95.6,853,562.7, cc_boss_mengtan,1,95.6,185,363.0,204.0,853,578.7,,,
cc_boss_qinqi,0,122.5,814,721.0, cc_boss_qinqi,0,122.5,254,449.0,246.0,814,837.5,,1.15,
cc_boss_wangzhi,0,135.3,811,796.4, cc_boss_wangzhi,0,135.3,322,553.5,255.0,811,826.7,,,
cc_boss_wangzhong,0,125.2,783,736.9, cc_boss_wangzhong,0,125.2,269,450.0,247.0,783,847.6,,1.15,
cc_boss_xiahoudun,1,103.4,867,608.6,눈 수동 실측 2026-11-10: 왼눈 x 408.0 · 오른눈 = 수염 가운데 459.7 대칭 511.4(안대) cc_boss_xiahoudun,1,103.4,0,0,0,867,608.6,,,눈 수동 실측 2026-11-10: 왼눈 x 408.0 · 오른눈 = 수염 가운데 459.7 대칭 511.4(안대)
cc_boss_xiahouen,1,87.5,840,515.0, cc_boss_xiahouen,1,87.5,172,341.0,195.0,840,536.8,,,
cc_boss_xiahoujie,1,94.2,845,554.4, cc_boss_xiahoujie,1,94.2,182,369.0,217.0,845,579.5,,,
cc_boss_xuchu,0,154.9,854,911.7, cc_boss_xuchu,0,154.9,353,487.0,189.0,854,1008.6,,1.18,
cc_boss_xuhuang,0,151.7,805,892.9, cc_boss_xuhuang,0,151.7,319,763.0,321.0,805,1011.8,,1.08,
cc_boss_yanming,0,112.0,786,659.2, cc_boss_yanming,0,112.0,239,425.0,233.0,786,799.7,,1.18,
cc_boss_yujin,0,138.4,844,814.6, cc_boss_yujin,0,138.4,303,627.0,384.0,844,1059.0,,1.15,
cc_boss_zhanghe,0,112.3,853,661.0, cc_boss_zhanghe,0,112.3,228,477.0,235.0,853,793.0,,1.15,
cc_cavalry,1,91.9,849,540.9, cc_cavalry,1,91.9,186,346.0,193.0,849,540.9,1,,
cc_infantry,0,125.3,765,737.5, cc_infantry,0,125.3,252,444.0,253.0,765,737.5,1,,
cc_spear,0,124.1,785,730.4, cc_spear,0,124.1,255,481.0,243.0,785,730.4,1,,
chunyuqiong,1,96.0,917,565.0, chunyuqiong,1,96.0,190,411.0,191.0,917,620.3,,1.08,
dianwei,0,167.4,843,985.3, dianwei,0,167.4,413,551.0,269.0,843,1132.7,,1.2,
diaochan,0,158.2,911,931.1, diaochan,0,158.2,320,569.5,320.0,911,1006.6,,1.08,
dongxi,0,116.2,757,683.9, dongxi,0,116.2,245,437.5,220.0,757,759.5,,1.12,
dongzhuo,0,120.9,931,711.6, dongzhuo,0,120.9,448,517.0,442.0,931,1070.7,,1.05,
dz_archer,0,123.3,745,725.7, dz_archer,0,123.3,257,448.5,251.0,745,725.7,1,,
dz_boss_caoxing,0,140.7,804,828.1, dz_boss_caoxing,0,140.7,310,585.0,274.0,804,957.6,,1.15,
dz_boss_chengong,0,157.8,892,928.8, dz_boss_chengong,0,157.8,376,532.0,290.0,892,980.1,,1.08,
dz_boss_gaoshun,0,132.2,798,778.1, dz_boss_gaoshun,0,132.2,275,473.0,252.0,798,888.3,,1.15,
dz_boss_huaxiong,0,116.7,774,686.9, dz_boss_huaxiong,0,116.7,263,444.0,230.0,774,827.7,,1.18,
dz_boss_huzhen,1,87.5,836,515.0, dz_boss_huzhen,1,87.5,183,344.0,184.0,836,538.6,,,
dz_boss_lvbu,1,75.8,819,446.1, dz_boss_lvbu,1,75.8,173,387.5,123.0,819,446.1,1,,
dz_boss_zhangliao,1,95.7,876,563.3, dz_boss_zhangliao,1,95.7,203,430.0,197.0,876,582.6,,,
dz_cavalry,1,96.2,873,566.2, dz_cavalry,1,96.2,197,364.0,207.0,873,566.2,1,,
dz_infantry,0,139.1,844,818.7, dz_infantry,0,139.1,304,507.0,259.0,844,818.7,1,,
dz_spear,0,117.2,818,689.8, dz_spear,0,117.2,247,500.0,237.0,818,689.8,1,,
guanping,0,132.9,770,782.2, guanping,0,132.9,306,540.0,239.0,770,878.2,,1.1,
guanyu,0,122.7,725,722.2, guanyu,0,122.7,287,568.5,214.0,725,722.2,1,,
guojia,0,147.2,854,866.4, guojia,0,147.2,366,528.0,267.0,854,969.6,,1.12,
hanxuan,0,113.5,793,668.0, hanxuan,0,113.5,262,477.0,234.0,793,791.0,,1.12,
hgj_archer,0,154.7,833,910.5, hgj_archer,0,154.7,376,573.0,298.0,833,910.5,1,,
hgj_boss_chengyuanzhi,0,137.2,740,807.5, hgj_boss_chengyuanzhi,0,137.2,395,478.5,233.0,740,875.3,,1.1,
hgj_boss_dengmao,0,146.1,803,859.9, hgj_boss_dengmao,0,146.1,346,515.0,250.0,803,894.4,,1.05,
hgj_boss_guanhai,0,144.2,826,848.7, hgj_boss_guanhai,0,144.2,366,822.0,244.0,826,1075.6,,1.18,
hgj_boss_peiyuanshao,0,134.3,736,790.5, hgj_boss_peiyuanshao,0,134.3,304,531.0,273.0,736,903.9,,1.1,
hgj_boss_zhangbao,0,155.7,804,916.4, hgj_boss_zhangbao,0,155.7,371,548.0,258.0,804,907.1,,,
hgj_boss_zhangjiao,0,147.8,854,869.9, hgj_boss_zhangjiao,0,147.8,341,524.0,341.0,854,869.9,1,,
hgj_boss_zhangliang,0,160.1,882,942.3, hgj_boss_zhangliang,0,160.1,370,649.0,269.0,882,1108.2,,1.15,
hgj_cavalry,1,107.4,879,632.1, hgj_cavalry,1,107.4,242,439.0,214.0,879,632.1,1,,
hgj_infantry,0,161.5,850,950.6, hgj_infantry,0,161.5,387,660.0,292.0,850,950.6,1,,
hgj_spear,0,168.5,862,991.8, hgj_spear,0,168.5,377,584.5,293.0,862,991.8,1,,
huangzhong,0,148.8,797,875.8, huangzhong,0,148.8,394,503.0,230.0,797,875.8,1,,
jiangwei,0,114.2,804,672.2, jiangwei,0,114.2,245,481.0,230.0,804,790.6,,1.15,
jianyong,0,164.8,786,970.0, jianyong,0,164.8,367,515.0,257.0,786,906.8,,,
jiaxu,0,146.4,843,861.7, jiaxu,0,146.4,334,468.0,269.0,843,968.1,,1.15,
jinxuan,0,128.2,772,754.6, jinxuan,0,128.2,289,536.0,257.0,772,932.8,,1.2,
jz_boss_caimao,0,131.1,805,771.6, jz_boss_caimao,0,131.1,278,511.0,248.0,805,902.4,,1.18,
jz_boss_caixun,0,143.2,833,842.9, jz_boss_caixun,0,143.2,320,543.0,296.0,833,1027.4,,1.18,
jz_boss_caizhong,0,139.4,872,820.5, jz_boss_caizhong,0,139.4,324,509.0,276.0,872,1006.3,,1.2,
jz_boss_chensun,0,111.4,749,655.7, jz_boss_chensun,0,111.4,235,394.0,219.0,749,767.7,,1.18,
jz_boss_wenpin,0,117.1,822,689.2, jz_boss_wenpin,0,117.1,260,429.5,243.0,822,851.4,,1.22,
jz_boss_zhangwu,1,84.7,862,498.5, jz_boss_zhangwu,1,84.7,177,332.0,188.0,862,521.2,,,
jz_boss_zhangyun,0,139.5,871,821.1, jz_boss_zhangyun,0,139.5,298,515.0,277.0,871,998.8,,1.2,
lijue,1,93.4,901,549.7, lijue,1,93.4,182,384.0,185.0,901,557.5,,,
lingtong,0,139.3,853,819.9, lingtong,0,139.3,414,585.0,285.0,853,1006.1,,1.1,
liubei,0,142.2,752,837.0, liubei,0,142.2,373,478.0,243.0,752,837.0,1,,
liufeng,1,95.8,851,563.9, liufeng,1,95.8,192,364.0,202.0,851,580.1,,,
lusu,0,158.0,777,930.0, lusu,0,158.0,418,485.0,244.0,777,905.3,,1.05,
luxun,0,171.7,906,1010.6, luxun,0,171.7,379,519.5,304.0,906,968.9,,,
lvmeng,0,147.3,824,867.0, lvmeng,0,147.3,309,501.0,262.0,824,944.9,,1.15,
machao,1,85.6,845,503.8, machao,1,85.6,166,396.0,174.0,845,517.8,,,
menghuo,0,147.7,860,869.3, menghuo,0,147.7,332,735.0,363.0,860,1076.2,,1.08,
mizhu,0,153.5,800,903.5, mizhu,0,153.5,423,589.0,252.0,800,980.9,,1.05,
pangtong,0,163.8,800,964.1, pangtong,0,163.8,405,546.0,277.0,800,929.3,,,
shu_archer,0,148.5,803,874.0, shu_archer,0,148.5,324,554.0,304.0,803,1024.4,,1.15,
shu_cavalry,1,95.2,848,560.3, shu_cavalry,1,95.2,187,361.0,197.0,848,575.9,,,
shu_infantry,0,140.1,881,824.6, shu_infantry,0,140.1,309,524.0,287.0,881,993.0,,1.18,
shu_spear,0,116.3,807,684.5, shu_spear,0,116.3,263,519.0,243.0,807,851.2,,1.18,
shu_strategist,0,134.0,789,788.7, shu_strategist,0,134.0,328,460.0,251.0,789,816.7,,1.05,
sunce,1,96.1,907,565.6, sunce,1,96.1,192,345.0,195.0,907,565.4,,,
sunqian,0,151.7,838,892.9, sunqian,0,151.7,400,460.0,266.0,838,852.8,,,
sunquan,0,149.4,770,879.3, sunquan,0,149.4,339,535.0,220.0,770,921.8,,1.05,
sunshangxiang,0,132.8,676,781.6, sunshangxiang,0,132.8,281,550.0,236.0,676,764.8,,,
taishici,0,146.9,777,864.6, taishici,0,146.9,403,632.0,268.0,777,997.5,,1.05,
wanglang,0,137.5,809,809.3, wanglang,0,137.5,324,434.0,291.0,809,877.7,,1.05,
wei_boss_simayi,0,148.8,846,875.8, wei_boss_simayi,0,148.8,318,439.0,258.0,846,882.8,,1.08,
weiyan,0,127.7,764,751.6, weiyan,0,127.7,257,452.0,246.0,764,857.9,,1.15,
wu_chengpu,0,112.9,717,664.5, wu_chengpu,0,112.9,227,427.0,205.0,717,722.9,,1.12,
wu_ganning,0,146.9,887,864.6, wu_ganning,0,146.9,454,775.0,326.0,887,1102.3,,,
wu_huanggai,0,146.5,762,862.3, wu_huanggai,0,146.5,417,627.0,215.0,762,944.7,,,
wu_sunjian,0,171.2,876,1007.7, wu_sunjian,0,171.2,411,537.0,269.0,876,1056.9,,1.12,
wu_zhouyu,0,136.3,823,802.2, wu_zhouyu,0,136.3,328,449.5,244.0,823,812.6,,1.05,
xiahoumao,1,92.3,840,543.3, xiahoumao,1,92.3,188,361.0,213.0,840,567.3,,,
xiahouyuan,0,125.6,791,739.3, xiahouyuan,0,125.6,265,447.0,252.0,791,868.2,,1.18,
xiaoqiao,0,158.2,859,931.1, xiaoqiao,0,158.2,343,577.0,292.0,859,995.8,,1.08,
xunyu,0,142.0,853,835.8, xunyu,0,142.0,356,441.0,257.0,853,851.1,,1.05,
xushu,0,164.5,898,968.2, xushu,0,164.5,454,551.0,286.0,898,982.2,,1.05,
yanbaihu,0,174.8,923,1028.8, yanbaihu,0,174.8,388,669.0,330.0,923,1185.5,,1.15,
ys_boss_quyi,0,127.7,793,751.6, ys_boss_quyi,0,127.7,256,471.0,255.0,793,875.8,,1.15,
ys_boss_wenchou,1,88.3,913,519.7, ys_boss_wenchou,1,88.3,182,392.0,181.0,913,579.3,,1.08,
ys_boss_yanliang,0,120.4,755,708.7, ys_boss_yanliang,0,120.4,249,458.0,215.0,755,788.6,,1.15,
ys_gongsunzan,1,85.7,825,504.4, ys_gongsunzan,1,85.7,184,327.0,181.0,825,520.0,,,
ysu_boss_jiling,0,111.2,765,654.5, ysu_boss_jiling,0,111.2,232,401.0,208.0,765,761.2,,1.18,
ysu_boss_xunzheng,0,116.2,755,683.9, ysu_boss_xunzheng,0,116.2,234,439.0,215.0,755,750.9,,1.12,
yuanshao,0,131.8,822,775.8, yuanshao,0,131.8,275,520.0,250.0,822,846.8,,1.1,
yuanshu,0,154.9,879,911.7, yuanshu,0,154.9,384,515.0,208.0,879,965.5,,1.1,
zhangfei,1,106.3,917,625.7,눈 수동 실측 2026-11-10: 눈+눈썹 붙은 어두운 덩어리 중심 x 403.0 · 509.3(v5 재디자인 · 자동 = 말 콧구멍 오검출) zhangfei,1,106.3,0,0,0,917,625.7,1,,눈 수동 실측 2026-11-10: 눈+눈썹 붙은 어두운 덩어리 중심 x 403.0 · 509.3(v5 재디자인 · 자동 = 말 콧구멍 오검출)
zhanglu,0,158.9,926,935.3, zhanglu,0,158.9,371,490.0,284.0,926,991.7,,1.1,
zhangren,0,128.5,786,756.3, zhangren,0,128.5,271,464.5,258.0,786,872.4,,1.15,
zhaofan,0,134.6,798,792.2, zhaofan,0,134.6,373,441.0,264.0,798,839.4,,1.05,
zhaoyun,1,100.4,926,590.9, zhaoyun,1,100.4,199,393.0,192.0,926,590.9,1,,
zhoucang,0,173.3,856,1020.0, zhoucang,0,173.3,453,598.0,276.0,856,1149.8,,1.15,
zhoutai,0,162.2,885,954.7, zhoutai,0,162.2,429,599.5,273.0,885,1045.9,,1.08,
zhugejin,0,160.2,870,942.9, zhugejin,0,160.2,372,501.0,270.0,870,954.7,,1.08,
zhugeliang,0,140.2,886,825.2, zhugeliang,0,140.2,336,469.0,264.0,886,962.8,,1.18,
zhurong,0,118.3,773,696.3,눈 수동 실측 2026-11-10: 눈 덩어리 중심 x 524.4 · 642.7(짙은 피부 = 피부 판정 밖) zhurong,0,118.3,0,0,0,773,821.6,,1.18,눈 수동 실측 2026-11-10: 눈 덩어리 중심 x 524.4 · 642.7(짙은 피부 = 피부 판정 밖)

1 art mounted eye_px face_px head_px crown_px body_px size_px lock adjust note
2 cc_archer 0 125.1 250 444.0 249.0 744 736.3 1
3 cc_boss_bianxi 0 172.1 471 556.0 266.0 835 1013.0 1010.0 1.05
4 cc_boss_caiyang 1 91.1 184 352.0 198.0 847 536.2 556.4
5 cc_boss_caocao 0 135.0 288 446.0 260.0 808 794.6 1
6 cc_boss_caohong 0 155.4 335 546.0 304.0 843 914.7 1013.1 1.12
7 cc_boss_caoren 0 148.1 303 519.0 282.0 829 871.7 984.4 1.15
8 cc_boss_chezhou 0 133.1 304 424.0 249.0 804 783.4 772.1
9 cc_boss_chunyudao 0 125.6 264 497.0 256.0 829 739.3 874.9 1.15
10 cc_boss_gaolan 0 119.4 251 462.0 229.0 772 702.8 806.5 1.15
11 cc_boss_hanfu 0 131.8 316 525.0 246.0 815 775.8 808.5
12 cc_boss_kongxiu 0 159.0 326 725.0 317.0 875 935.8 1066.5 1.12
13 cc_boss_lidian 0 124.7 260 451.0 258.0 814 734.0 846.8 1.15
14 cc_boss_liudai 0 118.3 258 487.0 227.0 774 696.3 778.4 1.12
15 cc_boss_lvkuang 1 92.2 193 372.0 201.0 903 542.7 576.0
16 cc_boss_lvxiang 1 89.7 185 340.0 202.0 863 528.0 542.5
17 cc_boss_maojie 0 139.3 330 448.0 292.0 804 819.9 849.2
18 cc_boss_mengtan 1 95.6 185 363.0 204.0 853 562.7 578.7
19 cc_boss_qinqi 0 122.5 254 449.0 246.0 814 721.0 837.5 1.15
20 cc_boss_wangzhi 0 135.3 322 553.5 255.0 811 796.4 826.7
21 cc_boss_wangzhong 0 125.2 269 450.0 247.0 783 736.9 847.6 1.15
22 cc_boss_xiahoudun 1 103.4 0 0 0 867 608.6 눈 수동 실측 2026-11-10: 왼눈 x 408.0 · 오른눈 = 수염 가운데 459.7 대칭 511.4(안대)
23 cc_boss_xiahouen 1 87.5 172 341.0 195.0 840 515.0 536.8
24 cc_boss_xiahoujie 1 94.2 182 369.0 217.0 845 554.4 579.5
25 cc_boss_xuchu 0 154.9 353 487.0 189.0 854 911.7 1008.6 1.18
26 cc_boss_xuhuang 0 151.7 319 763.0 321.0 805 892.9 1011.8 1.08
27 cc_boss_yanming 0 112.0 239 425.0 233.0 786 659.2 799.7 1.18
28 cc_boss_yujin 0 138.4 303 627.0 384.0 844 814.6 1059.0 1.15
29 cc_boss_zhanghe 0 112.3 228 477.0 235.0 853 661.0 793.0 1.15
30 cc_cavalry 1 91.9 186 346.0 193.0 849 540.9 1
31 cc_infantry 0 125.3 252 444.0 253.0 765 737.5 1
32 cc_spear 0 124.1 255 481.0 243.0 785 730.4 1
33 chunyuqiong 1 96.0 190 411.0 191.0 917 565.0 620.3 1.08
34 dianwei 0 167.4 413 551.0 269.0 843 985.3 1132.7 1.2
35 diaochan 0 158.2 320 569.5 320.0 911 931.1 1006.6 1.08
36 dongxi 0 116.2 245 437.5 220.0 757 683.9 759.5 1.12
37 dongzhuo 0 120.9 448 517.0 442.0 931 711.6 1070.7 1.05
38 dz_archer 0 123.3 257 448.5 251.0 745 725.7 1
39 dz_boss_caoxing 0 140.7 310 585.0 274.0 804 828.1 957.6 1.15
40 dz_boss_chengong 0 157.8 376 532.0 290.0 892 928.8 980.1 1.08
41 dz_boss_gaoshun 0 132.2 275 473.0 252.0 798 778.1 888.3 1.15
42 dz_boss_huaxiong 0 116.7 263 444.0 230.0 774 686.9 827.7 1.18
43 dz_boss_huzhen 1 87.5 183 344.0 184.0 836 515.0 538.6
44 dz_boss_lvbu 1 75.8 173 387.5 123.0 819 446.1 1
45 dz_boss_zhangliao 1 95.7 203 430.0 197.0 876 563.3 582.6
46 dz_cavalry 1 96.2 197 364.0 207.0 873 566.2 1
47 dz_infantry 0 139.1 304 507.0 259.0 844 818.7 1
48 dz_spear 0 117.2 247 500.0 237.0 818 689.8 1
49 guanping 0 132.9 306 540.0 239.0 770 782.2 878.2 1.1
50 guanyu 0 122.7 287 568.5 214.0 725 722.2 1
51 guojia 0 147.2 366 528.0 267.0 854 866.4 969.6 1.12
52 hanxuan 0 113.5 262 477.0 234.0 793 668.0 791.0 1.12
53 hgj_archer 0 154.7 376 573.0 298.0 833 910.5 1
54 hgj_boss_chengyuanzhi 0 137.2 395 478.5 233.0 740 807.5 875.3 1.1
55 hgj_boss_dengmao 0 146.1 346 515.0 250.0 803 859.9 894.4 1.05
56 hgj_boss_guanhai 0 144.2 366 822.0 244.0 826 848.7 1075.6 1.18
57 hgj_boss_peiyuanshao 0 134.3 304 531.0 273.0 736 790.5 903.9 1.1
58 hgj_boss_zhangbao 0 155.7 371 548.0 258.0 804 916.4 907.1
59 hgj_boss_zhangjiao 0 147.8 341 524.0 341.0 854 869.9 1
60 hgj_boss_zhangliang 0 160.1 370 649.0 269.0 882 942.3 1108.2 1.15
61 hgj_cavalry 1 107.4 242 439.0 214.0 879 632.1 1
62 hgj_infantry 0 161.5 387 660.0 292.0 850 950.6 1
63 hgj_spear 0 168.5 377 584.5 293.0 862 991.8 1
64 huangzhong 0 148.8 394 503.0 230.0 797 875.8 1
65 jiangwei 0 114.2 245 481.0 230.0 804 672.2 790.6 1.15
66 jianyong 0 164.8 367 515.0 257.0 786 970.0 906.8
67 jiaxu 0 146.4 334 468.0 269.0 843 861.7 968.1 1.15
68 jinxuan 0 128.2 289 536.0 257.0 772 754.6 932.8 1.2
69 jz_boss_caimao 0 131.1 278 511.0 248.0 805 771.6 902.4 1.18
70 jz_boss_caixun 0 143.2 320 543.0 296.0 833 842.9 1027.4 1.18
71 jz_boss_caizhong 0 139.4 324 509.0 276.0 872 820.5 1006.3 1.2
72 jz_boss_chensun 0 111.4 235 394.0 219.0 749 655.7 767.7 1.18
73 jz_boss_wenpin 0 117.1 260 429.5 243.0 822 689.2 851.4 1.22
74 jz_boss_zhangwu 1 84.7 177 332.0 188.0 862 498.5 521.2
75 jz_boss_zhangyun 0 139.5 298 515.0 277.0 871 821.1 998.8 1.2
76 lijue 1 93.4 182 384.0 185.0 901 549.7 557.5
77 lingtong 0 139.3 414 585.0 285.0 853 819.9 1006.1 1.1
78 liubei 0 142.2 373 478.0 243.0 752 837.0 1
79 liufeng 1 95.8 192 364.0 202.0 851 563.9 580.1
80 lusu 0 158.0 418 485.0 244.0 777 930.0 905.3 1.05
81 luxun 0 171.7 379 519.5 304.0 906 1010.6 968.9
82 lvmeng 0 147.3 309 501.0 262.0 824 867.0 944.9 1.15
83 machao 1 85.6 166 396.0 174.0 845 503.8 517.8
84 menghuo 0 147.7 332 735.0 363.0 860 869.3 1076.2 1.08
85 mizhu 0 153.5 423 589.0 252.0 800 903.5 980.9 1.05
86 pangtong 0 163.8 405 546.0 277.0 800 964.1 929.3
87 shu_archer 0 148.5 324 554.0 304.0 803 874.0 1024.4 1.15
88 shu_cavalry 1 95.2 187 361.0 197.0 848 560.3 575.9
89 shu_infantry 0 140.1 309 524.0 287.0 881 824.6 993.0 1.18
90 shu_spear 0 116.3 263 519.0 243.0 807 684.5 851.2 1.18
91 shu_strategist 0 134.0 328 460.0 251.0 789 788.7 816.7 1.05
92 sunce 1 96.1 192 345.0 195.0 907 565.6 565.4
93 sunqian 0 151.7 400 460.0 266.0 838 892.9 852.8
94 sunquan 0 149.4 339 535.0 220.0 770 879.3 921.8 1.05
95 sunshangxiang 0 132.8 281 550.0 236.0 676 781.6 764.8
96 taishici 0 146.9 403 632.0 268.0 777 864.6 997.5 1.05
97 wanglang 0 137.5 324 434.0 291.0 809 809.3 877.7 1.05
98 wei_boss_simayi 0 148.8 318 439.0 258.0 846 875.8 882.8 1.08
99 weiyan 0 127.7 257 452.0 246.0 764 751.6 857.9 1.15
100 wu_chengpu 0 112.9 227 427.0 205.0 717 664.5 722.9 1.12
101 wu_ganning 0 146.9 454 775.0 326.0 887 864.6 1102.3
102 wu_huanggai 0 146.5 417 627.0 215.0 762 862.3 944.7
103 wu_sunjian 0 171.2 411 537.0 269.0 876 1007.7 1056.9 1.12
104 wu_zhouyu 0 136.3 328 449.5 244.0 823 802.2 812.6 1.05
105 xiahoumao 1 92.3 188 361.0 213.0 840 543.3 567.3
106 xiahouyuan 0 125.6 265 447.0 252.0 791 739.3 868.2 1.18
107 xiaoqiao 0 158.2 343 577.0 292.0 859 931.1 995.8 1.08
108 xunyu 0 142.0 356 441.0 257.0 853 835.8 851.1 1.05
109 xushu 0 164.5 454 551.0 286.0 898 968.2 982.2 1.05
110 yanbaihu 0 174.8 388 669.0 330.0 923 1028.8 1185.5 1.15
111 ys_boss_quyi 0 127.7 256 471.0 255.0 793 751.6 875.8 1.15
112 ys_boss_wenchou 1 88.3 182 392.0 181.0 913 519.7 579.3 1.08
113 ys_boss_yanliang 0 120.4 249 458.0 215.0 755 708.7 788.6 1.15
114 ys_gongsunzan 1 85.7 184 327.0 181.0 825 504.4 520.0
115 ysu_boss_jiling 0 111.2 232 401.0 208.0 765 654.5 761.2 1.18
116 ysu_boss_xunzheng 0 116.2 234 439.0 215.0 755 683.9 750.9 1.12
117 yuanshao 0 131.8 275 520.0 250.0 822 775.8 846.8 1.1
118 yuanshu 0 154.9 384 515.0 208.0 879 911.7 965.5 1.1
119 zhangfei 1 106.3 0 0 0 917 625.7 1 눈 수동 실측 2026-11-10: 눈+눈썹 붙은 어두운 덩어리 중심 x 403.0 · 509.3(v5 재디자인 · 자동 = 말 콧구멍 오검출)
120 zhanglu 0 158.9 371 490.0 284.0 926 935.3 991.7 1.1
121 zhangren 0 128.5 271 464.5 258.0 786 756.3 872.4 1.15
122 zhaofan 0 134.6 373 441.0 264.0 798 792.2 839.4 1.05
123 zhaoyun 1 100.4 199 393.0 192.0 926 590.9 1
124 zhoucang 0 173.3 453 598.0 276.0 856 1020.0 1149.8 1.15
125 zhoutai 0 162.2 429 599.5 273.0 885 954.7 1045.9 1.08
126 zhugejin 0 160.2 372 501.0 270.0 870 942.9 954.7 1.08
127 zhugeliang 0 140.2 336 469.0 264.0 886 825.2 962.8 1.18
128 zhurong 0 118.3 0 0 0 773 696.3 821.6 1.18 눈 수동 실측 2026-11-10: 눈 덩어리 중심 x 524.4 · 642.7(짙은 피부 = 피부 판정 밖)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 484 KiB

After

Width:  |  Height:  |  Size: 483 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 462 KiB

After

Width:  |  Height:  |  Size: 461 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 417 KiB

After

Width:  |  Height:  |  Size: 416 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 529 KiB

After

Width:  |  Height:  |  Size: 528 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 426 KiB

After

Width:  |  Height:  |  Size: 423 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 488 KiB

After

Width:  |  Height:  |  Size: 488 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 384 KiB

After

Width:  |  Height:  |  Size: 384 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 379 KiB

After

Width:  |  Height:  |  Size: 379 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 306 KiB

After

Width:  |  Height:  |  Size: 308 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 530 KiB

After

Width:  |  Height:  |  Size: 531 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 362 KiB

After

Width:  |  Height:  |  Size: 362 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 572 KiB

After

Width:  |  Height:  |  Size: 571 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 435 KiB

After

Width:  |  Height:  |  Size: 432 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 505 KiB

After

Width:  |  Height:  |  Size: 503 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 593 KiB

After

Width:  |  Height:  |  Size: 592 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 343 KiB

After

Width:  |  Height:  |  Size: 344 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 373 KiB

After

Width:  |  Height:  |  Size: 372 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 464 KiB

After

Width:  |  Height:  |  Size: 464 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 356 KiB

After

Width:  |  Height:  |  Size: 354 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 456 KiB

After

Width:  |  Height:  |  Size: 454 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 424 KiB

After

Width:  |  Height:  |  Size: 424 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 384 KiB

After

Width:  |  Height:  |  Size: 384 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 360 KiB

After

Width:  |  Height:  |  Size: 360 KiB

View File

@ -978,26 +978,29 @@ namespace TKS.Tests
[UnityTest] [UnityTest]
public IEnumerator UnitArt_SizeTable_SameHeadSize_MountedRiderLikeFoot() public IEnumerator UnitArt_SizeTable_SameHeadSize_MountedRiderLikeFoot()
{ {
// PD 2026-11-09 「캐릭터 크기 동일 · 말 탄 유닛도 보병·창병과 비슷한 비율」 — 크기 표(art_size.csv · 눈 간격 기준)로 배율을 정하면 // PD 2026-11-09 「캐릭터 크기 동일 · 말 탄 유닛도 보병·창병과 비슷한 비율」 + 2026-11-10 「새 유닛이 이전 유닛보다 크다 · 이전 기준에 맞게」 —
// 게임 안 눈 간격(월드)이 모든 유닛에서 같다 · 기마 유닛은 표준 키보다 커진다(탄 사람 = 보병 크기) // 크기 표(art_size.csv · lock 1 = PD 확인 기준 20종 고정 · 나머지 = 눈·얼굴·머리 폭·정수리 가운데 값 × adjust · Tools/unit_art_size.py)의
// size_px 가 모든 유닛에서 표준 키(월드)가 되도록 배율을 정한다 · 기마 유닛은 표준 키보다 커진다(탄 사람 = 보병 크기)
var ta = Resources.Load<TextAsset>(UnitArt.Root + UnitArt.SizeTable); var ta = Resources.Load<TextAsset>(UnitArt.Root + UnitArt.SizeTable);
Assert.IsNotNull(ta, "크기 표 Resources/Units/art_size.csv"); Assert.IsNotNull(ta, "크기 표 Resources/Units/art_size.csv");
var lines = ta.text.TrimStart('').Split('\n'); var lines = ta.text.TrimStart('').Split('\n');
var head = new List<string>(lines[0].Trim().Split(',')); var head = new List<string>(lines[0].Trim().Split(','));
int ia = head.IndexOf("art"), im = head.IndexOf("mounted"), ie = head.IndexOf("eye_px"); int ia = head.IndexOf("art"), im = head.IndexOf("mounted"), isz = head.IndexOf("size_px"), il = head.IndexOf("lock");
var eyes = new List<float>(); Assert.GreaterOrEqual(il, 0, "lock 열(PD 확인 기준 행)");
int mounted = 0; int rows = 0, mounted = 0, locked = 0;
var go = new GameObject("SizeProbe"); var go = new GameObject("SizeProbe");
var fa = go.AddComponent<FrameAnimator>(); var fa = go.AddComponent<FrameAnimator>();
for (int i = 1; i < lines.Length; i++) for (int i = 1; i < lines.Length; i++)
{ {
var c = lines[i].Trim().Split(','); var c = lines[i].Trim().Split(',');
if (c.Length <= ie) continue; if (c.Length <= Mathf.Max(isz, il)) continue;
var a = UnitArt.Load(c[ia]); var a = UnitArt.Load(c[ia]);
Assert.IsNotNull(a, "표의 아트 " + c[ia]); Assert.IsNotNull(a, "표의 아트 " + c[ia]);
Assert.Greater(a.SizePx, 0f, c[ia] + " size_px"); Assert.AreEqual(float.Parse(c[isz], System.Globalization.CultureInfo.InvariantCulture), a.SizePx, 0.01f, c[ia] + " size_px 읽음");
fa.Setup(a, cfg.unitArtHeight, 0); fa.Setup(a, cfg.unitArtHeight, 0);
eyes.Add(float.Parse(c[ie], System.Globalization.CultureInfo.InvariantCulture) / a.Meta.ppu * go.transform.localScale.x); Assert.AreEqual(cfg.unitArtHeight, a.SizePx / a.Meta.ppu * go.transform.localScale.x, 1e-3f, c[ia] + " 크기 표 키(월드) = 표준 키");
rows++;
if (c[il] == "1") locked++;
if (c[im] == "1") if (c[im] == "1")
{ {
mounted++; mounted++;
@ -1005,10 +1008,9 @@ namespace TKS.Tests
} }
} }
Object.Destroy(go); Object.Destroy(go);
Assert.GreaterOrEqual(eyes.Count, 15, "표 행 수"); Assert.GreaterOrEqual(rows, 15, "표 행 수");
Assert.GreaterOrEqual(mounted, 5, "기마 행 수"); Assert.GreaterOrEqual(mounted, 5, "기마 행 수");
eyes.Sort(); Assert.GreaterOrEqual(locked, 10, "PD 확인 기준 행(lock) 수");
Assert.Less(eyes[eyes.Count - 1] / eyes[0], 1.01f, "모든 유닛 눈 간격(월드) 같음");
// 배치된 기마 영웅 = HP 바 기준(ArtHeight)이 실제 머리 끝 // 배치된 기마 영웅 = HP 바 기준(ArtHeight)이 실제 머리 끝
yield return Fresh(); yield return Fresh();

View File

@ -1,12 +1,17 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""유닛 아트 크기 표 생성(PD 2026-11-09 「영웅 목록 캐릭터 크기 동일 · 말 탄 유닛도 보병·창병과 비슷한 비율」). """유닛 아트 크기 표 생성(PD 2026-11-09 「영웅 목록 캐릭터 크기 동일 · 말 탄 유닛도 보병·창병과 비슷한 비율」).
기준 = 눈 간격(머리 크기) — 투구·수염·말과 상관없이 같은 화풍이면 머리 크기에 비례한다. 기준(2026-11-10 개정 · PD 「새 유닛(강유·서황 등)이 이전 유닛보다 크다 · 이전에 유닛 크기를 조정한 기준에 맞게」)
eye_px = 대기 첫 프레임(front_idle/f000.png)의 두 눈 중심 사이 가로 px(얼굴 피부 덩어리 안 어두운 구멍 2개) eye_px = 대기 첫 프레임(front_idle/f000.png)의 두 눈 중심 사이 가로 px(얼굴 피부 덩어리 안 어두운 구멍 2개)
ref = 말을 타지 않은 유닛(mounted=0)의 eye_px / body_px 중앙값 face_px = 같은 눈 높이 행에서 얼굴 피부 덩어리(구멍 메움) 폭
size_px = eye_px / ref = 「머리 크기가 표준인 유닛의 키」로 환산한 세로 px head_px = 머리 실루엣 폭(투구·머리카락 포함 · 가는 무기는 열림 연산으로 뗌 · 눈~이마 행 중앙값)
게임(FrameAnimator)·영웅 목록은 bodyHeightPx 대신 size_px 로 배율을 정한다 → 모든 유닛의 머리 크기가 같아지고, crown_px = 정수리(가는 깃 제외)~눈 높이
말 탄 유닛은 탄 사람이 보병과 같은 크기가 되도록 커진다. lock 1 = PD 가 크기를 확인한 행(2026-11-09 기존 20종 · 눈 간격 기준) → size_px 고정 = 기준점
나머지 size_px = 가운데 값(eye_px × a, face_px × b, head_px × c, crown_px × d) × adjust
a~d = 기준점(걷는 유닛) size_px ÷ 각 지표 중앙값 · adjust = 영웅 목록 카드 시뮬레이션(기준 6종과 나란히) 눈 확인 보정(1.1 = 10 % 작게 · 사람이 적음)
(11-09 판 = eye_px 하나 → 새 그림은 투구·관이 커서 머리 덩어리가 커짐 → 네 지표 가운데 값 + 눈 확인 보정)
게임(FrameAnimator)·영웅 목록은 bodyHeightPx 대신 size_px 로 배율을 정한다 → 머리 덩어리 크기가 고르게 맞고,
말 탄 유닛은 탄 사람이 보병과 같은 크기가 되도록 커진다(게임 상한 = BalanceConfig.mountedArtMaxTop).
표 = Assets/Resources/Units/art_size.csv(utf-8-sig · SOT) · mounted = 게임 표(영웅·무장·병사)의 병종이 cavalry 면 1(art_types · 표 = Assets/Resources/Units/art_size.csv(utf-8-sig · SOT) · mounted = 게임 표(영웅·무장·병사)의 병종이 cavalry 면 1(art_types ·
표에 없는 아트만 기존 값 · 그것도 없으면 이름에 cavalry 면 1). 표에 없는 아트만 기존 값 · 그것도 없으면 이름에 cavalry 면 1).
@ -25,7 +30,61 @@ from PIL import Image, ImageDraw, ImageFont
from scipy import ndimage from scipy import ndimage
TABLE = 'Assets/Resources/Units/art_size.csv' TABLE = 'Assets/Resources/Units/art_size.csv'
FIELDS = ['art', 'mounted', 'eye_px', 'body_px', 'size_px', 'note'] FIELDS = ['art', 'mounted', 'eye_px', 'face_px', 'head_px', 'crown_px', 'body_px', 'size_px', 'lock', 'adjust', 'note']
def head_width(img, eyes):
"""(머리 실루엣 폭, 정수리~눈 높이) px — 창대 같은 가는 무기는 열림 연산(반지름 0.22 × 눈 간격)으로 떼어 내고,
폭 = 눈 높이 ~ 그 위 0.6 × 눈 간격 행들에서 눈 가운데를 품은 불투명 구간 폭의 중앙값 · 못 재면 (0, 0)."""
if not eyes:
return 0, 0
(_, lx, ly), (_, rx, ry) = eyes
E = rx - lx
y0, cx = int((ly + ry) / 2), int((lx + rx) / 2)
al = np.asarray(img.convert('RGBA'))[..., 3] > 128
r = max(2, int(E * 0.22))
yy, xx = np.ogrid[-r:r + 1, -r:r + 1]
al = ndimage.binary_opening(al, structure=(xx * xx + yy * yy) <= r * r)
def run(y):
row = al[y]
if not row[cx]:
return 0
l = q = cx
while l > 0 and row[l - 1]:
l -= 1
while q < len(row) - 1 and row[q + 1]:
q += 1
return q - l + 1
ws = [w for w in (run(y) for y in range(max(0, int(y0 - 0.6 * E)), y0 + 1, 2)) if w]
top = y0
for y in range(y0, -1, -1): # 정수리 = 눈에서 위로, 눈 가운데를 품은 구간 폭 ≥ 0.5 × 눈 간격 인 마지막 행(가는 깃·창끝 제외)
if run(y) < 0.5 * E:
break
top = y
return (round(float(np.median(ws)), 1) if ws else 0), float(y0 - top)
def face_width(img, eyes):
"""눈 높이 행에서 두 눈을 품은 얼굴 피부 덩어리(구멍 메움) 폭 px · 못 재면 0."""
if not eyes:
return 0
a = np.asarray(img.convert('RGBA')).astype(np.float32) / 255.0
(_, lx, ly), (_, rx, ry) = eyes
y, cx = int(round((ly + ry) / 2)), int(round((lx + rx) / 2))
sk = skin_mask(a, False)[0] | skin_mask(a, True)[0]
lab, n = ndimage.label(sk)
k = lab[y, cx]
for dx in range(1, int(rx - lx) + 1):
if k:
break
for xx in (cx - dx, cx + dx):
if 0 <= xx < lab.shape[1] and lab[y, xx]:
k = lab[y, xx]
break
if not k:
return 0
xs = np.where(ndimage.binary_fill_holes(lab == k)[y])[0]
return int(xs.max() - xs.min() + 1) if len(xs) else 0
def skin_mask(a, red): def skin_mask(a, red):
@ -135,26 +194,49 @@ def main():
eye = round(eyes[1][1] - eyes[0][1], 1) if eyes else 0 eye = round(eyes[1][1] - eyes[0][1], 1) if eyes else 0
if not eyes and prev.get('note', '').startswith('눈 수동') and float(prev.get('eye_px') or 0) > 0: if not eyes and prev.get('note', '').startswith('눈 수동') and float(prev.get('eye_px') or 0) > 0:
eye = float(prev['eye_px']) # 자동으로 못 찾는 그림(안대·눈썹과 붙은 눈·짙은 피부) = 표에 적은 수동 실측 값 유지 eye = float(prev['eye_px']) # 자동으로 못 찾는 그림(안대·눈썹과 붙은 눈·짙은 피부) = 표에 적은 수동 실측 값 유지
rows.append({'art': art, 'mounted': mounted, 'eye_px': eye, 'body_px': body, 'size_px': '', 'note': prev.get('note', '')}) lock = prev.get('lock', '')
hw, cr = head_width(img, eyes)
rows.append({'art': art, 'mounted': mounted, 'eye_px': eye, 'face_px': face_width(img, eyes), 'head_px': hw, 'crown_px': cr,
'body_px': body, 'size_px': float(prev['size_px']) if lock == '1' and prev.get('size_px') else '', 'lock': lock,
'adjust': prev.get('adjust', ''), 'note': prev.get('note', '')})
shots.append((art, meta, img, eyes)) shots.append((art, meta, img, eyes))
foot = sorted(r['eye_px'] / r['body_px'] for r in rows if r['mounted'] == '0' and r['eye_px'] and r['body_px']) def median(v):
if not foot: v = sorted(v)
sys.exit('말을 타지 않은 유닛의 눈 간격을 하나도 못 찾음') m = len(v) // 2
mid = len(foot) // 2 return v[m] if len(v) % 2 else (v[m - 1] + v[m]) / 2
ref = foot[mid] if len(foot) % 2 else (foot[mid - 1] + foot[mid]) / 2
# 기준 = lock 1 행(PD 가 확인한 크기 · 고정) 중 걷는 유닛: size_px ÷ 눈 간격·얼굴 폭·머리 폭 중앙값 → 나머지 = 세 추정 평균
# (PD 2026-11-10 「새 유닛(강유·서황)이 이전 유닛보다 크다 · 이전에 유닛 크기를 조정한 기준에 맞게」 — 새 그림은 투구가 커서 눈 간격 하나로는 머리 덩어리가 커짐)
anchor = [r for r in rows if r['lock'] == '1' and r['mounted'] == '0' and r['size_px']]
if not anchor:
sys.exit('기준 행(lock = 1 · 걷는 유닛) 없음')
ratio = {}
for key in ('eye_px', 'face_px', 'head_px', 'crown_px'):
v = [r['size_px'] / r[key] for r in anchor if r[key]]
ratio[key] = median(v) if v else 0
for r in rows: for r in rows:
r['size_px'] = round(r['eye_px'] / ref, 1) if r['eye_px'] else '' if r['lock'] == '1' and r['size_px']:
continue
# 네 추정(눈 간격 · 얼굴 폭 · 머리 폭 · 정수리 높이)의 가운데 값 — 하나가 투구·수염·무기에 속아도 버팀 · × adjust(영웅 목록 카드 눈 확인 보정 · 1.1 = 10 % 작게)
est = sorted(r[k] * ratio[k] for k in ratio if r[k] and ratio[k])
if not est:
r['size_px'] = ''
continue
m = len(est) // 2
base = est[m] if len(est) % 2 else (est[m - 1] + est[m]) / 2
r['size_px'] = round(base * (float(r['adjust']) if r['adjust'] else 1.0), 1)
with open(table, 'w', encoding='utf-8-sig', newline='') as f: with open(table, 'w', encoding='utf-8-sig', newline='') as f:
w = csv.DictWriter(f, fieldnames=FIELDS, lineterminator='\n') w = csv.DictWriter(f, fieldnames=FIELDS, lineterminator='\n')
w.writeheader() w.writeheader()
w.writerows(rows) w.writerows(rows)
print('ref(눈 간격 / 키 · 말 안 탄 %d종 중앙값) = %.4f' % (len(foot), ref)) print('기준 %d종(lock · 걷는 유닛) · 비율 size/눈 %.3f · size/얼굴 %.3f · size/머리 %.3f · size/정수리 %.3f' % (
len(anchor), ratio['eye_px'], ratio['face_px'], ratio['head_px'], ratio['crown_px']))
for r in rows: for r in rows:
s = (r['size_px'] / r['body_px']) if r['size_px'] else 0 s = (r['size_px'] / r['body_px']) if r['size_px'] else 0
print('%-22s mounted %s eye %6s body %5s size %7s 배율 x%.2f%s' % ( print('%-22s mounted %s lock %1s eye %6s face %4s head %6s body %5s size %7s 배율 x%.2f%s' % (
r['art'], r['mounted'], r['eye_px'], r['body_px'], r['size_px'], 1 / s if s else 0, '' if r['eye_px'] else ' ← 눈 못 찾음(bodyHeightPx 대체)')) r['art'], r['mounted'], r['lock'], r['eye_px'], r['face_px'], r['head_px'], r['body_px'], r['size_px'], 1 / s if s else 0, '' if r['eye_px'] else ' ← 눈 못 찾음'))
if sheet_path: # 확인 시트: 표 배율로 그린 대기 그림 + 눈 표시(머리 크기가 같아 보여야 함) if sheet_path: # 확인 시트: 표 배율로 그린 대기 그림 + 눈 표시(머리 크기가 같아 보여야 함)
unit = 160.0 # 표준 키 = 시트 160 px unit = 160.0 # 표준 키 = 시트 160 px