diff --git a/Assets/Resources/Units/art_size.csv b/Assets/Resources/Units/art_size.csv new file mode 100644 index 00000000..6e245f51 --- /dev/null +++ b/Assets/Resources/Units/art_size.csv @@ -0,0 +1,21 @@ +art,mounted,eye_px,body_px,size_px,note +cc_archer,0,125.1,744,741.6, +cc_boss_caocao,0,135.0,808,800.3, +cc_cavalry,1,91.9,849,544.8, +cc_infantry,0,125.3,765,742.8, +cc_spear,0,124.1,785,735.7, +dz_archer,0,123.3,745,730.9, +dz_boss_lvbu,1,75.8,819,449.3, +dz_cavalry,1,96.2,873,570.3, +dz_infantry,0,139.1,844,824.6, +dz_spear,0,117.2,818,694.8, +guanyu,0,122.7,725,727.4, +hgj_archer,0,154.7,833,917.0, +hgj_boss_zhangjiao,0,147.8,854,876.1, +hgj_cavalry,1,107.4,879,636.7, +hgj_infantry,0,161.5,850,957.4, +hgj_spear,0,168.5,862,998.9, +huangzhong,0,148.8,797,882.1, +liubei,0,142.2,752,843.0, +zhangfei,1,108.2,917,641.4, +zhaoyun,1,100.4,926,595.2, diff --git a/Assets/Resources/Units/wei_boss_simayi/meta.json.meta b/Assets/Resources/Units/art_size.csv.meta similarity index 75% rename from Assets/Resources/Units/wei_boss_simayi/meta.json.meta rename to Assets/Resources/Units/art_size.csv.meta index d68eb508..6371c547 100644 --- a/Assets/Resources/Units/wei_boss_simayi/meta.json.meta +++ b/Assets/Resources/Units/art_size.csv.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 6c52ae5244a4c1d47999b26723feb8d6 +guid: 7f92b435a2912a24cb826a5b40683511 TextScriptImporter: externalObjects: {} userData: diff --git a/Assets/Resources/Units/wei_archer.meta b/Assets/Resources/Units/wei_archer.meta deleted file mode 100644 index e7829653..00000000 --- a/Assets/Resources/Units/wei_archer.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: c8fe4e3059806cd4198d7544e2061771 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Resources/Units/wei_archer/front_idle.meta b/Assets/Resources/Units/wei_archer/front_idle.meta deleted file mode 100644 index 518c1fa0..00000000 --- a/Assets/Resources/Units/wei_archer/front_idle.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 44bb65b9a5cf86848ab36c47523fe2a2 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Resources/Units/wei_archer/front_idle/f000.png b/Assets/Resources/Units/wei_archer/front_idle/f000.png deleted file mode 100644 index 0c2de2c6..00000000 Binary files a/Assets/Resources/Units/wei_archer/front_idle/f000.png and /dev/null differ diff --git a/Assets/Resources/Units/wei_archer/front_idle/f000.png.meta b/Assets/Resources/Units/wei_archer/front_idle/f000.png.meta deleted file mode 100644 index b69bd755..00000000 --- a/Assets/Resources/Units/wei_archer/front_idle/f000.png.meta +++ /dev/null @@ -1,168 +0,0 @@ -fileFormatVersion: 2 -guid: 154714b72b6b71a439a066069edd217a -TextureImporter: - internalIDToNameTable: - - first: - 213: -166343660977832731 - second: f000_0 - externalObjects: {} - serializedVersion: 13 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - flipGreenChannel: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMipmapLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 1 - wrapV: 1 - wrapW: 1 - nPOTScale: 0 - lightmap: 0 - compressionQuality: 50 - spriteMode: 1 - spriteExtrude: 1 - spriteMeshType: 0 - alignment: 9 - spritePivot: {x: 0.5, y: 0.02101} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 8 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - swizzle: 50462976 - cookieLightType: 0 - platformSettings: - - serializedVersion: 4 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 4 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 4 - buildTarget: Android - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 4 - buildTarget: WebGL - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: - - serializedVersion: 2 - name: f000_0 - rect: - serializedVersion: 2 - x: 19 - y: 19 - width: 578 - height: 914 - alignment: 0 - pivot: {x: 0, y: 0} - border: {x: 0, y: 0, z: 0, w: 0} - customData: - outline: [] - physicsShape: [] - tessellationDetail: -1 - bones: [] - spriteID: 5ec37c8525701bdf0800000000000000 - internalID: -166343660977832731 - vertices: [] - indices: - edges: [] - weights: [] - outline: [] - customData: - physicsShape: [] - bones: [] - spriteID: 5e97eb03825dee720800000000000000 - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - spriteCustomMetadata: - entries: [] - nameFileIdTable: {} - mipmapLimitGroupName: - pSDRemoveMatte: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Resources/Units/wei_archer/meta.json b/Assets/Resources/Units/wei_archer/meta.json deleted file mode 100644 index b15a7788..00000000 --- a/Assets/Resources/Units/wei_archer/meta.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "fps": 1, - "ppu": 100, - "frame": [ - 616, - 952 - ], - "pivot": [ - 0.5, - 0.02101 - ], - "charHeightPx": 912, - "bodyHeightPx": 842, - "clips": [ - { - "name": "front_idle", - "frames": 1, - "loop": true - } - ] -} \ No newline at end of file diff --git a/Assets/Resources/Units/wei_archer/meta.json.meta b/Assets/Resources/Units/wei_archer/meta.json.meta deleted file mode 100644 index bef538ca..00000000 --- a/Assets/Resources/Units/wei_archer/meta.json.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 357942899e8b8504792baf9a75f4795f -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Resources/Units/wei_boss_simayi.meta b/Assets/Resources/Units/wei_boss_simayi.meta deleted file mode 100644 index 53b7efbe..00000000 --- a/Assets/Resources/Units/wei_boss_simayi.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 321a9b9e1c1291640bb97fc92b2924c9 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Resources/Units/wei_boss_simayi/front_idle.meta b/Assets/Resources/Units/wei_boss_simayi/front_idle.meta deleted file mode 100644 index 9aa3f57a..00000000 --- a/Assets/Resources/Units/wei_boss_simayi/front_idle.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: f2de55fd9322ded4e8e550631eb53734 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Resources/Units/wei_boss_simayi/front_idle/f000.png b/Assets/Resources/Units/wei_boss_simayi/front_idle/f000.png deleted file mode 100644 index a9b62535..00000000 Binary files a/Assets/Resources/Units/wei_boss_simayi/front_idle/f000.png and /dev/null differ diff --git a/Assets/Resources/Units/wei_boss_simayi/front_idle/f000.png.meta b/Assets/Resources/Units/wei_boss_simayi/front_idle/f000.png.meta deleted file mode 100644 index de3ccca1..00000000 --- a/Assets/Resources/Units/wei_boss_simayi/front_idle/f000.png.meta +++ /dev/null @@ -1,168 +0,0 @@ -fileFormatVersion: 2 -guid: a5abb9cd3db4e694891b52a867a1707a -TextureImporter: - internalIDToNameTable: - - first: - 213: -166343660977832731 - second: f000_0 - externalObjects: {} - serializedVersion: 13 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - flipGreenChannel: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMipmapLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 1 - wrapV: 1 - wrapW: 1 - nPOTScale: 0 - lightmap: 0 - compressionQuality: 50 - spriteMode: 1 - spriteExtrude: 1 - spriteMeshType: 0 - alignment: 9 - spritePivot: {x: 0.5, y: 0.02037} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 8 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - swizzle: 50462976 - cookieLightType: 0 - platformSettings: - - serializedVersion: 4 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 4 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 4 - buildTarget: Android - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 4 - buildTarget: WebGL - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: - - serializedVersion: 2 - name: f000_0 - rect: - serializedVersion: 2 - x: 19 - y: 19 - width: 532 - height: 944 - alignment: 0 - pivot: {x: 0, y: 0} - border: {x: 0, y: 0, z: 0, w: 0} - customData: - outline: [] - physicsShape: [] - tessellationDetail: -1 - bones: [] - spriteID: 5ec37c8525701bdf0800000000000000 - internalID: -166343660977832731 - vertices: [] - indices: - edges: [] - weights: [] - outline: [] - customData: - physicsShape: [] - bones: [] - spriteID: 5e97eb03825dee720800000000000000 - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - spriteCustomMetadata: - entries: [] - nameFileIdTable: {} - mipmapLimitGroupName: - pSDRemoveMatte: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Resources/Units/wei_boss_simayi/meta.json b/Assets/Resources/Units/wei_boss_simayi/meta.json deleted file mode 100644 index e5abc5ae..00000000 --- a/Assets/Resources/Units/wei_boss_simayi/meta.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "fps": 1, - "ppu": 100, - "frame": [ - 570, - 982 - ], - "pivot": [ - 0.5, - 0.02037 - ], - "charHeightPx": 942, - "bodyHeightPx": 799, - "clips": [ - { - "name": "front_idle", - "frames": 1, - "loop": true - } - ] -} \ No newline at end of file diff --git a/Assets/Resources/Units/wei_cavalry.meta b/Assets/Resources/Units/wei_cavalry.meta deleted file mode 100644 index eea46d12..00000000 --- a/Assets/Resources/Units/wei_cavalry.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 48fa1fa1606e6d44e857c4e315d8ba96 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Resources/Units/wei_cavalry/front_idle.meta b/Assets/Resources/Units/wei_cavalry/front_idle.meta deleted file mode 100644 index 0a0519d2..00000000 --- a/Assets/Resources/Units/wei_cavalry/front_idle.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 0d68a9e892581594e939bb8bb78a3ac1 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Resources/Units/wei_cavalry/front_idle/f000.png b/Assets/Resources/Units/wei_cavalry/front_idle/f000.png deleted file mode 100644 index 26e7978e..00000000 Binary files a/Assets/Resources/Units/wei_cavalry/front_idle/f000.png and /dev/null differ diff --git a/Assets/Resources/Units/wei_cavalry/front_idle/f000.png.meta b/Assets/Resources/Units/wei_cavalry/front_idle/f000.png.meta deleted file mode 100644 index ec90679d..00000000 --- a/Assets/Resources/Units/wei_cavalry/front_idle/f000.png.meta +++ /dev/null @@ -1,168 +0,0 @@ -fileFormatVersion: 2 -guid: 1900b449bbfb58b4393d5665f5129b0c -TextureImporter: - internalIDToNameTable: - - first: - 213: -166343660977832731 - second: f000_0 - externalObjects: {} - serializedVersion: 13 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - flipGreenChannel: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMipmapLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 1 - wrapV: 1 - wrapW: 1 - nPOTScale: 0 - lightmap: 0 - compressionQuality: 50 - spriteMode: 1 - spriteExtrude: 1 - spriteMeshType: 0 - alignment: 9 - spritePivot: {x: 0.5, y: 0.02045} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 8 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - swizzle: 50462976 - cookieLightType: 0 - platformSettings: - - serializedVersion: 4 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 4 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 4 - buildTarget: Android - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 4 - buildTarget: WebGL - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: - - serializedVersion: 2 - name: f000_0 - rect: - serializedVersion: 2 - x: 19 - y: 19 - width: 694 - height: 940 - alignment: 0 - pivot: {x: 0, y: 0} - border: {x: 0, y: 0, z: 0, w: 0} - customData: - outline: [] - physicsShape: [] - tessellationDetail: -1 - bones: [] - spriteID: 5ec37c8525701bdf0800000000000000 - internalID: -166343660977832731 - vertices: [] - indices: - edges: [] - weights: [] - outline: [] - customData: - physicsShape: [] - bones: [] - spriteID: 5e97eb03825dee720800000000000000 - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - spriteCustomMetadata: - entries: [] - nameFileIdTable: {} - mipmapLimitGroupName: - pSDRemoveMatte: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Resources/Units/wei_cavalry/meta.json b/Assets/Resources/Units/wei_cavalry/meta.json deleted file mode 100644 index 29aad89e..00000000 --- a/Assets/Resources/Units/wei_cavalry/meta.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "fps": 1, - "ppu": 100, - "frame": [ - 732, - 978 - ], - "pivot": [ - 0.5, - 0.02045 - ], - "charHeightPx": 938, - "bodyHeightPx": 877, - "clips": [ - { - "name": "front_idle", - "frames": 1, - "loop": true - } - ] -} \ No newline at end of file diff --git a/Assets/Resources/Units/wei_cavalry/meta.json.meta b/Assets/Resources/Units/wei_cavalry/meta.json.meta deleted file mode 100644 index 1c94f711..00000000 --- a/Assets/Resources/Units/wei_cavalry/meta.json.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: e2e0e727ef2627e4e95edf3bee7fc76b -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Resources/Units/wei_infantry.meta b/Assets/Resources/Units/wei_infantry.meta deleted file mode 100644 index a5cb73f4..00000000 --- a/Assets/Resources/Units/wei_infantry.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: ab5e1fb35f54c734f9849c8cea6396b2 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Resources/Units/wei_infantry/front_idle.meta b/Assets/Resources/Units/wei_infantry/front_idle.meta deleted file mode 100644 index daaa6ae4..00000000 --- a/Assets/Resources/Units/wei_infantry/front_idle.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 2182604a7db43d840b09344b749496d4 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Resources/Units/wei_infantry/front_idle/f000.png b/Assets/Resources/Units/wei_infantry/front_idle/f000.png deleted file mode 100644 index b6baae88..00000000 Binary files a/Assets/Resources/Units/wei_infantry/front_idle/f000.png and /dev/null differ diff --git a/Assets/Resources/Units/wei_infantry/front_idle/f000.png.meta b/Assets/Resources/Units/wei_infantry/front_idle/f000.png.meta deleted file mode 100644 index 84cafacd..00000000 --- a/Assets/Resources/Units/wei_infantry/front_idle/f000.png.meta +++ /dev/null @@ -1,168 +0,0 @@ -fileFormatVersion: 2 -guid: cc7eaa04bc7977848bc4717a47ff8f4b -TextureImporter: - internalIDToNameTable: - - first: - 213: -166343660977832731 - second: f000_0 - externalObjects: {} - serializedVersion: 13 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - flipGreenChannel: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMipmapLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 1 - wrapV: 1 - wrapW: 1 - nPOTScale: 0 - lightmap: 0 - compressionQuality: 50 - spriteMode: 1 - spriteExtrude: 1 - spriteMeshType: 0 - alignment: 9 - spritePivot: {x: 0.5, y: 0.02075} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 8 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - swizzle: 50462976 - cookieLightType: 0 - platformSettings: - - serializedVersion: 4 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 4 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 4 - buildTarget: Android - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 4 - buildTarget: WebGL - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: - - serializedVersion: 2 - name: f000_0 - rect: - serializedVersion: 2 - x: 19 - y: 19 - width: 525 - height: 926 - alignment: 0 - pivot: {x: 0, y: 0} - border: {x: 0, y: 0, z: 0, w: 0} - customData: - outline: [] - physicsShape: [] - tessellationDetail: -1 - bones: [] - spriteID: 5ec37c8525701bdf0800000000000000 - internalID: -166343660977832731 - vertices: [] - indices: - edges: [] - weights: [] - outline: [] - customData: - physicsShape: [] - bones: [] - spriteID: 5e97eb03825dee720800000000000000 - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - spriteCustomMetadata: - entries: [] - nameFileIdTable: {} - mipmapLimitGroupName: - pSDRemoveMatte: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Resources/Units/wei_infantry/meta.json b/Assets/Resources/Units/wei_infantry/meta.json deleted file mode 100644 index a75aa1d9..00000000 --- a/Assets/Resources/Units/wei_infantry/meta.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "fps": 1, - "ppu": 100, - "frame": [ - 563, - 964 - ], - "pivot": [ - 0.5, - 0.02075 - ], - "charHeightPx": 924, - "bodyHeightPx": 850, - "clips": [ - { - "name": "front_idle", - "frames": 1, - "loop": true - } - ] -} \ No newline at end of file diff --git a/Assets/Resources/Units/wei_infantry/meta.json.meta b/Assets/Resources/Units/wei_infantry/meta.json.meta deleted file mode 100644 index 534830d5..00000000 --- a/Assets/Resources/Units/wei_infantry/meta.json.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: a91577d55a26cf145bdb48cae6068b51 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Resources/Units/wei_spear.meta b/Assets/Resources/Units/wei_spear.meta deleted file mode 100644 index 7eda3655..00000000 --- a/Assets/Resources/Units/wei_spear.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: daf601eef2501824cba4fcf78852bed7 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Resources/Units/wei_spear/front_idle.meta b/Assets/Resources/Units/wei_spear/front_idle.meta deleted file mode 100644 index 60740d66..00000000 --- a/Assets/Resources/Units/wei_spear/front_idle.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 70d931937e5258447851f43e7fc4429b -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Resources/Units/wei_spear/front_idle/f000.png b/Assets/Resources/Units/wei_spear/front_idle/f000.png deleted file mode 100644 index 2db95e07..00000000 Binary files a/Assets/Resources/Units/wei_spear/front_idle/f000.png and /dev/null differ diff --git a/Assets/Resources/Units/wei_spear/front_idle/f000.png.meta b/Assets/Resources/Units/wei_spear/front_idle/f000.png.meta deleted file mode 100644 index 386bc465..00000000 --- a/Assets/Resources/Units/wei_spear/front_idle/f000.png.meta +++ /dev/null @@ -1,168 +0,0 @@ -fileFormatVersion: 2 -guid: 8671e3ec0807b3340b1921dc2ed4a333 -TextureImporter: - internalIDToNameTable: - - first: - 213: -166343660977832731 - second: f000_0 - externalObjects: {} - serializedVersion: 13 - mipmaps: - mipMapMode: 0 - enableMipMap: 0 - sRGBTexture: 1 - linearTexture: 0 - fadeOut: 0 - borderMipMap: 0 - mipMapsPreserveCoverage: 0 - alphaTestReferenceValue: 0.5 - mipMapFadeDistanceStart: 1 - mipMapFadeDistanceEnd: 3 - bumpmap: - convertToNormalMap: 0 - externalNormalMap: 0 - heightScale: 0.25 - normalMapFilter: 0 - flipGreenChannel: 0 - isReadable: 0 - streamingMipmaps: 0 - streamingMipmapsPriority: 0 - vTOnly: 0 - ignoreMipmapLimit: 0 - grayScaleToAlpha: 0 - generateCubemap: 6 - cubemapConvolution: 0 - seamlessCubemap: 0 - textureFormat: 1 - maxTextureSize: 2048 - textureSettings: - serializedVersion: 2 - filterMode: 1 - aniso: 1 - mipBias: 0 - wrapU: 1 - wrapV: 1 - wrapW: 1 - nPOTScale: 0 - lightmap: 0 - compressionQuality: 50 - spriteMode: 1 - spriteExtrude: 1 - spriteMeshType: 0 - alignment: 9 - spritePivot: {x: 0.5, y: 0.02121} - spritePixelsToUnits: 100 - spriteBorder: {x: 0, y: 0, z: 0, w: 0} - spriteGenerateFallbackPhysicsShape: 1 - alphaUsage: 1 - alphaIsTransparency: 1 - spriteTessellationDetail: -1 - textureType: 8 - textureShape: 1 - singleChannelComponent: 0 - flipbookRows: 1 - flipbookColumns: 1 - maxTextureSizeSet: 0 - compressionQualitySet: 0 - textureFormatSet: 0 - ignorePngGamma: 0 - applyGammaDecoding: 0 - swizzle: 50462976 - cookieLightType: 0 - platformSettings: - - serializedVersion: 4 - buildTarget: DefaultTexturePlatform - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 0 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 4 - buildTarget: Standalone - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 4 - buildTarget: Android - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - - serializedVersion: 4 - buildTarget: WebGL - maxTextureSize: 2048 - resizeAlgorithm: 0 - textureFormat: -1 - textureCompression: 1 - compressionQuality: 50 - crunchedCompression: 0 - allowsAlphaSplitting: 0 - overridden: 0 - ignorePlatformSupport: 0 - androidETC2FallbackOverride: 0 - forceMaximumCompressionQuality_BC6H_BC7: 0 - spriteSheet: - serializedVersion: 2 - sprites: - - serializedVersion: 2 - name: f000_0 - rect: - serializedVersion: 2 - x: 19 - y: 19 - width: 474 - height: 905 - alignment: 0 - pivot: {x: 0, y: 0} - border: {x: 0, y: 0, z: 0, w: 0} - customData: - outline: [] - physicsShape: [] - tessellationDetail: -1 - bones: [] - spriteID: 5ec37c8525701bdf0800000000000000 - internalID: -166343660977832731 - vertices: [] - indices: - edges: [] - weights: [] - outline: [] - customData: - physicsShape: [] - bones: [] - spriteID: 5e97eb03825dee720800000000000000 - internalID: 0 - vertices: [] - indices: - edges: [] - weights: [] - secondaryTextures: [] - spriteCustomMetadata: - entries: [] - nameFileIdTable: {} - mipmapLimitGroupName: - pSDRemoveMatte: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Resources/Units/wei_spear/meta.json b/Assets/Resources/Units/wei_spear/meta.json deleted file mode 100644 index b2fa5e71..00000000 --- a/Assets/Resources/Units/wei_spear/meta.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "fps": 1, - "ppu": 100, - "frame": [ - 512, - 943 - ], - "pivot": [ - 0.5, - 0.02121 - ], - "charHeightPx": 903, - "bodyHeightPx": 860, - "clips": [ - { - "name": "front_idle", - "frames": 1, - "loop": true - } - ] -} \ No newline at end of file diff --git a/Assets/Resources/Units/wei_spear/meta.json.meta b/Assets/Resources/Units/wei_spear/meta.json.meta deleted file mode 100644 index 90678804..00000000 --- a/Assets/Resources/Units/wei_spear/meta.json.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: c3f282f7fd7dedf4a9d91436db8ca357 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Scripts/OutGame/UI/HeroScreens.cs b/Assets/Scripts/OutGame/UI/HeroScreens.cs index 4cb49f0d..35e85a10 100644 --- a/Assets/Scripts/OutGame/UI/HeroScreens.cs +++ b/Assets/Scripts/OutGame/UI/HeroScreens.cs @@ -84,8 +84,8 @@ namespace TKS.OutGame { public static readonly Vector2 CellSize = new Vector2(320f, 431f); public static readonly Vector2 Spacing = new Vector2(22f, 20f); - /// 일러 배율(원본 px → 화면 px · 전 유닛 공통) · 머리 끝 위치(카드 위에서 px). - const float ArtScale = 0.56f; + /// 크기 표 size_px(머리 크기 기준 표준 키)가 카드에서 차지할 px — 배율 = UnitPx ÷ size_px(모든 유닛 머리 크기 같음) · 머리 끝 위치(카드 위에서 px). + const float UnitPx = 450f; const float HeadTop = 50f; public static Image Card(Transform content, OutGameSession s, HeroDb.Hero h, bool deployed, System.Action onTap) @@ -107,17 +107,18 @@ namespace TKS.OutGame var sp = UiKit.ArtSprite(h.art); if (sp != null) { - // 모든 유닛 같은 배율(PD 2026-11-09 「유닛 크기를 동일한 비율로」) = 원본 px × ArtScale · 머리 끝(발 + bodyHeightPx · 무기 제외)을 카드 위 HeadTop 에 맞춤 - // → 머리 크기가 같고 다리·말은 아래 띠 뒤로 잘림(레퍼런스 흉상 느낌) · 메타가 없으면 칸 맞춤 + // 머리 크기 통일(PD 2026-11-09 「캐릭터 크기가 동일하게 보이도록」) = 배율 UnitPx ÷ 크기 표 size_px(눈 간격 기준 · 말 탄 유닛은 탄 사람 기준) · + // 머리 끝(발 + bodyHeightPx · 무기 제외)을 카드 위 HeadTop 에 맞춤 → 다리·말은 아래 띠 뒤로 잘림(레퍼런스 흉상 느낌) · 메타가 없으면 칸 맞춤 var a = UnitArt.Load(h.art); var m = a != null ? a.Meta : null; - float body = m != null ? (m.bodyHeightPx > 0.5f ? m.bodyHeightPx : m.charHeightPx) : 0f; + float body = a != null ? a.BodyPx : 0f; + float size = a != null && a.SizePx > 0.5f ? a.SizePx : body; Image art; if (body > 0.5f && m.pivot != null && m.pivot.Length > 1) { float hgt = sp.rect.height; float headY = Mathf.Clamp01((m.pivot[1] * hgt + body) / hgt); // 머리 끝 = 프레임 아래에서의 비율 - art = UiKit.Rect("Character", b, new Vector2(0.5f, 1f), new Vector2(0.5f, headY), new Vector2(0f, -HeadTop), sp.rect.size * ArtScale).gameObject.AddComponent(); + art = UiKit.Rect("Character", b, new Vector2(0.5f, 1f), new Vector2(0.5f, headY), new Vector2(0f, -HeadTop), sp.rect.size * (UnitPx / size)).gameObject.AddComponent(); } else { diff --git a/Assets/Scripts/Runtime/Unit.cs b/Assets/Scripts/Runtime/Unit.cs index 205be0e2..4890a5b3 100644 --- a/Assets/Scripts/Runtime/Unit.cs +++ b/Assets/Scripts/Runtime/Unit.cs @@ -23,7 +23,7 @@ namespace TKS public float ArcherMoveAllow; /// Resources/Units/<ArtId>/ 아트 폴더 · 비면 도형. public string ArtId = ""; - /// 아트 세로 크기(월드) = unitArtHeight × 반지름 배율. + /// 아트 머리 끝 높이(월드) — Init = 표준 키(unitArtHeight × 반지름 배율) · 아트가 있으면 UnitView 가 크기 표 배율 뒤 실제 머리 끝으로 바꾼다. public float ArtHeight; /// 이번 아군 턴에 행동을 마쳤는가. diff --git a/Assets/Scripts/Runtime/UnitArt.cs b/Assets/Scripts/Runtime/UnitArt.cs index 18e2363f..44071f7d 100644 --- a/Assets/Scripts/Runtime/UnitArt.cs +++ b/Assets/Scripts/Runtime/UnitArt.cs @@ -37,15 +37,25 @@ namespace TKS public UnitArtMeta Meta; public readonly Dictionary Clips = new Dictionary(); public readonly Dictionary Loop = new Dictionary(); + /// + /// 크기 기준 px = Resources/Units/art_size.csv 의 size_px(눈 간격 ÷ 기준 비율 = 머리 크기가 표준인 유닛의 키로 환산 · Tools/unit_art_size.py) · + /// 0 = 표에 없음 → BodyPx. PD 2026-11-09 「캐릭터 크기 동일 · 말 탄 유닛도 보병·창병과 비슷한 비율」. + /// + public float SizePx; - /// 캐릭터 몸 세로 크기(월드) — 임포터 PPU = meta.ppu 전제 · bodyHeightPx(무기 제외) 우선, 없으면 charHeightPx. + /// 그림 속 몸(머리 끝~발) 세로 px — bodyHeightPx(무기 제외) 우선, 없으면 charHeightPx. + public float BodyPx + { + get { return Meta.bodyHeightPx > 0.5f ? Meta.bodyHeightPx : Meta.charHeightPx; } + } + + /// 배율 기준 세로 크기(월드) — 임포터 PPU = meta.ppu 전제 · 크기 표 size_px 우선(모든 유닛의 머리 크기가 같아짐), 없으면 BodyPx. public float CharHeightWorld { get { if (Meta.ppu <= 0.01f) return 1f; - float px = Meta.bodyHeightPx > 0.5f ? Meta.bodyHeightPx : Meta.charHeightPx; - return px / Meta.ppu; + return (SizePx > 0.5f ? SizePx : BodyPx) / Meta.ppu; } } } @@ -54,7 +64,41 @@ namespace TKS public static class UnitArt { public const string Root = "Units/"; + /// 크기 표(TextAsset · utf-8-sig CSV · 열 art · size_px) = Resources/Units/art_size.csv. + public const string SizeTable = "art_size"; static readonly Dictionary cache = new Dictionary(); + static Dictionary sizes; + + /// 크기 표의 size_px(없으면 0). + public static float SizeOf(string id) + { + if (sizes == null) sizes = ParseSizes(Resources.Load(Root + SizeTable)); + float v; + return id != null && sizes.TryGetValue(id, out v) ? v : 0f; + } + + static Dictionary ParseSizes(TextAsset ta) + { + var d = new Dictionary(); + if (ta == null) return d; + var lines = ta.text.TrimStart('').Split('\n'); + if (lines.Length == 0) return d; + var head = new List(lines[0].Trim().Split(',')); + int ia = head.IndexOf("art"), isz = head.IndexOf("size_px"); + if (ia < 0 || isz < 0) + { + Debug.LogWarning("[TKS] 유닛 크기 표 열(art · size_px) 없음"); + return d; + } + for (int i = 1; i < lines.Length; i++) + { + var c = lines[i].Trim().Split(','); + float v; + if (c.Length > Mathf.Max(ia, isz) && float.TryParse(c[isz], System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out v) && v > 0f) + d[c[ia]] = v; + } + return d; + } public static UnitArtData Load(string id) { @@ -69,6 +113,7 @@ namespace TKS public static void ClearCache() { cache.Clear(); + sizes = null; } static UnitArtData LoadUncached(string id) @@ -87,7 +132,7 @@ namespace TKS } if (meta == null || meta.clips == null) return null; - var d = new UnitArtData { Id = id, Meta = meta }; + var d = new UnitArtData { Id = id, Meta = meta, SizePx = SizeOf(id) }; foreach (var c in meta.clips) { if (c == null || string.IsNullOrEmpty(c.name)) continue; @@ -134,6 +179,10 @@ namespace TKS get { return data; } } + /// 그려진 머리 끝 높이(월드 · 발 기준) = BodyPx × 배율 — 크기 표로 커진 기마 유닛은 표준 키보다 높다. + public float TopHeight { get; private set; } + + /// 표준 키(월드) — 크기 표 size_px 가 이 높이가 되도록 배율(= 머리 크기 통일). public void Setup(UnitArtData d, float worldHeight, int sortingOrder) { data = d; @@ -143,6 +192,7 @@ namespace TKS float h = d.CharHeightWorld; float s = h > 0.001f ? worldHeight / h : 1f; transform.localScale = new Vector3(s, s, 1f); + TopHeight = d.Meta.ppu > 0.01f ? d.BodyPx / d.Meta.ppu * s : worldHeight; } public bool Has(string clip) diff --git a/Assets/Scripts/Runtime/UnitView.cs b/Assets/Scripts/Runtime/UnitView.cs index b4377aec..6e02c904 100644 --- a/Assets/Scripts/Runtime/UnitView.cs +++ b/Assets/Scripts/Runtime/UnitView.cs @@ -140,6 +140,7 @@ namespace TKS ago.transform.localPosition = new Vector3(0f, -u.Radius * 0.55f, 0f); anim = ago.AddComponent(); anim.Setup(art, u.ArtHeight, 0); + u.ArtHeight = anim.TopHeight; // 크기 표 배율 뒤 실제 머리 끝(HP 바 · 머리 위 표시 기준) anim.Renderer.flipX = facingLeft; anim.SetIdle(ClipName("idle")); anim.PlayIdle(); diff --git a/Assets/Tests/PlayMode/BattleFlowTests.cs b/Assets/Tests/PlayMode/BattleFlowTests.cs index 4539cfcb..6466caa0 100644 --- a/Assets/Tests/PlayMode/BattleFlowTests.cs +++ b/Assets/Tests/PlayMode/BattleFlowTests.cs @@ -975,6 +975,49 @@ namespace TKS.Tests Assert.IsTrue(u.View.Anim.Renderer.flipX, "왼쪽 = 좌우 반전"); } + [UnityTest] + public IEnumerator UnitArt_SizeTable_SameHeadSize_MountedRiderLikeFoot() + { + // PD 2026-11-09 「캐릭터 크기 동일 · 말 탄 유닛도 보병·창병과 비슷한 비율」 — 크기 표(art_size.csv · 눈 간격 기준)로 배율을 정하면 + // 게임 안 눈 간격(월드)이 모든 유닛에서 같다 · 기마 유닛은 표준 키보다 커진다(탄 사람 = 보병 크기) + var ta = Resources.Load(UnitArt.Root + UnitArt.SizeTable); + Assert.IsNotNull(ta, "크기 표 Resources/Units/art_size.csv"); + var lines = ta.text.TrimStart('').Split('\n'); + var head = new List(lines[0].Trim().Split(',')); + int ia = head.IndexOf("art"), im = head.IndexOf("mounted"), ie = head.IndexOf("eye_px"); + var eyes = new List(); + int mounted = 0; + var go = new GameObject("SizeProbe"); + var fa = go.AddComponent(); + for (int i = 1; i < lines.Length; i++) + { + var c = lines[i].Trim().Split(','); + if (c.Length <= ie) continue; + var a = UnitArt.Load(c[ia]); + Assert.IsNotNull(a, "표의 아트 " + c[ia]); + Assert.Greater(a.SizePx, 0f, c[ia] + " size_px"); + fa.Setup(a, cfg.unitArtHeight, 0); + eyes.Add(float.Parse(c[ie], System.Globalization.CultureInfo.InvariantCulture) / a.Meta.ppu * go.transform.localScale.x); + if (c[im] == "1") + { + mounted++; + Assert.Greater(fa.TopHeight, cfg.unitArtHeight * 1.2f, c[ia] + " 기마 = 탄 사람이 보병 크기가 되도록 커짐"); + } + } + Object.Destroy(go); + Assert.GreaterOrEqual(eyes.Count, 15, "표 행 수"); + Assert.GreaterOrEqual(mounted, 5, "기마 행 수"); + eyes.Sort(); + Assert.Less(eyes[eyes.Count - 1] / eyes[0], 1.01f, "모든 유닛 눈 간격(월드) 같음"); + + // 배치된 기마 영웅 = HP 바 기준(ArtHeight)이 실제 머리 끝 + yield return Fresh(); + var u = bm.SpawnUnit(UnitType.Cavalry, Faction.Player, new Vector2(0f, -4f), "조운", 1f, 1f, false, "zhaoyun"); + yield return null; + Assert.AreEqual(u.View.Anim.TopHeight, u.ArtHeight, 1e-4f, "ArtHeight = 그려진 머리 끝"); + Assert.Greater(u.ArtHeight, cfg.unitArtHeight, "기마 = 표준 키보다 높음"); + } + // ---------- 스테이지 표(Assets/Data/Stages/*.csv · 145 스테이지 · 2026-11-05 #1086) ---------- static StageTable.Tables ReadStageTable() diff --git a/Tools/unit_art_size.py b/Tools/unit_art_size.py new file mode 100644 index 00000000..2c1bf297 --- /dev/null +++ b/Tools/unit_art_size.py @@ -0,0 +1,149 @@ +# -*- coding: utf-8 -*- +"""유닛 아트 크기 표 생성(PD 2026-11-09 「영웅 목록 캐릭터 크기 동일 · 말 탄 유닛도 보병·창병과 비슷한 비율」). + +기준 = 눈 간격(머리 크기) — 투구·수염·말과 상관없이 같은 화풍이면 머리 크기에 비례한다. + eye_px = 대기 첫 프레임(front_idle/f000.png)의 두 눈 중심 사이 가로 px(얼굴 피부 덩어리 안 어두운 구멍 2개) + ref = 말을 타지 않은 유닛(mounted=0)의 eye_px / body_px 중앙값 + size_px = eye_px / ref = 「머리 크기가 표준인 유닛의 키」로 환산한 세로 px +게임(FrameAnimator)·영웅 목록은 bodyHeightPx 대신 size_px 로 배율을 정한다 → 모든 유닛의 머리 크기가 같아지고, +말 탄 유닛은 탄 사람이 보병과 같은 크기가 되도록 커진다. + +표 = Assets/Resources/Units/art_size.csv(utf-8-sig · SOT) · mounted 열만 사람이 고친다(새 아트 = 이름에 cavalry 면 1). +눈을 못 찾으면 size_px 를 비워 둔다(게임은 bodyHeightPx 로 대체) · 실행 결과를 --sheet 시트로 눈 위치를 확인할 것. + +사용: python -I -B -X utf8 Tools/unit_art_size.py <프로젝트 루트> [--sheet out.png] +""" +import csv +import glob +import json +import os +import sys + +import numpy as np +from PIL import Image, ImageDraw, ImageFont +from scipy import ndimage + +TABLE = 'Assets/Resources/Units/art_size.csv' +FIELDS = ['art', 'mounted', 'eye_px', 'body_px', 'size_px', 'note'] + + +def skin_mask(a, red): + r, g, b, al = a[..., 0], a[..., 1], a[..., 2], a[..., 3] + mx = np.maximum(np.maximum(r, g), b) + mn = np.minimum(np.minimum(r, g), b) + sat = np.where(mx > 0, (mx - mn) / np.maximum(mx, 1e-6), 0) + if red: # 붉은 얼굴(관우) + sk = (al > 0.9) & (r > 0.8) & (g > 0.3) & (g < 0.6) & (b > 0.25) & (b < 0.55) + else: + sk = (al > 0.9) & (r >= g) & (g >= b - 0.02) & (mx > 0.78) & (sat > 0.06) & (sat < 0.45) & ((r - b) > 0.06) + return sk, mx + + +def find_eyes(img): + """두 눈 (왼쪽, 오른쪽) = (면적, x, y) · 못 찾으면 None.""" + a = np.asarray(img.convert('RGBA')).astype(np.float32) / 255.0 + for red in (False, True): + sk, val = skin_mask(a, red) + lab, n = ndimage.label(sk) + if not n: + continue + sizes = ndimage.sum(sk, lab, range(1, n + 1)) + for k in list(np.argsort(sizes)[::-1][:6] + 1): + face = lab == k + ys, xs = np.where(face) + if len(ys) < 3000: + continue + fh = ys.max() - ys.min() + 1 + holes = ndimage.binary_fill_holes(face) & ~face + hl, hn = ndimage.label(holes) + cand = [] + for j in range(1, hn + 1): + yy, xx = np.where(hl == j) + if len(yy) < 150 or val[yy, xx].mean() > 0.4: + continue + if (xx.max() - xx.min() + 1) > 2.2 * (yy.max() - yy.min() + 1): + continue # 가로로 긴 구멍 = 수염·입 + cand.append((len(yy), xx.mean(), yy.mean())) + best = None + for l in cand: + for r in cand: + if l[1] >= r[1] or abs(l[2] - r[2]) > 0.12 * fh: + continue + if min(l[0], r[0]) < 0.45 * max(l[0], r[0]): + continue + score = min(l[0], r[0]) * (r[1] - l[1]) + if best is None or score > best[0]: + best = (score, l, r) + if best: + return best[1], best[2] + return None + + +def main(): + root = sys.argv[1] + sheet_path = sys.argv[sys.argv.index('--sheet') + 1] if '--sheet' in sys.argv else None + table = os.path.join(root, TABLE) + old = {} + if os.path.exists(table): + with open(table, encoding='utf-8-sig', newline='') as f: + old = {r['art']: r for r in csv.DictReader(f)} + + rows, shots = [], [] + for meta_path in sorted(glob.glob(os.path.join(root, 'Assets/Resources/Units/*/meta.json'))): + folder = os.path.dirname(meta_path) + art = os.path.basename(folder) + meta = json.load(open(meta_path, encoding='utf-8')) + body = meta.get('bodyHeightPx') or meta.get('charHeightPx') or 0 + frame = os.path.join(folder, 'front_idle', 'f000.png') + if not os.path.exists(frame): + frame = sorted(glob.glob(os.path.join(folder, '*', 'f000.png')))[0] + img = Image.open(frame).convert('RGBA') + eyes = find_eyes(img) + prev = old.get(art, {}) + mounted = prev.get('mounted', '1' if 'cavalry' in art else '0') + eye = round(eyes[1][1] - eyes[0][1], 1) if eyes else 0 + rows.append({'art': art, 'mounted': mounted, 'eye_px': eye, 'body_px': body, 'size_px': '', 'note': prev.get('note', '')}) + 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']) + if not foot: + sys.exit('말을 타지 않은 유닛의 눈 간격을 하나도 못 찾음') + mid = len(foot) // 2 + ref = foot[mid] if len(foot) % 2 else (foot[mid - 1] + foot[mid]) / 2 + for r in rows: + r['size_px'] = round(r['eye_px'] / ref, 1) if r['eye_px'] else '' + + with open(table, 'w', encoding='utf-8-sig', newline='') as f: + w = csv.DictWriter(f, fieldnames=FIELDS, lineterminator='\n') + w.writeheader() + w.writerows(rows) + print('ref(눈 간격 / 키 · 말 안 탄 %d종 중앙값) = %.4f' % (len(foot), ref)) + for r in rows: + 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' % ( + 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 대체)')) + + if sheet_path: # 확인 시트: 표 배율로 그린 대기 그림 + 눈 표시(머리 크기가 같아 보여야 함) + unit = 160.0 # 표준 키 = 시트 160 px + cols, cw, ch = 9, 220, 330 + sheet = Image.new('RGB', (cw * cols, ch * ((len(shots) + cols - 1) // cols)), (40, 44, 60)) + dr = ImageDraw.Draw(sheet) + font = ImageFont.truetype('C:/Windows/Fonts/malgun.ttf', 13) + for i, ((art, meta, img, eyes), r) in enumerate(zip(shots, rows)): + size = r['size_px'] or r['body_px'] + sc = unit / size + x0, y0 = (i % cols) * cw, (i // cols) * ch + t = img.resize((max(1, int(img.width * sc)), max(1, int(img.height * sc))), Image.LANCZOS) + base = y0 + ch - 22 + ox, oy = x0 + cw // 2 - t.width // 2, int(base - (1 - meta['pivot'][1]) * img.height * sc) + sheet.paste(t, (ox, oy), t) + for e in eyes or (): + ex, ey = ox + e[1] * sc, oy + e[2] * sc + dr.ellipse([ex - 3, ey - 3, ex + 3, ey + 3], outline=(0, 255, 0), width=2) + dr.text((x0 + 3, base + 3), '%s%s' % (art, ' (말)' if r['mounted'] == '1' else ''), fill=(255, 255, 255), font=font) + sheet.save(sheet_path) + print('sheet', sheet_path) + + +if __name__ == '__main__': + main()