diff --git a/Assets/Resources/BalanceConfig.asset b/Assets/Resources/BalanceConfig.asset index cd582318..2bc05e5f 100644 --- a/Assets/Resources/BalanceConfig.asset +++ b/Assets/Resources/BalanceConfig.asset @@ -67,7 +67,11 @@ MonoBehaviour: bossRadiusMult: 1.25 cavalryKnockback: 0.35 archerRangeRatio: 0.2 + archerMeleeDealtRatio: 0.5 + archerMeleeTakenRatio: 1.5 + collisionPushRatio: 1 unitArtHeight: 1.5 + boardArt: battlefield_01 minDragDistance: 0.35 finalHitTolerance: 0.15 moveSpeed: 9 diff --git a/Assets/Resources/Board.meta b/Assets/Resources/Board.meta new file mode 100644 index 00000000..6ac7ba5c --- /dev/null +++ b/Assets/Resources/Board.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a74463feafb491c4dafe8d1133c7f3cc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Board/battlefield_01.png b/Assets/Resources/Board/battlefield_01.png new file mode 100644 index 00000000..4917d126 Binary files /dev/null and b/Assets/Resources/Board/battlefield_01.png differ diff --git a/Assets/Resources/Board/battlefield_01.png.meta b/Assets/Resources/Board/battlefield_01.png.meta new file mode 100644 index 00000000..06f5e2b7 --- /dev/null +++ b/Assets/Resources/Board/battlefield_01.png.meta @@ -0,0 +1,169 @@ +fileFormatVersion: 2 +guid: 6e3a6ea6e68311c4683b0c9f0944480f +TextureImporter: + internalIDToNameTable: + - first: + 213: 6962303912857251952 + second: battlefield_01_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: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + 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: 4096 + 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: 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: battlefield_01_0 + rect: + serializedVersion: 2 + x: 0 + y: 0 + width: 2000 + height: 3200 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 0703b2855821f9060800000000000000 + internalID: 6962303912857251952 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + battlefield_01_0: 6962303912857251952 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Units/dz_archer.meta b/Assets/Resources/Units/dz_archer.meta new file mode 100644 index 00000000..c41dee7d --- /dev/null +++ b/Assets/Resources/Units/dz_archer.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c762694df723e0449b223cfd4674c673 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Units/dz_archer/front_idle.meta b/Assets/Resources/Units/dz_archer/front_idle.meta new file mode 100644 index 00000000..e459f2dc --- /dev/null +++ b/Assets/Resources/Units/dz_archer/front_idle.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b61c180460f762d45a53cbc320967d18 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Units/dz_archer/front_idle/f000.png b/Assets/Resources/Units/dz_archer/front_idle/f000.png new file mode 100644 index 00000000..b7c92872 Binary files /dev/null and b/Assets/Resources/Units/dz_archer/front_idle/f000.png differ diff --git a/Assets/Resources/Units/dz_archer/front_idle/f000.png.meta b/Assets/Resources/Units/dz_archer/front_idle/f000.png.meta new file mode 100644 index 00000000..8f6fce35 --- /dev/null +++ b/Assets/Resources/Units/dz_archer/front_idle/f000.png.meta @@ -0,0 +1,168 @@ +fileFormatVersion: 2 +guid: 9948907966e189148b1268d13d76c475 +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.02064} + 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: 18 + width: 530 + height: 932 + 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/dz_archer/meta.json b/Assets/Resources/Units/dz_archer/meta.json new file mode 100644 index 00000000..933eecc8 --- /dev/null +++ b/Assets/Resources/Units/dz_archer/meta.json @@ -0,0 +1,20 @@ +{ + "fps": 1, + "ppu": 100, + "frame": [ + 568, + 969 + ], + "pivot": [ + 0.5, + 0.02064 + ], + "charHeightPx": 929, + "clips": [ + { + "name": "front_idle", + "frames": 1, + "loop": true + } + ] +} \ No newline at end of file diff --git a/Assets/Resources/Units/dz_archer/meta.json.meta b/Assets/Resources/Units/dz_archer/meta.json.meta new file mode 100644 index 00000000..38118640 --- /dev/null +++ b/Assets/Resources/Units/dz_archer/meta.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 68b84df74057f3f47a3c33b6b3342573 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Units/dz_cavalry.meta b/Assets/Resources/Units/dz_cavalry.meta new file mode 100644 index 00000000..2503af16 --- /dev/null +++ b/Assets/Resources/Units/dz_cavalry.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c58e18725c9a5514da41526a47391814 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Units/dz_cavalry/front_idle.meta b/Assets/Resources/Units/dz_cavalry/front_idle.meta new file mode 100644 index 00000000..badf3e6d --- /dev/null +++ b/Assets/Resources/Units/dz_cavalry/front_idle.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5769dc3460a78ca47a6b782fc06ebd7c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Units/dz_cavalry/front_idle/f000.png b/Assets/Resources/Units/dz_cavalry/front_idle/f000.png new file mode 100644 index 00000000..4fef8f45 Binary files /dev/null and b/Assets/Resources/Units/dz_cavalry/front_idle/f000.png differ diff --git a/Assets/Resources/Units/dz_cavalry/front_idle/f000.png.meta b/Assets/Resources/Units/dz_cavalry/front_idle/f000.png.meta new file mode 100644 index 00000000..c0234fc6 --- /dev/null +++ b/Assets/Resources/Units/dz_cavalry/front_idle/f000.png.meta @@ -0,0 +1,168 @@ +fileFormatVersion: 2 +guid: e1b356e27b2ca84409a21237e725c1ad +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.02092} + 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: 676 + height: 918 + 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/dz_cavalry/meta.json b/Assets/Resources/Units/dz_cavalry/meta.json new file mode 100644 index 00000000..99512cc1 --- /dev/null +++ b/Assets/Resources/Units/dz_cavalry/meta.json @@ -0,0 +1,20 @@ +{ + "fps": 1, + "ppu": 100, + "frame": [ + 714, + 956 + ], + "pivot": [ + 0.5, + 0.02092 + ], + "charHeightPx": 916, + "clips": [ + { + "name": "front_idle", + "frames": 1, + "loop": true + } + ] +} \ No newline at end of file diff --git a/Assets/Resources/Units/dz_cavalry/meta.json.meta b/Assets/Resources/Units/dz_cavalry/meta.json.meta new file mode 100644 index 00000000..6ef4b4e2 --- /dev/null +++ b/Assets/Resources/Units/dz_cavalry/meta.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: d3a20275187eda3458bc205f153411ae +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Units/dz_infantry.meta b/Assets/Resources/Units/dz_infantry.meta new file mode 100644 index 00000000..cf559dbe --- /dev/null +++ b/Assets/Resources/Units/dz_infantry.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8264d82aab0a4ec4da8daef6b607a1d4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Units/dz_infantry/front_idle.meta b/Assets/Resources/Units/dz_infantry/front_idle.meta new file mode 100644 index 00000000..9442e48f --- /dev/null +++ b/Assets/Resources/Units/dz_infantry/front_idle.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 64bd26411189d0149a15c532ddb851d1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Units/dz_infantry/front_idle/f000.png b/Assets/Resources/Units/dz_infantry/front_idle/f000.png new file mode 100644 index 00000000..c73e5626 Binary files /dev/null and b/Assets/Resources/Units/dz_infantry/front_idle/f000.png differ diff --git a/Assets/Resources/Units/dz_infantry/front_idle/f000.png.meta b/Assets/Resources/Units/dz_infantry/front_idle/f000.png.meta new file mode 100644 index 00000000..6dee01df --- /dev/null +++ b/Assets/Resources/Units/dz_infantry/front_idle/f000.png.meta @@ -0,0 +1,168 @@ +fileFormatVersion: 2 +guid: 82e9825e5f8895c4d88848505ca6a5b9 +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.0221} + 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: 528 + height: 867 + 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/dz_infantry/meta.json b/Assets/Resources/Units/dz_infantry/meta.json new file mode 100644 index 00000000..61e67eea --- /dev/null +++ b/Assets/Resources/Units/dz_infantry/meta.json @@ -0,0 +1,20 @@ +{ + "fps": 1, + "ppu": 100, + "frame": [ + 566, + 905 + ], + "pivot": [ + 0.5, + 0.0221 + ], + "charHeightPx": 865, + "clips": [ + { + "name": "front_idle", + "frames": 1, + "loop": true + } + ] +} \ No newline at end of file diff --git a/Assets/Resources/Units/dz_infantry/meta.json.meta b/Assets/Resources/Units/dz_infantry/meta.json.meta new file mode 100644 index 00000000..b839eea1 --- /dev/null +++ b/Assets/Resources/Units/dz_infantry/meta.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9ce640825d5c4e74fbfb0c09a8d7fced +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Units/dz_spear.meta b/Assets/Resources/Units/dz_spear.meta new file mode 100644 index 00000000..7ae7efcc --- /dev/null +++ b/Assets/Resources/Units/dz_spear.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8a518d38fe2e823429d906d3681919ce +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Units/dz_spear/front_idle.meta b/Assets/Resources/Units/dz_spear/front_idle.meta new file mode 100644 index 00000000..12858da4 --- /dev/null +++ b/Assets/Resources/Units/dz_spear/front_idle.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 21750aef097feac448849e0781b4d12f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Units/dz_spear/front_idle/f000.png b/Assets/Resources/Units/dz_spear/front_idle/f000.png new file mode 100644 index 00000000..6deb4855 Binary files /dev/null and b/Assets/Resources/Units/dz_spear/front_idle/f000.png differ diff --git a/Assets/Resources/Units/dz_spear/front_idle/f000.png.meta b/Assets/Resources/Units/dz_spear/front_idle/f000.png.meta new file mode 100644 index 00000000..638392df --- /dev/null +++ b/Assets/Resources/Units/dz_spear/front_idle/f000.png.meta @@ -0,0 +1,168 @@ +fileFormatVersion: 2 +guid: 4b581a6de17271047ba0feb63ea70500 +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.02033} + 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: 540 + height: 960 + 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/dz_spear/meta.json b/Assets/Resources/Units/dz_spear/meta.json new file mode 100644 index 00000000..ff2d5238 --- /dev/null +++ b/Assets/Resources/Units/dz_spear/meta.json @@ -0,0 +1,20 @@ +{ + "fps": 1, + "ppu": 100, + "frame": [ + 578, + 984 + ], + "pivot": [ + 0.5, + 0.02033 + ], + "charHeightPx": 957, + "clips": [ + { + "name": "front_idle", + "frames": 1, + "loop": true + } + ] +} \ No newline at end of file diff --git a/Assets/Resources/Units/dz_spear/meta.json.meta b/Assets/Resources/Units/dz_spear/meta.json.meta new file mode 100644 index 00000000..e7f74a55 --- /dev/null +++ b/Assets/Resources/Units/dz_spear/meta.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c406e2a385c03a74f87aa25e6a6f3c09 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Units/hgj_archer.meta b/Assets/Resources/Units/hgj_archer.meta new file mode 100644 index 00000000..71fa3be2 --- /dev/null +++ b/Assets/Resources/Units/hgj_archer.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6c3636902d4db564792989f078754f48 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Units/hgj_archer/front_idle.meta b/Assets/Resources/Units/hgj_archer/front_idle.meta new file mode 100644 index 00000000..be704426 --- /dev/null +++ b/Assets/Resources/Units/hgj_archer/front_idle.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b3ec43f64b3072d4abd386d5e1895eb6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Units/hgj_archer/front_idle/f000.png b/Assets/Resources/Units/hgj_archer/front_idle/f000.png new file mode 100644 index 00000000..432c2acb Binary files /dev/null and b/Assets/Resources/Units/hgj_archer/front_idle/f000.png differ diff --git a/Assets/Resources/Units/hgj_archer/front_idle/f000.png.meta b/Assets/Resources/Units/hgj_archer/front_idle/f000.png.meta new file mode 100644 index 00000000..136359a0 --- /dev/null +++ b/Assets/Resources/Units/hgj_archer/front_idle/f000.png.meta @@ -0,0 +1,168 @@ +fileFormatVersion: 2 +guid: e0d9e04563411c949a226789ed94534f +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.02157} + 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: 557 + height: 890 + 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/hgj_archer/meta.json b/Assets/Resources/Units/hgj_archer/meta.json new file mode 100644 index 00000000..f5ee38cd --- /dev/null +++ b/Assets/Resources/Units/hgj_archer/meta.json @@ -0,0 +1,20 @@ +{ + "fps": 1, + "ppu": 100, + "frame": [ + 595, + 927 + ], + "pivot": [ + 0.5, + 0.02157 + ], + "charHeightPx": 887, + "clips": [ + { + "name": "front_idle", + "frames": 1, + "loop": true + } + ] +} \ No newline at end of file diff --git a/Assets/Resources/Units/hgj_archer/meta.json.meta b/Assets/Resources/Units/hgj_archer/meta.json.meta new file mode 100644 index 00000000..37e8e2fe --- /dev/null +++ b/Assets/Resources/Units/hgj_archer/meta.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: d046c89bed998a340bd6f9ecefbfc4f0 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Units/hgj_boss_zhangjiao.meta b/Assets/Resources/Units/hgj_boss_zhangjiao.meta new file mode 100644 index 00000000..c832be53 --- /dev/null +++ b/Assets/Resources/Units/hgj_boss_zhangjiao.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 09f436c99abc85c40903215547c36eaf +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Units/hgj_boss_zhangjiao/front_idle.meta b/Assets/Resources/Units/hgj_boss_zhangjiao/front_idle.meta new file mode 100644 index 00000000..22d2ee34 --- /dev/null +++ b/Assets/Resources/Units/hgj_boss_zhangjiao/front_idle.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d343dbcb4505382479e05bdfc7ab2ffe +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Units/hgj_boss_zhangjiao/front_idle/f000.png b/Assets/Resources/Units/hgj_boss_zhangjiao/front_idle/f000.png new file mode 100644 index 00000000..ce1214a9 Binary files /dev/null and b/Assets/Resources/Units/hgj_boss_zhangjiao/front_idle/f000.png differ diff --git a/Assets/Resources/Units/hgj_boss_zhangjiao/front_idle/f000.png.meta b/Assets/Resources/Units/hgj_boss_zhangjiao/front_idle/f000.png.meta new file mode 100644 index 00000000..325f9076 --- /dev/null +++ b/Assets/Resources/Units/hgj_boss_zhangjiao/front_idle/f000.png.meta @@ -0,0 +1,168 @@ +fileFormatVersion: 2 +guid: 17f44627146649542b114aa9b63c9dd1 +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.02119} + 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: 608 + height: 906 + 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/hgj_boss_zhangjiao/meta.json b/Assets/Resources/Units/hgj_boss_zhangjiao/meta.json new file mode 100644 index 00000000..fbae8e4e --- /dev/null +++ b/Assets/Resources/Units/hgj_boss_zhangjiao/meta.json @@ -0,0 +1,20 @@ +{ + "fps": 1, + "ppu": 100, + "frame": [ + 646, + 944 + ], + "pivot": [ + 0.5, + 0.02119 + ], + "charHeightPx": 904, + "clips": [ + { + "name": "front_idle", + "frames": 1, + "loop": true + } + ] +} \ No newline at end of file diff --git a/Assets/Resources/Units/hgj_boss_zhangjiao/meta.json.meta b/Assets/Resources/Units/hgj_boss_zhangjiao/meta.json.meta new file mode 100644 index 00000000..0ce6d6c9 --- /dev/null +++ b/Assets/Resources/Units/hgj_boss_zhangjiao/meta.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c4fddb826eaa7874cba807c3f1cc1903 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Units/hgj_cavalry.meta b/Assets/Resources/Units/hgj_cavalry.meta new file mode 100644 index 00000000..b739352b --- /dev/null +++ b/Assets/Resources/Units/hgj_cavalry.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e8fa108f337384f4fa47e6a21d775d21 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Units/hgj_cavalry/front_idle.meta b/Assets/Resources/Units/hgj_cavalry/front_idle.meta new file mode 100644 index 00000000..585dfa2f --- /dev/null +++ b/Assets/Resources/Units/hgj_cavalry/front_idle.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 07ca2b82651d3184f845bf4709a9692d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Units/hgj_cavalry/front_idle/f000.png b/Assets/Resources/Units/hgj_cavalry/front_idle/f000.png new file mode 100644 index 00000000..cbda342d Binary files /dev/null and b/Assets/Resources/Units/hgj_cavalry/front_idle/f000.png differ diff --git a/Assets/Resources/Units/hgj_cavalry/front_idle/f000.png.meta b/Assets/Resources/Units/hgj_cavalry/front_idle/f000.png.meta new file mode 100644 index 00000000..9b41093e --- /dev/null +++ b/Assets/Resources/Units/hgj_cavalry/front_idle/f000.png.meta @@ -0,0 +1,168 @@ +fileFormatVersion: 2 +guid: 9fed149a8ac54b94eb620fe7bf0ad83c +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.02083} + 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: 687 + height: 922 + 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/hgj_cavalry/meta.json b/Assets/Resources/Units/hgj_cavalry/meta.json new file mode 100644 index 00000000..0bf1cf6f --- /dev/null +++ b/Assets/Resources/Units/hgj_cavalry/meta.json @@ -0,0 +1,20 @@ +{ + "fps": 1, + "ppu": 100, + "frame": [ + 725, + 960 + ], + "pivot": [ + 0.5, + 0.02083 + ], + "charHeightPx": 920, + "clips": [ + { + "name": "front_idle", + "frames": 1, + "loop": true + } + ] +} \ No newline at end of file diff --git a/Assets/Resources/Units/hgj_cavalry/meta.json.meta b/Assets/Resources/Units/hgj_cavalry/meta.json.meta new file mode 100644 index 00000000..afd31545 --- /dev/null +++ b/Assets/Resources/Units/hgj_cavalry/meta.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: a7092a9a34597e54d90b46dbbde76bd4 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Units/hgj_infantry.meta b/Assets/Resources/Units/hgj_infantry.meta new file mode 100644 index 00000000..a1eb43e4 --- /dev/null +++ b/Assets/Resources/Units/hgj_infantry.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: da646cd4bb2c34f418b81a081dac92ed +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Units/hgj_infantry/front_idle.meta b/Assets/Resources/Units/hgj_infantry/front_idle.meta new file mode 100644 index 00000000..9d253b7e --- /dev/null +++ b/Assets/Resources/Units/hgj_infantry/front_idle.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6cad2bd92c97c484f8fc94ded468c7bb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Units/hgj_infantry/front_idle/f000.png b/Assets/Resources/Units/hgj_infantry/front_idle/f000.png new file mode 100644 index 00000000..4b7044d3 Binary files /dev/null and b/Assets/Resources/Units/hgj_infantry/front_idle/f000.png differ diff --git a/Assets/Resources/Units/hgj_infantry/front_idle/f000.png.meta b/Assets/Resources/Units/hgj_infantry/front_idle/f000.png.meta new file mode 100644 index 00000000..9fa290a4 --- /dev/null +++ b/Assets/Resources/Units/hgj_infantry/front_idle/f000.png.meta @@ -0,0 +1,168 @@ +fileFormatVersion: 2 +guid: fe11dbe17cc3fe840820473f273cf926 +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.02291} + 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: 835 + 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/hgj_infantry/meta.json b/Assets/Resources/Units/hgj_infantry/meta.json new file mode 100644 index 00000000..308aae0b --- /dev/null +++ b/Assets/Resources/Units/hgj_infantry/meta.json @@ -0,0 +1,20 @@ +{ + "fps": 1, + "ppu": 100, + "frame": [ + 570, + 873 + ], + "pivot": [ + 0.5, + 0.02291 + ], + "charHeightPx": 833, + "clips": [ + { + "name": "front_idle", + "frames": 1, + "loop": true + } + ] +} \ No newline at end of file diff --git a/Assets/Resources/Units/hgj_infantry/meta.json.meta b/Assets/Resources/Units/hgj_infantry/meta.json.meta new file mode 100644 index 00000000..6913281d --- /dev/null +++ b/Assets/Resources/Units/hgj_infantry/meta.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 3294e2cca1df12e4a82604ec8c6ad12d +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Units/hgj_spear.meta b/Assets/Resources/Units/hgj_spear.meta new file mode 100644 index 00000000..994d14ec --- /dev/null +++ b/Assets/Resources/Units/hgj_spear.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c1131a44c41c90e4483cfcd59e05716f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Units/hgj_spear/front_idle.meta b/Assets/Resources/Units/hgj_spear/front_idle.meta new file mode 100644 index 00000000..c3d9c57b --- /dev/null +++ b/Assets/Resources/Units/hgj_spear/front_idle.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 84f1180717c2745438b1b87279a68ce1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Units/hgj_spear/front_idle/f000.png b/Assets/Resources/Units/hgj_spear/front_idle/f000.png new file mode 100644 index 00000000..e96e711c Binary files /dev/null and b/Assets/Resources/Units/hgj_spear/front_idle/f000.png differ diff --git a/Assets/Resources/Units/hgj_spear/front_idle/f000.png.meta b/Assets/Resources/Units/hgj_spear/front_idle/f000.png.meta new file mode 100644 index 00000000..40c79b3d --- /dev/null +++ b/Assets/Resources/Units/hgj_spear/front_idle/f000.png.meta @@ -0,0 +1,168 @@ +fileFormatVersion: 2 +guid: dc29d8b6aee0ae141800576aff7e4518 +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.02232} + 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: 500 + height: 858 + 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/hgj_spear/meta.json b/Assets/Resources/Units/hgj_spear/meta.json new file mode 100644 index 00000000..c99032ef --- /dev/null +++ b/Assets/Resources/Units/hgj_spear/meta.json @@ -0,0 +1,20 @@ +{ + "fps": 1, + "ppu": 100, + "frame": [ + 538, + 896 + ], + "pivot": [ + 0.5, + 0.02232 + ], + "charHeightPx": 856, + "clips": [ + { + "name": "front_idle", + "frames": 1, + "loop": true + } + ] +} \ No newline at end of file diff --git a/Assets/Resources/Units/hgj_spear/meta.json.meta b/Assets/Resources/Units/hgj_spear/meta.json.meta new file mode 100644 index 00000000..4551d8bb --- /dev/null +++ b/Assets/Resources/Units/hgj_spear/meta.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 35d4a4ca7503dc84e896e62dbc609093 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Editor/BalanceDefaults.cs b/Assets/Scripts/Editor/BalanceDefaults.cs index 440ec598..2b4c902c 100644 --- a/Assets/Scripts/Editor/BalanceDefaults.cs +++ b/Assets/Scripts/Editor/BalanceDefaults.cs @@ -16,7 +16,7 @@ namespace TKS.EditorTools { Stats(UnitType.Infantry, 100, 30, 10, 4.5f, 0f, 0.45f), Stats(UnitType.Cavalry, 110, 28, 8, 6.5f, 0f, 0.45f), - Stats(UnitType.Archer, 70, 26, 4, 4.0f, 0f, 0.42f), // 궁병 사거리 = slingMaxDistance × archerRangeRatio (attackRange 미사용) + Stats(UnitType.Archer, 70, 26, 4, 4.0f, 0f, 0.42f), // 궁병 사거리 = slingMaxDistance (attackRange 미사용 · #1080) Stats(UnitType.Spear, 100, 30, 10, 4.5f, 2.2f, 0.45f), }; @@ -41,8 +41,12 @@ namespace TKS.EditorTools c.bossHpMult = 1.6f; c.bossRadiusMult = 1.25f; c.cavalryKnockback = 0.35f; - c.archerRangeRatio = 0.2f; // PD 2026-11-04: 슬링샷 범위 + 20 % + c.archerRangeRatio = 0.2f; // PD 2026-11-04: 사거리(슬링샷 범위) 밖 +20 % 안의 적에게 다가가 사격 + c.archerMeleeDealtRatio = 0.5f; // PD 2026-11-04 #1080: 궁수 근접 전투 피해 50 % + c.archerMeleeTakenRatio = 1.5f; // PD 2026-11-04 #1080: 궁수 근접 피격 +50 % + c.collisionPushRatio = 1f; // PD 2026-11-04 #1080: 보병 알까기 밀어내기 = 남은 거리 그대로 c.unitArtHeight = 1.5f; + c.boardArt = "battlefield_01"; // 원화 세션 1차 납품(2026-11-04) · Resources/Board/ c.minDragDistance = 0.35f; c.finalHitTolerance = 0.15f; c.moveSpeed = 9f; diff --git a/Assets/Scripts/Editor/UnitArtImporter.cs b/Assets/Scripts/Editor/UnitArtImporter.cs index 0652bce5..cb3a3a6b 100644 --- a/Assets/Scripts/Editor/UnitArtImporter.cs +++ b/Assets/Scripts/Editor/UnitArtImporter.cs @@ -11,10 +11,30 @@ namespace TKS.EditorTools public class UnitArtImporter : AssetPostprocessor { public const string Root = "Assets/Resources/Units/"; + /// 전장 배경(원화 세션 납품 · 5:8 불투명 · PPU 100 = 전장 20×32 월드). + public const string BoardRoot = "Assets/Resources/Board/"; void OnPreprocessTexture() { string path = assetPath.Replace('\\', '/'); + if (path.StartsWith(BoardRoot)) + { + var bi = (TextureImporter)assetImporter; + bi.textureType = TextureImporterType.Sprite; + bi.spriteImportMode = SpriteImportMode.Single; + bi.mipmapEnabled = false; + bi.filterMode = FilterMode.Bilinear; + bi.alphaIsTransparency = false; + bi.textureCompression = TextureImporterCompression.Compressed; + bi.maxTextureSize = 4096; + bi.spritePixelsPerUnit = 100f; + var bs = new TextureImporterSettings(); + bi.ReadTextureSettings(bs); + bs.spriteMeshType = SpriteMeshType.FullRect; + bs.spriteAlignment = (int)SpriteAlignment.Center; + bi.SetTextureSettings(bs); + return; + } if (!path.StartsWith(Root)) return; var ti = (TextureImporter)assetImporter; ti.textureType = TextureImporterType.Sprite; @@ -59,15 +79,18 @@ namespace TKS.EditorTools [MenuItem("TKS/Reimport Unit Art (유닛 아트 재임포트)")] public static void ReimportAll() { - string dir = Root.TrimEnd('/'); - if (!AssetDatabase.IsValidFolder(dir)) + foreach (var root in new[] { Root, BoardRoot }) { - Debug.Log("[TKS] " + dir + " 없음"); - return; + string dir = root.TrimEnd('/'); + if (!AssetDatabase.IsValidFolder(dir)) + { + Debug.Log("[TKS] " + dir + " 없음"); + continue; + } + AssetDatabase.ImportAsset(dir, ImportAssetOptions.ImportRecursive | ImportAssetOptions.ForceUpdate); + Debug.Log("[TKS] 아트 재임포트 완료 · " + dir); } - AssetDatabase.ImportAsset(dir, ImportAssetOptions.ImportRecursive | ImportAssetOptions.ForceUpdate); AssetDatabase.Refresh(); - Debug.Log("[TKS] 유닛 아트 재임포트 완료 · " + dir); } } } diff --git a/Assets/Scripts/Runtime/ActionResolver.cs b/Assets/Scripts/Runtime/ActionResolver.cs index ed12e804..b555fb77 100644 --- a/Assets/Scripts/Runtime/ActionResolver.cs +++ b/Assets/Scripts/Runtime/ActionResolver.cs @@ -11,22 +11,26 @@ namespace TKS public bool Returned; // 기병: 최종 목표점 명중 → 제자리 복귀 public bool Overwatch; // 창병: 최종 목표점 명중 → 대기(견제) public bool Crit; // 궁병: 최종 목표점 명중 → 크리티컬 - public bool MovedOnly; // 공격 없이 이동만 + public bool MovedOnly; // 행동 유닛 자신은 공격하지 않음(이동 · 밀어내기만) public int DamageDealt; public int CounterTaken; public List Attacked = new List(); + /// 충돌로 밀려난 유닛(아군·적군 · PD 2026-11-04 #1080). + public List Pushed = new List(); + /// 밀린 아군이 적과 닿아 얻은 공격 등 부가 설명(HUD 문구). + public List Notes = new List(); /// 실제로 지나간 경로(시작 포함). 창병 견제 판정용. public List Path = new List(); } /// - /// 슬링샷 벡터(시작점 → 목표점)를 병종 규칙대로 이동·공격으로 해석한다. - /// ① 보병: 경로 위 첫 적까지 이동 후 공격 · 목표점 명중 시 추가 이동 1회 - /// ② 기병: 경로 위 적을 모두 관통 피해 · 목표점까지 이동 · 목표점 명중 시 제자리 복귀 - /// ③ 창병: 보병과 동일 · 목표점 명중 시 대기 → 반경 안에서 움직이는 적에게 피해 - /// ④ 궁병: 조준 방향 슬링샷 거리 + 사거리(슬링샷 최대 × archerRangeRatio) 안에 적이 있으면 - /// 적 가장자리가 사거리에 들어올 때까지만 이동 후 사격(반격 없음) · 목표점 명중 시 크리티컬 · - /// 적이 없으면 목표점까지 이동만(PD 2026-11-04 2차 지시 · 1차의 「행동 취소」 폐기) + /// 슬링샷 벡터(시작점 → 목표점)를 병종 규칙대로 이동·공격으로 해석한다 (PD 2026-11-04 #1080 충돌 규칙). + /// ① 보병: 경로 위 첫 유닛(아군·적군)에 부딪히면 알까기처럼 그 유닛을 남은 힘만큼 밀어내고 자신은 멈춤 · 적이면 공격(반격 받음) · 목표점 명중 시 추가 이동 1회 + /// ② 기병: 유닛을 무시하고 관통 · 경로 위 적은 모두 피해(옆으로 밀림) · 아군은 지나칠 거리가 안 나오면 그 아군 직전에 멈춤 · 목표점 명중 시 제자리 복귀 + /// ③ 창병: 첫 유닛에 부딪히면 튕기지 않고 남은 거리만큼 밀며 함께 전진 · 적이면 피해(반격 받음) · 아군이면 밀기만 · 목표점 명중 시 대기(견제) + /// ④ 궁병: 사거리 = 슬링샷 최대 거리 · 조준 방향 사거리 안의 적은 제자리에서 사격 · 사거리 밖 ~ ×(1+비율) 안이면 들어올 만큼만 다가가 사격 · + /// 더 멀면 목표점까지 이동 · 반격 없음 · 목표점 명중 시 크리티컬 · 근접 전투는 피해 50 % · 피격 +50 %(Combat.Damage) + /// ⑤ 밀린 아군(행동 유닛과 같은 진영)이 상대 유닛과 닿으면 그 자리에서 공격 1회(조작마다 · 자기 행동은 소모하지 않음) /// public class ActionResolver { @@ -53,8 +57,10 @@ namespace TKS switch (u.Type) { case UnitType.Infantry: + yield return InfantryRoutine(u, origin, dir, dist, target, moveOnly, o); + break; case UnitType.Spear: - yield return MeleeRoutine(u, origin, dir, dist, target, moveOnly, o); + yield return SpearRoutine(u, origin, dir, dist, target, moveOnly, o); break; case UnitType.Cavalry: yield return CavalryRoutine(u, origin, dir, dist, target, moveOnly, o); @@ -67,7 +73,7 @@ namespace TKS // ---------- 미리보기(드라이런) ---------- - /// 조작 중 표시용: 이 슬링샷이 공격하게 될 적 목록. + /// 조작 중 표시용: 이 슬링샷으로 행동 유닛이 직접 공격하게 될 적 목록(밀린 아군의 공격은 예측하지 않음). public List PredictTargets(Unit u, Vector2 target, bool moveOnly) { var result = new List(); @@ -83,20 +89,21 @@ namespace TKS case UnitType.Infantry: case UnitType.Spear: { - var first = Combat.FirstEnemyOnPath(u, origin, dir, dist, out hitDist); - if (first != null && Combat.FreeTravel(u, origin, dir, hitDist, false) >= hitDist - 0.05f) result.Add(first); + var first = FirstUnitBeforeWall(u, origin, dir, dist, out hitDist); + if (first != null && first.Faction != u.Faction) result.Add(first); break; } case UnitType.Cavalry: { - float travel = Combat.FreeTravel(u, origin, dir, dist, false); + float travel = Combat.FreeTravel(u, origin, dir, dist, false, false); + travel = StopBeforeUnclearedAllies(u, origin, dir, travel); var dists = new List(); result.AddRange(Combat.EnemiesOnPath(u, origin, dir, travel, dists)); break; } case UnitType.Archer: { - var first = Combat.FirstEnemyOnPath(u, origin, dir, dist + u.AttackRange, out hitDist); + var first = Combat.FirstEnemyOnPath(u, origin, dir, u.AttackRange + u.ArcherMoveAllow, out hitDist); if (first != null) result.Add(first); break; } @@ -104,48 +111,134 @@ namespace TKS return result; } - // ---------- 보병 · 창병 ---------- + // ---------- 공통 질의 ---------- - IEnumerator MeleeRoutine(Unit u, Vector2 origin, Vector2 dir, float dist, Vector2 target, bool moveOnly, ActionOutcome o) + /// 경로 위 첫 유닛. 벽이 그보다 먼저 있으면 null. + Unit FirstUnitBeforeWall(Unit u, Vector2 origin, Vector2 dir, float dist, out float hitDist) { - float hitDist = 0f; - Unit first = moveOnly ? null : Combat.FirstEnemyOnPath(u, origin, dir, dist, out hitDist); + Unit first = Combat.FirstUnitOnPath(u, origin, dir, dist, out hitDist); + if (first == null) return null; + float wall = Combat.FreeTravel(u, origin, dir, dist, false, false); + if (hitDist > wall + Combat.Epsilon) + { + hitDist = 0f; + return null; + } + return first; + } + + // ---------- 보병: 알까기 충돌 ---------- + + IEnumerator InfantryRoutine(Unit u, Vector2 origin, Vector2 dir, float dist, Vector2 target, bool moveOnly, ActionOutcome o) + { + if (moveOnly) + { + yield return MoveFree(u, origin, dir, dist, o); + yield break; + } + + float hitDist; + Unit first = FirstUnitBeforeWall(u, origin, dir, dist, out hitDist); if (first == null) { - float free = Combat.FreeTravel(u, origin, dir, dist, true); - yield return Move(u, origin + dir * free, o); - o.MovedOnly = true; + yield return MoveFree(u, origin, dir, dist, o); yield break; } - float freeToEnemy = Combat.FreeTravel(u, origin, dir, hitDist, false); - if (freeToEnemy < hitDist - 0.05f) + Vector2 contact = origin + dir * hitDist; + yield return Move(u, contact, o); // 부딪힌 지점에서 멈춤 + float remaining = Mathf.Max(0f, dist - hitDist); + bool enemy = first.Faction != u.Faction; + bool isFinal = enemy && Combat.EnemyAtPoint(u, target, cfg.finalHitTolerance) == first; + + if (enemy) + { + yield return Attack(u, first, false, false, o, true); + if (!u.IsAlive) yield break; + } + else { - // 아군·벽이 먼저 막는다 → 거기까지만 이동 - yield return Move(u, origin + dir * freeToEnemy, o); o.MovedOnly = true; + } + + if (first.IsAlive) + { + // 알까기: 접촉 방향(행동 유닛 중심 → 부딪힌 유닛 중심)으로 남은 힘만큼 밀어낸다 + Vector2 n = first.Position - contact; + n = n.sqrMagnitude > 1e-6f ? n.normalized : dir; + yield return Push(first, n, remaining * cfg.collisionPushRatio, u, o); + if (!enemy) yield return PushedAllyAttack(first, o); + } + + if (isFinal && u.IsAlive) o.BonusMove = true; + } + + // ---------- 창병: 밀며 함께 전진 ---------- + + IEnumerator SpearRoutine(Unit u, Vector2 origin, Vector2 dir, float dist, Vector2 target, bool moveOnly, ActionOutcome o) + { + if (moveOnly) + { + yield return MoveFree(u, origin, dir, dist, o); yield break; } - yield return Move(u, origin + dir * hitDist, o); - Unit finalHit = Combat.EnemyAtPoint(u, target, cfg.finalHitTolerance); - bool isFinal = finalHit == first; - yield return Attack(u, first, false, false, o); - if (!u.IsAlive) yield break; + float hitDist; + Unit first = FirstUnitBeforeWall(u, origin, dir, dist, out hitDist); + if (first == null) + { + yield return MoveFree(u, origin, dir, dist, o); + yield break; + } - if (u.Type == UnitType.Infantry && isFinal) o.BonusMove = true; - if (u.Type == UnitType.Spear && isFinal) + Vector2 contact = origin + dir * hitDist; + yield return Move(u, contact, o); + float remaining = Mathf.Max(0f, dist - hitDist); + bool enemy = first.Faction != u.Faction; + bool isFinal = enemy && Combat.EnemyAtPoint(u, target, cfg.finalHitTolerance) == first; + + if (enemy) + { + yield return Attack(u, first, false, false, o, true); + if (!u.IsAlive) yield break; + } + else + { + o.MovedOnly = true; + } + + if (first.IsAlive && remaining > 0.01f) + { + // 튕기지 않고 앞 유닛을 밀며 함께 전진 · 앞 유닛이 다른 유닛·벽에 막히면 둘 다 멈춤 · 접촉 간격 유지 + float travel = Combat.FreeTravel(first, first.Position, dir, remaining, true, true, u); + if (travel > 0.01f) + { + Vector2 firstEnd = first.Position + dir * travel; + Vector2 spearEnd = contact + dir * travel; + Fx.Run(Fx.MoveAlong(first.transform, first.Position, firstEnd, cfg.moveSpeed, null)); + yield return Fx.MoveAlong(u.transform, contact, spearEnd, cfg.moveSpeed, null); + first.Position = firstEnd; + u.Position = spearEnd; + o.Path.Add(spearEnd); + battle.NotifyChanged(); + } + o.Pushed.Add(first); + if (!enemy) yield return PushedAllyAttack(first, o); + } + + if (isFinal && u.IsAlive) { u.SetOverwatch(true); o.Overwatch = true; } } - // ---------- 기병 ---------- + // ---------- 기병: 관통 ---------- IEnumerator CavalryRoutine(Unit u, Vector2 origin, Vector2 dir, float dist, Vector2 target, bool moveOnly, ActionOutcome o) { - float travel = Combat.FreeTravel(u, origin, dir, dist, false); + float travel = Combat.FreeTravel(u, origin, dir, dist, false, false); // 유닛은 무시 · 벽만 + travel = StopBeforeUnclearedAllies(u, origin, dir, travel); // 지나칠 수 없는 아군 직전에서 멈춤 var dists = new List(); var enemies = moveOnly ? new List() : Combat.EnemiesOnPath(u, origin, dir, travel, dists); Unit finalHit = moveOnly ? null : Combat.EnemyAtPoint(u, target, cfg.finalHitTolerance); @@ -209,7 +302,7 @@ namespace TKS void PierceHit(Unit cav, Unit e, Vector2 dir, ActionOutcome o) { if (!e.IsAlive) return; - int dmg = Combat.Damage(cfg, cav, e, false, rng); + int dmg = Combat.Damage(cfg, cav, e, false, rng, true); e.TakeDamage(dmg); o.Attacked.Add(e); o.DamageDealt += dmg; @@ -225,6 +318,33 @@ namespace TKS battle.NotifyChanged(); } + /// 아군은 관통(통과)하되 travel 안에 완전히 지나칠 수 없는 아군이 있으면 그 아군 직전까지로 줄인다. + float StopBeforeUnclearedAllies(Unit u, Vector2 origin, Vector2 dir, float travel) + { + float t = travel; + var allies = battle.AliveUnits(u.Faction); + for (int pass = 0; pass < 4; pass++) + { + float before = t; + foreach (var a in allies) + { + if (a == u) continue; + Vector2 rel = a.Position - origin; + float along = Vector2.Dot(rel, dir); + float lat = Mathf.Abs(rel.x * dir.y - rel.y * dir.x); + float sum = u.Radius + a.Radius; + if (lat >= sum || along + sum <= 0f) continue; // 경로와 겹치지 않음 · 뒤쪽 + float half = Mathf.Sqrt(sum * sum - lat * lat); + float touch = along - half; + float clear = along + half; + if (t >= clear || t <= touch) continue; // 완전히 지나침 · 닿기 전에 멈춤 + t = Mathf.Min(t, Mathf.Max(0f, touch - Combat.Epsilon)); + } + if (Mathf.Approximately(before, t)) break; + } + return t; + } + /// 종착점이 적과 겹치면 경로를 되짚어 겹치지 않는 지점까지 물러선다. Vector2 BackOffFromEnemies(Unit u, Vector2 origin, Vector2 dir, float travel) { @@ -251,27 +371,25 @@ namespace TKS IEnumerator ArcherRoutine(Unit u, Vector2 origin, Vector2 dir, float dist, Vector2 target, bool moveOnly, ActionOutcome o) { - // 조준 방향으로 슬링샷 거리 + 사거리 안의 첫 적. hitDist = 그 적 가장자리에 닿기까지의 이동 거리. + // 조준 방향으로 사거리 + 접근 허용 거리 안의 첫 적. hitDist = 그 적 가장자리에 닿기까지의 이동 거리(= 가장자리 간격). float hitDist = 0f; - Unit first = moveOnly ? null : Combat.FirstEnemyOnPath(u, origin, dir, dist + u.AttackRange, out hitDist); + Unit first = moveOnly ? null : Combat.FirstEnemyOnPath(u, origin, dir, u.AttackRange + u.ArcherMoveAllow, out hitDist); if (first == null) { - // 적이 없으면 목표점까지 이동(PD 2026-11-04 2차: 「슬링샷 범위 내 적이 없을 경우 해당 위치까지 이동」) - float free = Combat.FreeTravel(u, origin, dir, dist, true); - yield return Move(u, origin + dir * free, o); - o.MovedOnly = true; + // 공격 가능 범위에 적이 없으면 목표점까지 이동 (PD 2026-11-04 2차 지시) + yield return MoveFree(u, origin, dir, dist, o); yield break; } - // 적 가장자리까지 남은 간격이 사거리 안에 들어올 때까지만 이동(슬링샷 거리 상한) - float need = Mathf.Clamp(hitDist - u.AttackRange, 0f, dist); - float freeMove = Combat.FreeTravel(u, origin, dir, need, true); + // 사거리 안이면 제자리 · 밖이면 가장자리가 사거리에 들어올 만큼만 다가간다(접근 허용 거리 상한) + float need = Mathf.Clamp(hitDist - u.AttackRange, 0f, u.ArcherMoveAllow); + float freeMove = need > 0.01f ? Combat.FreeTravel(u, origin, dir, need, true) : 0f; if (freeMove > 0.01f) yield return Move(u, origin + dir * freeMove, o); if (hitDist - freeMove <= u.AttackRange + 0.05f) { bool crit = Combat.EnemyAtPoint(u, target, cfg.finalHitTolerance) == first; - yield return Attack(u, first, true, crit, o); + yield return Attack(u, first, true, crit, o, true); } else { @@ -281,6 +399,13 @@ namespace TKS // ---------- 공통 ---------- + IEnumerator MoveFree(Unit u, Vector2 origin, Vector2 dir, float dist, ActionOutcome o) + { + float free = Combat.FreeTravel(u, origin, dir, dist, true, true); + yield return Move(u, origin + dir * free, o); + o.MovedOnly = true; + } + IEnumerator Move(Unit u, Vector2 to, ActionOutcome o) { yield return Fx.MoveAlong(u.transform, u.Position, to, cfg.moveSpeed, null); @@ -288,32 +413,67 @@ namespace TKS o.Path.Add(to); } - IEnumerator Attack(Unit a, Unit d, bool ranged, bool crit, ActionOutcome o) + /// 부딪힌 유닛을 n 방향으로 force 만큼 밀어낸다(다른 유닛·벽에 닿으면 멈춤). 밀어 주는 유닛(pusher)은 막는 것으로 보지 않는다. + IEnumerator Push(Unit target, Vector2 n, float force, Unit pusher, ActionOutcome o) + { + if (target == null || !target.IsAlive || force < 0.01f) yield break; + float slide = Combat.FreeTravel(target, target.Position, n, force, true, true, pusher); + if (slide > 0.01f) + { + Vector2 end = battle.Board.ClampInside(target.Position + n * slide, target.Radius); + yield return Fx.MoveAlong(target.transform, target.Position, end, cfg.moveSpeed, null); + target.Position = end; + } + o.Pushed.Add(target); + battle.NotifyChanged(); + } + + /// 규칙 ⑤: 밀린 아군이 상대 유닛과 닿아 있으면 그 자리에서 공격 1회(근접 · 자기 행동 소모 없음). + IEnumerator PushedAllyAttack(Unit ally, ActionOutcome o) + { + if (ally == null || !ally.IsAlive) yield break; + Unit foe = Combat.TouchingOpponent(ally); + if (foe == null) yield break; + yield return Fx.Wait(0.1f); + yield return Attack(ally, foe, false, false, o, false); + } + + /// 공격 1회. byActor = 행동 유닛의 공격(결과 요약에 집계) · false = 밀린 아군의 공격(Notes 에 기록). + IEnumerator Attack(Unit a, Unit d, bool ranged, bool crit, ActionOutcome o, bool byActor) { if (a.View != null) a.View.PlayAttack(); if (ranged) yield return Fx.Arrow(a.Position, d.Position); else yield return Fx.Lunge(a, d.Position); - int dmg = Combat.Damage(cfg, a, d, crit, rng); + int dmg = Combat.Damage(cfg, a, d, crit, rng, !ranged); d.TakeDamage(dmg); - o.Attacked.Add(d); - o.DamageDealt += dmg; - o.Crit |= crit; + if (byActor) + { + o.Attacked.Add(d); + o.DamageDealt += dmg; + o.Crit |= crit; + } Fx.Popup(d.Position, crit ? dmg + "!" : dmg.ToString(), crit ? new Color(1f, 0.7f, 0.2f) : Color.white); battle.NotifyChanged(); yield return Fx.Wait(0.2f); + int counter = 0; if (!ranged && d.IsAlive && a.IsAlive) { - int c = Combat.CounterDamage(cfg, d, a, rng); + counter = Combat.CounterDamage(cfg, d, a, rng); if (d.View != null) d.View.PlayAttack(); yield return Fx.Lunge(d, a.Position); - a.TakeDamage(c); - o.CounterTaken += c; - Fx.Popup(a.Position, c.ToString(), new Color(1f, 0.45f, 0.45f)); + a.TakeDamage(counter); + if (byActor) o.CounterTaken += counter; + Fx.Popup(a.Position, counter.ToString(), new Color(1f, 0.45f, 0.45f)); battle.NotifyChanged(); yield return Fx.Wait(0.2f); } + + if (!byActor) + { + o.Notes.Add("밀린 " + a.DisplayName + " → " + d.DisplayName + " 공격 " + dmg + (counter > 0 ? " · 반격 " + counter : "")); + } } } } diff --git a/Assets/Scripts/Runtime/BalanceConfig.cs b/Assets/Scripts/Runtime/BalanceConfig.cs index c8b65c75..72b536eb 100644 --- a/Assets/Scripts/Runtime/BalanceConfig.cs +++ b/Assets/Scripts/Runtime/BalanceConfig.cs @@ -20,7 +20,7 @@ namespace TKS public int def; [Tooltip("슬링샷으로 지정할 수 있는 최대 거리(월드 단위)")] public float slingMaxDistance; - [Tooltip("창병 대기(견제) 반경 · 궁병은 쓰지 않음(사거리 = slingMaxDistance × archerRangeRatio)")] + [Tooltip("창병 대기(견제) 반경 · 궁병은 쓰지 않음(사거리 = slingMaxDistance)")] public float attackRange; public float radius; } @@ -81,13 +81,23 @@ namespace TKS [Tooltip("기병 관통 시 적을 옆으로 밀어내는 거리")] public float cavalryKnockback = 0.35f; - [Header("궁병 규칙 (PD 2026-11-04)")] - [Tooltip("궁병 사거리 = 슬링샷 최대 거리 × 비율. 조준 방향의 슬링샷 거리 + 사거리 안에 적이 있을 때만 행동 가능(없으면 놓아도 취소) · 적 가장자리가 사거리에 들어올 때까지만 이동 후 사격")] + [Header("궁병 규칙 (PD 2026-11-04 · #1080)")] + [Tooltip("궁병 사거리 = 슬링샷 최대 거리(얇은 원 · 안의 적은 제자리 사격). 그 밖 ~ 사거리 × (1 + 비율) 안(붉은 도넛)의 적은 사거리에 들어올 만큼만 다가가 사격 · 더 멀면 목표점까지 이동")] public float archerRangeRatio = 0.2f; + [Tooltip("궁병이 근접 유닛(보병·기병·창병)과 근접 전투(돌진·반격·관통·견제·밀려 닿은 공격)할 때 주는 피해 배율 · 원거리 사격은 1")] + public float archerMeleeDealtRatio = 0.5f; + [Tooltip("궁병이 근접 유닛에게 근접으로 맞을 때 받는 피해 배율(상성 배율과 곱)")] + public float archerMeleeTakenRatio = 1.5f; + + [Header("충돌 (PD 2026-11-04 · #1080)")] + [Tooltip("보병 알까기: 부딪힌 유닛(아군·적군)이 밀려나는 거리 = 충돌 시 남은 슬링샷 거리 × 비율 · 창병은 비율 없이 남은 거리만큼 밀며 함께 전진")] + public float collisionPushRatio = 1f; [Header("표시")] [Tooltip("유닛 아트(스프라이트) 세로 크기 · 월드 단위 · 장수는 반지름 배율만큼 커진다")] public float unitArtHeight = 1.5f; + [Tooltip("Resources/Board/<이름> 전장 배경 스프라이트(원화 세션 납품 · 5:8) · 비면 도형·격자 바닥")] + public string boardArt = "battlefield_01"; [Header("조작")] [Tooltip("이보다 짧게 당기면 취소")] diff --git a/Assets/Scripts/Runtime/BattleHUD.cs b/Assets/Scripts/Runtime/BattleHUD.cs index 9a000624..15c5d197 100644 --- a/Assets/Scripts/Runtime/BattleHUD.cs +++ b/Assets/Scripts/Runtime/BattleHUD.cs @@ -189,7 +189,7 @@ namespace TKS string line1 = side + " · " + u.DisplayName + " · " + UnitTypeInfo.Korean(u.Type) + (u.IsBoss ? " (장수)" : ""); string line2 = "HP " + u.Hp + "/" + u.MaxHp + " 공 " + u.Atk + " 방 " + u.Def; string line3 = "슬링 " + u.SlingMaxDistance.ToString("0.#"); - if (u.Type == UnitType.Archer) line3 += " 사거리 " + u.AttackRange.ToString("0.#") + " (슬링 +" + Mathf.RoundToInt(battle.Config.archerRangeRatio * 100f) + " %)"; + if (u.Type == UnitType.Archer) line3 += " 사거리 " + u.AttackRange.ToString("0.#") + " (접근 +" + u.ArcherMoveAllow.ToString("0.#") + ")"; if (u.Type == UnitType.Spear) line3 += " 견제 반경 " + u.AttackRange.ToString("0.#"); string state = ""; if (u.Faction == Faction.Player) diff --git a/Assets/Scripts/Runtime/BattleManager.cs b/Assets/Scripts/Runtime/BattleManager.cs index 58e1aeec..edc8b99f 100644 --- a/Assets/Scripts/Runtime/BattleManager.cs +++ b/Assets/Scripts/Runtime/BattleManager.cs @@ -184,11 +184,11 @@ namespace TKS return Phase == BattlePhase.PlayerTurn && u != null && u.Faction == Faction.Player && u.IsAlive && !u.ActedThisTurn; } - /// 궁병 공격 가능 범위(슬링샷 최대 + 사거리 · 가장자리 간격 기준) 안에 상대 유닛이 하나라도 있는가 — 도넛 색 표시용. + /// 궁병 공격 가능 범위(사거리 + 접근 허용 거리 · 가장자리 간격 기준) 안에 상대 유닛이 하나라도 있는가 — 도넛 색 표시용. public bool AnyEnemyWithinArcherReach(Unit u) { if (u == null) return false; - float reach = u.SlingMaxDistance + u.AttackRange; + float reach = u.AttackRange + u.ArcherMoveAllow; Faction other = u.Faction == Faction.Player ? Faction.Enemy : Faction.Player; foreach (var e in AliveUnits(other)) { @@ -383,18 +383,32 @@ namespace TKS static string Describe(Unit u, ActionOutcome o, bool moveOnly) { string who = u.DisplayName + "(" + UnitTypeInfo.Korean(u.Type) + ")"; + string s; if (o.Attacked.Count == 0) { - return who + (moveOnly ? " 추가 이동" : " 이동"); + s = who + (moveOnly ? " 추가 이동" : " 이동"); } - var names = new List(); - foreach (var a in o.Attacked) + else { - if (!names.Contains(a.DisplayName)) names.Add(a.DisplayName); + var names = new List(); + foreach (var a in o.Attacked) + { + if (!names.Contains(a.DisplayName)) names.Add(a.DisplayName); + } + s = who + " → " + string.Join(", ", names.ToArray()) + " 공격 " + o.DamageDealt; + if (o.Crit) s += " 크리티컬!"; + if (o.CounterTaken > 0) s += " · 반격 " + o.CounterTaken; } - string s = who + " → " + string.Join(", ", names.ToArray()) + " 공격 " + o.DamageDealt; - if (o.Crit) s += " 크리티컬!"; - if (o.CounterTaken > 0) s += " · 반격 " + o.CounterTaken; + if (o.Pushed.Count > 0) + { + var pushed = new List(); + foreach (var p in o.Pushed) + { + if (!pushed.Contains(p.DisplayName)) pushed.Add(p.DisplayName); + } + s += " · " + string.Join(", ", pushed.ToArray()) + " 밀어냄"; + } + foreach (var n in o.Notes) s += " · " + n; if (o.BonusMove) s += " · 추가 이동!"; if (o.Returned) s += " · 제자리 복귀"; if (o.Overwatch) s += " · 대기(견제) 발동"; diff --git a/Assets/Scripts/Runtime/Board.cs b/Assets/Scripts/Runtime/Board.cs index 9799f2db..31482d44 100644 --- a/Assets/Scripts/Runtime/Board.cs +++ b/Assets/Scripts/Runtime/Board.cs @@ -7,48 +7,61 @@ namespace TKS { } - /// 전장(바닥·격자·테두리·4면 벽 콜라이더). 화면보다 넓어 카메라로 스크롤한다. + /// 전장(바닥 = 원화 배경 또는 도형·격자 · 테두리 · 4면 벽 콜라이더). 화면보다 넓어 카메라로 스크롤한다. public class Board : MonoBehaviour { public Vector2 Size { get; private set; } + /// Resources/Board/<boardArt> 원화 배경을 썼는가(없으면 도형·격자). + public bool HasArt { get; private set; } public Rect Rect { get { return new Rect(-Size.x * 0.5f, -Size.y * 0.5f, Size.x, Size.y); } } - public void Build(Vector2 size) + public void Build(Vector2 size, string boardArt = null) { Size = size; float w = size.x; float h = size.y; - var bg = ProceduralSprites.NewSprite(transform, "Background", ProceduralSprites.Square, new Color(0.17f, 0.24f, 0.17f), 1f, -20); - bg.transform.localScale = new Vector3(w, h, 1f); - - // 아군·적군 진영 구분용 옅은 띠 - var enemyHalf = ProceduralSprites.NewSprite(transform, "EnemyHalf", ProceduralSprites.Square, new Color(0.45f, 0.2f, 0.2f, 0.18f), 1f, -19); - enemyHalf.transform.localScale = new Vector3(w, h * 0.5f, 1f); - enemyHalf.transform.localPosition = new Vector3(0f, h * 0.25f, 0f); - - // 격자(4 단위) — 스크롤 체감용 - var gridColor = new Color(1f, 1f, 1f, 0.07f); - const float gridStep = 4f; - for (float x = -w * 0.5f + gridStep; x < w * 0.5f - 0.01f; x += gridStep) + Sprite art = string.IsNullOrEmpty(boardArt) ? null : Resources.Load("Board/" + boardArt); + HasArt = art != null; + if (HasArt) { - var g = ProceduralSprites.NewSprite(transform, "GridV", ProceduralSprites.Square, gridColor, 1f, -18); - g.transform.localPosition = new Vector3(x, 0f, 0f); - g.transform.localScale = new Vector3(0.04f, h, 1f); + // 원화 세션 납품 배경(5:8 · 위 = 적 진영) — 전장 크기에 맞춰 늘린다 · 격자·진영 띠는 그리지 않음 + var bg = ProceduralSprites.NewSprite(transform, "Background", art, Color.white, 1f, -20); + bg.transform.localScale = new Vector3(w / art.bounds.size.x, h / art.bounds.size.y, 1f); } - for (float y = -h * 0.5f + gridStep; y < h * 0.5f - 0.01f; y += gridStep) + else { - var g = ProceduralSprites.NewSprite(transform, "GridH", ProceduralSprites.Square, gridColor, 1f, -18); - g.transform.localPosition = new Vector3(0f, y, 0f); - g.transform.localScale = new Vector3(w, 0.04f, 1f); - } + var bg = ProceduralSprites.NewSprite(transform, "Background", ProceduralSprites.Square, new Color(0.17f, 0.24f, 0.17f), 1f, -20); + bg.transform.localScale = new Vector3(w, h, 1f); - var mid = ProceduralSprites.NewSprite(transform, "MidLine", ProceduralSprites.Square, new Color(1f, 1f, 1f, 0.14f), 1f, -17); - mid.transform.localScale = new Vector3(w, 0.06f, 1f); + // 아군·적군 진영 구분용 옅은 띠 + var enemyHalf = ProceduralSprites.NewSprite(transform, "EnemyHalf", ProceduralSprites.Square, new Color(0.45f, 0.2f, 0.2f, 0.18f), 1f, -19); + enemyHalf.transform.localScale = new Vector3(w, h * 0.5f, 1f); + enemyHalf.transform.localPosition = new Vector3(0f, h * 0.25f, 0f); + + // 격자(4 단위) — 스크롤 체감용 + var gridColor = new Color(1f, 1f, 1f, 0.07f); + const float gridStep = 4f; + for (float x = -w * 0.5f + gridStep; x < w * 0.5f - 0.01f; x += gridStep) + { + var g = ProceduralSprites.NewSprite(transform, "GridV", ProceduralSprites.Square, gridColor, 1f, -18); + g.transform.localPosition = new Vector3(x, 0f, 0f); + g.transform.localScale = new Vector3(0.04f, h, 1f); + } + for (float y = -h * 0.5f + gridStep; y < h * 0.5f - 0.01f; y += gridStep) + { + var g = ProceduralSprites.NewSprite(transform, "GridH", ProceduralSprites.Square, gridColor, 1f, -18); + g.transform.localPosition = new Vector3(0f, y, 0f); + g.transform.localScale = new Vector3(w, 0.04f, 1f); + } + + var mid = ProceduralSprites.NewSprite(transform, "MidLine", ProceduralSprites.Square, new Color(1f, 1f, 1f, 0.14f), 1f, -17); + mid.transform.localScale = new Vector3(w, 0.06f, 1f); + } // 테두리 var borderColor = new Color(0.85f, 0.75f, 0.45f); diff --git a/Assets/Scripts/Runtime/Combat.cs b/Assets/Scripts/Runtime/Combat.cs index 67171dd3..29653fa6 100644 --- a/Assets/Scripts/Runtime/Combat.cs +++ b/Assets/Scripts/Runtime/Combat.cs @@ -8,27 +8,39 @@ namespace TKS { /// 경로 질의에 쓰는 원 반지름 배율(살짝 작게 캐스트해 스침을 관대하게). public const float CastRadiusScale = 0.9f; - const float Epsilon = 0.02f; + public const float Epsilon = 0.02f; + /// 두 유닛 가장자리 간격이 이 이하면 「닿아 있다」(밀린 아군의 공격 기회 판정). + public const float ContactTolerance = 0.12f; // ---------- 피해 공식 ---------- - public static int Damage(BalanceConfig cfg, Unit attacker, Unit defender, bool crit, System.Random rng) + /// + /// 피해 = (공격 × 상성 × 크리 − 방어 × defenseFactor) × 궁병 근접 배율 × 난수. + /// melee = 근접 전투(돌진·반격·관통·견제·밀려 닿은 공격). 궁병이 근접 유닛(보병·기병·창병)과 근접 전투하면 + /// 주는 피해 × archerMeleeDealtRatio · 받는 피해 × archerMeleeTakenRatio (PD 2026-11-04 #1080) · 원거리 사격은 패널티 없음. + /// + public static int Damage(BalanceConfig cfg, Unit attacker, Unit defender, bool crit, System.Random rng, bool melee) { float mult = cfg.Matchup(attacker.Type, defender.Type); float raw = attacker.Atk * mult * (crit ? cfg.critMultiplier : 1f) - defender.Def * cfg.defenseFactor; + if (melee) + { + if (attacker.Type == UnitType.Archer && UnitTypeInfo.IsMelee(defender.Type)) raw *= cfg.archerMeleeDealtRatio; + if (defender.Type == UnitType.Archer && UnitTypeInfo.IsMelee(attacker.Type)) raw *= cfg.archerMeleeTakenRatio; + } float variance = 1f + ((float)rng.NextDouble() * 2f - 1f) * cfg.damageVariance; return Mathf.Max(1, Mathf.RoundToInt(raw * variance)); } public static int CounterDamage(BalanceConfig cfg, Unit defender, Unit attacker, System.Random rng) { - int baseDmg = Damage(cfg, defender, attacker, false, rng); + int baseDmg = Damage(cfg, defender, attacker, false, rng, true); return Mathf.Max(1, Mathf.RoundToInt(baseDmg * cfg.counterRatio)); } public static int OverwatchDamage(BalanceConfig cfg, Unit spear, Unit mover, System.Random rng) { - int baseDmg = Damage(cfg, spear, mover, false, rng); + int baseDmg = Damage(cfg, spear, mover, false, rng, true); return Mathf.Max(1, Mathf.RoundToInt(baseDmg * cfg.overwatchDamageRatio)); } @@ -61,6 +73,40 @@ namespace TKS return null; } + /// 경로(원 캐스트) 위 가장 가까운 유닛(아군·적군 불문). hitDist = 닿기까지 이동 거리. 벽은 무시한다(호출 쪽에서 FreeTravel 과 비교). + public static Unit FirstUnitOnPath(Unit actor, Vector2 origin, Vector2 dir, float dist, out float hitDist) + { + hitDist = 0f; + foreach (var h in Cast(actor, origin, dir, dist)) + { + var u = UnitOf(h.collider); + if (u == null || u == actor || !u.IsAlive) continue; + hitDist = h.distance; + return u; + } + return null; + } + + /// u 와 가장자리가 닿아 있는(ContactTolerance 이내) 가장 가까운 상대 진영 유닛. + public static Unit TouchingOpponent(Unit u) + { + Physics2D.SyncTransforms(); + Unit best = null; + float bestGap = float.MaxValue; + foreach (var c in Physics2D.OverlapCircleAll(u.Position, u.Radius + ContactTolerance + 0.5f)) + { + var o = UnitOf(c); + if (o == null || o == u || !o.IsAlive || o.Faction == u.Faction) continue; + float gap = Vector2.Distance(u.Position, o.Position) - u.Radius - o.Radius; + if (gap <= ContactTolerance && gap < bestGap) + { + bestGap = gap; + best = o; + } + } + return best; + } + /// 경로 위의 모든 적(가까운 순)과 각 접촉 거리. public static List EnemiesOnPath(Unit actor, Vector2 origin, Vector2 dir, float dist, List distances) { @@ -77,8 +123,8 @@ namespace TKS return list; } - /// 벽·(옵션) 유닛에 막히기 전까지 실제로 나아갈 수 있는 거리. - public static float FreeTravel(Unit actor, Vector2 origin, Vector2 dir, float dist, bool enemiesBlock, bool friendsBlock = true) + /// 벽·(옵션) 유닛에 막히기 전까지 실제로 나아갈 수 있는 거리. ignore = 밀어 주는 유닛처럼 출발 지점에서 닿아 있어도 무시할 유닛. + public static float FreeTravel(Unit actor, Vector2 origin, Vector2 dir, float dist, bool enemiesBlock, bool friendsBlock = true, Unit ignore = null) { float min = dist; foreach (var h in Cast(actor, origin, dir, dist)) @@ -89,7 +135,7 @@ namespace TKS continue; } var u = UnitOf(h.collider); - if (u == null || u == actor || !u.IsAlive) continue; + if (u == null || u == actor || u == ignore || !u.IsAlive) continue; bool enemy = u.Faction != actor.Faction; if (enemy && !enemiesBlock) continue; if (!enemy && !friendsBlock) continue; diff --git a/Assets/Scripts/Runtime/GameBootstrap.cs b/Assets/Scripts/Runtime/GameBootstrap.cs index d6db3287..77362cb2 100644 --- a/Assets/Scripts/Runtime/GameBootstrap.cs +++ b/Assets/Scripts/Runtime/GameBootstrap.cs @@ -39,7 +39,7 @@ namespace TKS cam.transparencySortAxis = Vector3.up; var board = new GameObject("Board").AddComponent(); - board.Build(Config.boardSize); + board.Build(Config.boardSize, Config.boardArt); CameraCtrl = cam.GetComponent(); if (CameraCtrl == null) CameraCtrl = cam.gameObject.AddComponent(); diff --git a/Assets/Scripts/Runtime/Unit.cs b/Assets/Scripts/Runtime/Unit.cs index fbaaf7f5..3cd04ac3 100644 --- a/Assets/Scripts/Runtime/Unit.cs +++ b/Assets/Scripts/Runtime/Unit.cs @@ -17,8 +17,10 @@ namespace TKS public int Def; public float Radius; public float SlingMaxDistance; - /// 궁병 = 슬링샷 최대 거리 × archerRangeRatio (적 가장자리까지의 간격 기준) · 창병 = 대기(견제) 반경. + /// 궁병 = 사거리 = 슬링샷 최대 거리(적 가장자리까지의 간격 기준 · 제자리 사격) · 창병 = 대기(견제) 반경. public float AttackRange; + /// 궁병이 사거리 밖(~ 사거리 × (1 + archerRangeRatio))의 적에게 다가갈 수 있는 최대 거리. 다른 병종 = 0. + public float ArcherMoveAllow; /// Resources/Units/<ArtId>/ 아트 폴더 · 비면 도형. public string ArtId = ""; /// 아트 세로 크기(월드) = unitArtHeight × 반지름 배율. @@ -61,8 +63,9 @@ namespace TKS Radius = s.radius * radiusMult; ArtHeight = cfg.unitArtHeight * radiusMult; SlingMaxDistance = s.slingMaxDistance; - // PD 2026-11-04: 궁병 사거리 = 슬링샷 범위의 비율(+20 %) · 창병은 자산의 대기 반경 - AttackRange = type == UnitType.Archer ? s.slingMaxDistance * cfg.archerRangeRatio : s.attackRange; + // PD 2026-11-04 #1080: 궁병 사거리 = 슬링샷 범위(제자리 사격) · 그 밖 +비율 안의 적은 들어올 만큼만 다가가 사격 · 창병은 자산의 대기 반경 + AttackRange = type == UnitType.Archer ? s.slingMaxDistance : s.attackRange; + ArcherMoveAllow = type == UnitType.Archer ? s.slingMaxDistance * cfg.archerRangeRatio : 0f; gameObject.name = (faction == Faction.Player ? "P_" : "E_") + displayName; Collider = GetComponent(); diff --git a/Assets/Tests/PlayMode/BattleFlowTests.cs b/Assets/Tests/PlayMode/BattleFlowTests.cs index 7d1a9a1a..2e93fcf8 100644 --- a/Assets/Tests/PlayMode/BattleFlowTests.cs +++ b/Assets/Tests/PlayMode/BattleFlowTests.cs @@ -7,7 +7,7 @@ using UnityEngine.TestTools; namespace TKS.Tests { - /// 병종 4종 규칙·턴 흐름·승리 판정을 실제 씬에서 검증한다(헤드리스 실행 가능). + /// 병종 4종 규칙(PD 2026-11-04 #1080 충돌 규칙 포함)·턴 흐름·승리 판정을 실제 씬에서 검증한다(헤드리스 실행 가능). public class BattleFlowTests { BattleManager bm; @@ -40,6 +40,17 @@ namespace TKS.Tests yield return null; // 파괴된 콜라이더가 물리 월드에서 빠질 시간 } + /// 경로 질의가 쓰는 접촉 거리(행동 유닛 캐스트 반지름 + 상대 반지름). + static float CastContact(Unit mover, Unit other) + { + return mover.Radius * Combat.CastRadiusScale + other.Radius; + } + + static float Gap(Unit a, Unit b) + { + return Vector2.Distance(a.Position, b.Position) - a.Radius - b.Radius; + } + [UnityTest] public IEnumerator Bootstrap_SpawnsHeroesAndStageEnemies() { @@ -64,19 +75,24 @@ namespace TKS.Tests Assert.Greater(c.Matchup(UnitType.Spear, UnitType.Archer), 1f); } + // ---------- 보병 ---------- + [UnityTest] - public IEnumerator Infantry_AttacksFirstEnemyOnPath_BonusMoveOnFinalHit() + public IEnumerator Infantry_HitsEnemy_StopsAtContact_PushesIt_BonusMoveOnFinalHit() { yield return Fresh(); var inf = bm.SpawnUnit(UnitType.Infantry, Faction.Player, new Vector2(0f, -3f), "보병"); var foe = bm.SpawnUnit(UnitType.Spear, Faction.Enemy, new Vector2(0f, 0f), "적창병"); + float contactY = -3f + (3f - CastContact(inf, foe)); var o = new ActionOutcome(); yield return bm.ResolveForTest(inf, foe.Position, false, o); Assert.Contains(foe, o.Attacked); - Assert.Less(foe.Hp, foe.MaxHp, "경로 위 첫 적을 공격"); + Assert.Less(foe.Hp, foe.MaxHp, "부딪힌 적을 공격"); Assert.IsTrue(o.BonusMove, "최종 목표점 명중 → 추가 이동"); - Assert.Less(Vector2.Distance(inf.Position, foe.Position), inf.Radius + foe.Radius + 0.2f, "적에 닿는 지점까지 이동"); + Assert.AreEqual(contactY, inf.Position.y, 0.1f, "보병은 부딪힌 지점에서 멈춘다(알까기)"); + Assert.Contains(foe, o.Pushed, "부딪힌 유닛은 밀려난다"); + Assert.Greater(foe.Position.y, 0.3f, "적이 남은 힘만큼 밀려남"); Assert.Less(inf.Hp, inf.MaxHp, "근접 공격은 반격 피해를 받는다"); int foeHp = foe.Hp; @@ -99,6 +115,39 @@ namespace TKS.Tests Assert.IsFalse(o.BonusMove); } + [UnityTest] + public IEnumerator Infantry_PushesAlly_AllyAttacksTouchingEnemy_OncePerPush() + { + yield return Fresh(); + // A(보병) 가 B(아군 창병)를 +x 로 밀어 적에게 붙이면 B 가 공격 · C 가 B 를 다시 밀면 B 가 또 공격 (규칙 ⑤) + var a = bm.SpawnUnit(UnitType.Infantry, Faction.Player, new Vector2(-3f, -2f), "보병A"); + var b = bm.SpawnUnit(UnitType.Spear, Faction.Player, new Vector2(0f, -2f), "창병B"); + float pushX = CastContact(a, b); // A 는 3 − 접촉거리 만큼 가서 닿으므로 남는 힘(= 밀리는 거리) = 접촉거리 + var foe = bm.SpawnUnit(UnitType.Infantry, Faction.Enemy, new Vector2(pushX, -2f + b.Radius + 0.45f + 0.05f), "적보병"); + Assert.AreEqual(b.MaxHp, b.Hp); + + var o = new ActionOutcome(); + yield return bm.ResolveForTest(a, new Vector2(0f, -2f), false, o); + Assert.AreEqual(0, o.Attacked.Count, "아군에 부딪힌 보병 자신은 공격하지 않음"); + Assert.Contains(b, o.Pushed); + Assert.AreEqual(pushX, b.Position.x, 0.1f, "B 가 남은 힘만큼 밀려남"); + Assert.LessOrEqual(Gap(b, foe), Combat.ContactTolerance + 0.05f, "밀려서 적과 닿음"); + Assert.Less(foe.Hp, foe.MaxHp, "밀린 아군 B 가 적을 공격"); + Assert.AreEqual(a.MaxHp, a.Hp, "A 는 피해 없음"); + Assert.IsFalse(b.ActedThisTurn, "B 의 공격은 자기 행동을 소모하지 않음"); + Assert.AreEqual(1, o.Notes.Count); + + int hp = foe.Hp; + var c = bm.SpawnUnit(UnitType.Infantry, Faction.Player, new Vector2(pushX, -5f), "보병C"); + var o2 = new ActionOutcome(); + yield return bm.ResolveForTest(c, new Vector2(pushX, -2.2f), false, o2); + Assert.Contains(b, o2.Pushed, "C 가 B 를 다시 밀었다"); + Assert.Less(foe.Hp, hp, "B 가 C 의 기회로 또 공격"); + Assert.AreEqual(0, o2.Attacked.Count); + } + + // ---------- 기병 ---------- + [UnityTest] public IEnumerator Cavalry_PiercesAllOnPath_AndReturnsOnFinalHit() { @@ -129,41 +178,82 @@ namespace TKS.Tests } [UnityTest] - public IEnumerator Archer_RangeIsSlingTimesRatio_MovesIntoRange_ShootsWithoutCounter() + public IEnumerator Cavalry_PassesThroughAlly_OrStopsJustBeforeIt() + { + yield return Fresh(); + var cav = bm.SpawnUnit(UnitType.Cavalry, Faction.Player, new Vector2(0f, -4f), "기병"); + var ally = bm.SpawnUnit(UnitType.Infantry, Faction.Player, new Vector2(0f, -1.5f), "아군보병"); + var o = new ActionOutcome(); + yield return bm.ResolveForTest(cav, new Vector2(0f, 2f), false, o); + Assert.AreEqual(2f, cav.Position.y, 0.1f, "아군을 관통해 목표점까지"); + Assert.AreEqual(-1.5f, ally.Position.y, 0.01f, "아군은 밀리지 않음"); + Assert.AreEqual(0, o.Pushed.Count); + + var cav2 = bm.SpawnUnit(UnitType.Cavalry, Faction.Player, new Vector2(4f, -4f), "기병2"); + var ally2 = bm.SpawnUnit(UnitType.Infantry, Faction.Player, new Vector2(4f, -1.5f), "아군2"); + float sum = cav2.Radius + ally2.Radius; + var o2 = new ActionOutcome(); + yield return bm.ResolveForTest(cav2, new Vector2(4f, -1.5f + sum * 0.5f), false, o2); // 지나칠 거리가 안 나옴 + Assert.AreEqual(-1.5f - sum, cav2.Position.y, 0.1f, "통과할 거리가 안 나오면 아군 직전에 멈춤"); + Assert.GreaterOrEqual(Vector2.Distance(cav2.Position, ally2.Position), sum - 0.05f, "아군과 겹치지 않음"); + Assert.AreEqual(-1.5f, ally2.Position.y, 0.01f); + } + + // ---------- 궁병 ---------- + + [UnityTest] + public IEnumerator Archer_ShootsInPlace_WhenEnemyWithinSlingRange() { yield return Fresh(); var arc = bm.SpawnUnit(UnitType.Archer, Faction.Player, new Vector2(0f, -5f), "궁병"); - Assert.AreEqual(arc.SlingMaxDistance * cfg.archerRangeRatio, arc.AttackRange, 0.001f, "궁병 사거리 = 슬링샷 최대 × 비율 (PD 2026-11-04 · +20 %)"); - // 적 가장자리까지 4.8 − 반지름 합 ≈ 4.0 ≤ 슬링샷 4.0 + 사거리 0.8 → 행동 가능 · 목표점 (0,−1) 은 적 원 밖(크리 아님) - var foe = bm.SpawnUnit(UnitType.Infantry, Faction.Enemy, new Vector2(0f, -0.2f), "적보병"); + Assert.AreEqual(arc.SlingMaxDistance, arc.AttackRange, 0.001f, "궁병 사거리 = 슬링샷 범위 (PD #1080)"); + Assert.AreEqual(arc.SlingMaxDistance * cfg.archerRangeRatio, arc.ArcherMoveAllow, 0.001f, "접근 허용 = 슬링샷 × 비율"); + var foe = bm.SpawnUnit(UnitType.Infantry, Faction.Enemy, new Vector2(0f, -1.5f), "적보병"); + Assert.Less(3.5f - CastContact(arc, foe), arc.AttackRange, "전제: 적 가장자리가 사거리 안"); var o = new ActionOutcome(); - yield return bm.ResolveForTest(arc, new Vector2(0f, -1f), false, o); - Assert.Contains(foe, o.Attacked, "조준 방향의 적을 사거리까지 이동 후 사격"); + yield return bm.ResolveForTest(arc, new Vector2(0f, -2.5f), false, o); + Assert.Contains(foe, o.Attacked, "사거리 안의 적을 사격"); Assert.Less(foe.Hp, foe.MaxHp); - Assert.AreEqual(arc.MaxHp, arc.Hp, "궁병은 반격을 받지 않는다"); - float gap = Vector2.Distance(arc.Position, foe.Position) - arc.Radius * Combat.CastRadiusScale - foe.Radius; - Assert.LessOrEqual(gap, arc.AttackRange + 0.1f, "적 가장자리가 사거리에 들어올 때까지만 이동"); - Assert.Greater(arc.Position.y, -5f + 2.5f, "사거리에 들어오기 위해 실제로 이동"); + Assert.Less(Vector2.Distance(arc.Position, new Vector2(0f, -5f)), 0.01f, "움직이지 않고 제자리에서"); + Assert.AreEqual(arc.MaxHp, arc.Hp, "원거리 사격은 반격을 받지 않는다"); Assert.IsFalse(o.Crit); } [UnityTest] - public IEnumerator Archer_MovesToTarget_WhenNoEnemyWithinSlingPlusRatio() + public IEnumerator Archer_StepsInOnlyAsNeeded_WhenEnemyInDonut() + { + yield return Fresh(); + var arc = bm.SpawnUnit(UnitType.Archer, Faction.Player, new Vector2(0f, -5f), "궁병"); + var foe = bm.SpawnUnit(UnitType.Infantry, Faction.Enemy, new Vector2(0f, 0.3f), "적보병"); + float hitDist = 5.3f - CastContact(arc, foe); + Assert.Greater(hitDist, arc.AttackRange, "전제: 사거리 밖"); + Assert.LessOrEqual(hitDist, arc.AttackRange + arc.ArcherMoveAllow, "전제: 공격 가능 범위(도넛) 안"); + float need = hitDist - arc.AttackRange; + var o = new ActionOutcome(); + yield return bm.ResolveForTest(arc, new Vector2(0f, -1f), false, o); + Assert.Contains(foe, o.Attacked, "사거리에 들어올 만큼만 다가가 사격"); + Assert.AreEqual(-5f + need, arc.Position.y, 0.1f, "필요한 만큼만 이동"); + Assert.AreEqual(arc.MaxHp, arc.Hp); + Assert.IsFalse(o.Crit); + } + + [UnityTest] + public IEnumerator Archer_MovesToTarget_WhenNoEnemyWithinReach() { yield return Fresh(); var arc = bm.SpawnUnit(UnitType.Archer, Faction.Player, new Vector2(0f, -5f), "궁병"); - // 적 가장자리까지 6.0 − 반지름 합 ≈ 5.2 > 슬링샷 + 사거리 → 공격 없이 목표점까지 이동(PD 2026-11-04 2차 지시) var foe = bm.SpawnUnit(UnitType.Infantry, Faction.Enemy, new Vector2(0f, 1f), "적보병"); + Assert.Greater(6f - CastContact(arc, foe), arc.AttackRange + arc.ArcherMoveAllow, "전제: 공격 가능 범위 밖"); Assert.IsFalse(bm.AnyEnemyWithinArcherReach(arc), "공격 가능 범위 안에 적 없음(도넛 회색)"); var o = new ActionOutcome(); var target = new Vector2(0f, -1f); yield return bm.ResolveForTest(arc, target, false, o); - Assert.IsTrue(o.MovedOnly, "슬링샷 범위 + 비율 안에 적이 없으면 궁병은 목표점까지 이동만 한다"); + Assert.IsTrue(o.MovedOnly, "공격 가능 범위에 적이 없으면 목표점까지 이동만 (PD 2026-11-04 2차 지시)"); Assert.AreEqual(0, o.Attacked.Count); Assert.AreEqual(foe.MaxHp, foe.Hp); Assert.Less(Vector2.Distance(arc.Position, target), 0.05f, "목표 지점까지 이동"); - var near = bm.SpawnUnit(UnitType.Infantry, Faction.Enemy, new Vector2(0f, -0.4f), "가까운적"); + var near = bm.SpawnUnit(UnitType.Infantry, Faction.Enemy, new Vector2(2f, -1f), "가까운적"); Assert.IsTrue(bm.AnyEnemyWithinArcherReach(arc), "범위 안에 적이 생기면 도넛 붉게"); Assert.IsTrue(near.IsAlive); } @@ -182,13 +272,42 @@ namespace TKS.Tests } [UnityTest] - public IEnumerator Spear_OverwatchOnFinalHit_DamagesMovingEnemy() + public IEnumerator Archer_MeleePenalty_DealsRatio_TakesRatio_RangedUnaffected() + { + yield return Fresh(); + var arc = bm.SpawnUnit(UnitType.Archer, Faction.Player, new Vector2(0f, -5f), "궁병"); + var arc2 = bm.SpawnUnit(UnitType.Archer, Faction.Player, new Vector2(2f, -5f), "궁병2"); + var inf = bm.SpawnUnit(UnitType.Infantry, Faction.Enemy, new Vector2(4f, -5f), "적보병"); + + int ranged = Combat.Damage(cfg, arc, inf, false, new System.Random(7), false); + int melee = Combat.Damage(cfg, arc, inf, false, new System.Random(7), true); + Assert.AreEqual(ranged * cfg.archerMeleeDealtRatio, melee, 1f, "궁병이 근접 유닛과 근접 전투하면 주는 피해 × 비율(기본 50 %)"); + + int takenRanged = Combat.Damage(cfg, inf, arc, false, new System.Random(7), false); + int takenMelee = Combat.Damage(cfg, inf, arc, false, new System.Random(7), true); + Assert.AreEqual(takenRanged * cfg.archerMeleeTakenRatio, takenMelee, 1f, "근접 유닛에게 근접으로 맞으면 받는 피해 × 비율(기본 +50 %)"); + + int aa = Combat.Damage(cfg, arc, arc2, false, new System.Random(7), true); + int ab = Combat.Damage(cfg, arc, arc2, false, new System.Random(7), false); + Assert.AreEqual(ab, aa, "궁병끼리는 근접 패널티 없음(근접 유닛 상대만)"); + yield return null; + } + + // ---------- 창병 ---------- + + [UnityTest] + public IEnumerator Spear_PlowsEnemyForward_OverwatchOnFinalHit_DamagesMovingEnemy() { yield return Fresh(); var spear = bm.SpawnUnit(UnitType.Spear, Faction.Player, new Vector2(0f, -3f), "창병"); var foe = bm.SpawnUnit(UnitType.Infantry, Faction.Enemy, new Vector2(0f, 0f), "적보병"); var o = new ActionOutcome(); yield return bm.ResolveForTest(spear, foe.Position, false, o); + Assert.Contains(foe, o.Attacked); + Assert.Less(foe.Hp, foe.MaxHp, "부딪힌 적에게 피해"); + Assert.Contains(foe, o.Pushed, "튕기지 않고 밀며 함께 전진"); + Assert.Greater(foe.Position.y, 0.5f, "적이 남은 거리만큼 앞으로 밀림"); + Assert.AreEqual(CastContact(spear, foe), foe.Position.y - spear.Position.y, 0.1f, "창병은 접촉 간격을 유지하며 따라감"); Assert.IsTrue(o.Overwatch && spear.Overwatch, "최종 목표점 명중 → 대기(견제)"); int hp = foe.Hp; @@ -203,6 +322,29 @@ namespace TKS.Tests Assert.AreEqual(farHp, far.Hp); } + [UnityTest] + public IEnumerator Spear_PlowsAlly_NoDamage_AllyAttacksWhenPushedOntoEnemy() + { + yield return Fresh(); + var spear = bm.SpawnUnit(UnitType.Spear, Faction.Player, new Vector2(0f, -4f), "창병"); + var ally = bm.SpawnUnit(UnitType.Infantry, Faction.Player, new Vector2(0f, -2f), "아군보병"); + var foe = bm.SpawnUnit(UnitType.Infantry, Faction.Enemy, new Vector2(0f, 1.5f), "적보병"); + int allyHp = ally.Hp; + var o = new ActionOutcome(); + yield return bm.ResolveForTest(spear, new Vector2(0f, 0f), false, o); + Assert.AreEqual(0, o.Attacked.Count, "아군에 부딪힌 창병 자신은 공격하지 않음"); + Assert.Contains(ally, o.Pushed); + Assert.Greater(ally.Position.y, 0.4f, "아군을 밀며 함께 전진(적에 닿을 때까지)"); + Assert.LessOrEqual(Gap(ally, foe), Combat.ContactTolerance + 0.05f, "밀린 아군이 적과 닿음"); + Assert.AreEqual(CastContact(spear, ally), ally.Position.y - spear.Position.y, 0.1f, "창병은 아군 바로 뒤까지 따라옴"); + Assert.Less(foe.Hp, foe.MaxHp, "밀린 아군이 적을 공격(규칙 ⑤)"); + Assert.AreEqual(spear.MaxHp, spear.Hp, "창병은 피해 없음"); + Assert.AreEqual(1, o.Notes.Count); + Assert.IsTrue(allyHp >= ally.Hp, "아군은 밀려서 피해를 받지 않는다(근접 공격 반격만 가능)"); + } + + // ---------- 턴 · 승패 · AI · 카메라 · 표시 ---------- + [UnityTest] public IEnumerator EnemyTurn_RunsAndReturnsToPlayerTurn() { @@ -313,7 +455,7 @@ namespace TKS.Tests [UnityTest] public IEnumerator UnitArt_HeroWithArt_PlaysBackIdle_UnitWithoutArt_IsShape() { - // 부트스트랩 스테이지 1: 유비·관우·장비 = 스켈레탈 세션 아트(Resources/Units/liubei·guanyu·zhangfei) · 조운·황충·적 = 도형 + // 부트스트랩 스테이지 1: 유비·관우·장비 = 스켈레탈 세션 아트(Resources/Units/liubei·guanyu·zhangfei) · 조운·황충 = 도형 Unit liubei = null; Unit shape = null; foreach (var u in bm.AliveUnits(Faction.Player)) @@ -332,6 +474,29 @@ namespace TKS.Tests liubei.View.PlayAttack(); Assert.AreEqual("back_action", liubei.View.Anim.Current, "공격 자세 클립"); + + // 원화 세션 1차 납품(2026-11-04): 황건적 5종 정지 그림(front_idle 1장) + 전장 배경 + int enemyArt = 0; + foreach (var e in bm.AliveUnits(Faction.Enemy)) + { + if (e.View.HasArt) + { + enemyArt++; + Assert.AreEqual("front_idle", e.View.Anim.Current, "적은 앞모습 정지 그림"); + } + } + Assert.AreEqual(bm.AliveCount(Faction.Enemy), enemyArt, "스테이지 1 황건적은 전원 원화(hgj_*)로 표시"); + Assert.IsTrue(bm.Board.HasArt, "전장 배경 = Resources/Board/" + cfg.boardArt); + + // 원화 2차 납품(2026-11-04): 동탁군 보·창·기·궁 4종 반영 · 여포(dz_boss_lvbu)는 보류 → 도형 + bm.StartStage(1); + yield return null; + foreach (var e in bm.AliveUnits(Faction.Enemy)) + { + if (e.IsBoss) continue; + Assert.IsTrue(e.View.HasArt, "스테이지 2 동탁군 병종 4종은 원화(" + e.ArtId + ")"); + } + bm.StartStage(0); yield return null; } } diff --git a/CLAUDE.md b/CLAUDE.md index 93291931..5df6470f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -44,9 +44,10 @@ Unity.exe -projectPath -executeMethod TKS.EditorTools.ProjectSetup.AutoPl ## 코드 규칙 - 수치·영웅·스테이지 SOT = `Assets/Resources/BalanceConfig.asset`(Inspector 조정 · 최초 시드만 `Assets/Scripts/Editor/BalanceDefaults.cs`). 코드·테스트에 수치를 직접 적지 않는다(C45). -- 규칙 해석 변경 = `Assets/Scripts/Runtime/ActionResolver.cs`(병종 4종) · `BattleManager.cs`(턴·승패·창병 대기) · `Combat.cs`(피해 공식·경로 질의). 변경 시 `Assets/Tests/PlayMode/BattleFlowTests.cs` 에 테스트 추가 후 14종 이상 전부 통과 확인. +- 규칙 해석 변경 = `Assets/Scripts/Runtime/ActionResolver.cs`(병종 4종) · `BattleManager.cs`(턴·승패·창병 대기) · `Combat.cs`(피해 공식·경로 질의). 변경 시 `Assets/Tests/PlayMode/BattleFlowTests.cs` 에 테스트 추가 후 22종 이상 전부 통과 확인. - 콜라이더 질의 전 `Physics2D.SyncTransforms()` · 유닛 제거는 `SetActive(false)` 후 `Destroy` · 자식 렌더러가 있는 표시물은 GameObject 통째로 끈다. -- **궁병 규칙(PD 2026-11-04)**: 사거리 = `slingMaxDistance × archerRangeRatio`(자산 · 기본 0.2 = 슬링샷 범위 +20 %). 조준 방향 「슬링샷 거리 + 사거리」 안에 적이 있으면 적 **가장자리**가 사거리에 들어올 때까지만 이동 후 사격 · 적이 없으면 **목표점까지 이동만**(PD 2026-11-04 2차 지시 · 1차의 「행동 취소」 폐기 · AI 적 궁병도 같음). `UnitStats.attackRange` 는 창병 견제 반경만. +- **궁병 규칙(PD 2026-11-04 · #1080)**: 사거리 = `slingMaxDistance`(얇은 원). 조준 방향 사거리 안의 적(가장자리 간격 기준) = **제자리 사격** · 사거리 밖 ~ ×(1 + `archerRangeRatio`)(붉은 도넛) 안의 적 = 들어올 만큼만(최대 `ArcherMoveAllow` = 슬링 × 비율) 다가가 사격 · 더 멀면 **목표점까지 이동만**(#1079). 반격 없음 · 목표점 명중 크리. **근접 전투**(돌진·반격·관통·견제·밀려 닿은 공격)에서 궁병은 근접 유닛 상대 주는 피해 × `archerMeleeDealtRatio`(0.5) · 받는 피해 × `archerMeleeTakenRatio`(1.5) — `Combat.Damage(…, melee)` · 원거리 사격은 패널티 없음. +- **충돌 규칙(PD 2026-11-04 · #1080)** — `ActionResolver`: 보병 = 경로 첫 유닛(아군·적군)에 부딪히면 **알까기**(자신은 접촉점에 멈춤 · 상대는 접촉 방향으로 남은 거리 × `collisionPushRatio` 만큼 밀림 · 적이면 공격+반격 뒤 밀림) · 기병 = 유닛 무시 관통(적 피해 · 아군은 지나칠 거리가 안 나오면 **그 아군 직전 정지** `StopBeforeUnclearedAllies`) · 창병 = 첫 유닛을 **밀며 함께 전진**(접촉 간격 유지 · 앞 유닛이 막히면 둘 다 정지 · 적이면 피해 · 아군은 밀기만) · **규칙 ⑤** = 밀린 같은 진영 유닛이 상대와 닿으면(`Combat.TouchingOpponent` · 간격 ≤ 0.12) 그 자리에서 근접 공격 1회(조작마다 · 자기 행동 소모 없음 · `ActionOutcome.Notes`). 적 AI 도 같은 코드(대칭). `UnitStats.attackRange` 는 창병 견제 반경만. - **사거리 표시(PD 2026-11-04)**: 유닛 탭(아군·적군) → `RangeIndicator`(슬링샷 최대 거리 = 얇은 반투명 원 · 궁병 = 슬링샷 범위 ~ ×(1+비율) 채워진 붉은 도넛 · 범위 안 적이 없으면 회색). - 보고는 실측·추정·미확인을 분리한다(C23 · C5). 커밋은 의도 변경 파일만. @@ -54,7 +55,8 @@ Unity.exe -projectPath -executeMethod TKS.EditorTools.ProjectSetup.AutoPl - 아트 위치 = `Assets/Resources/Units///f000.png …` + `meta.json`(fps · ppu · pivot(발) · charHeightPx · clips). `` 는 `BalanceConfig.asset` 의 `heroes[].art` / `stages[].enemies[].art`(비면 도형). 아군 = `liubei`·`guanyu`·`zhangfei`(스켈레탈 세션 리그 프레임) · 적 = `<세력>_<병종>`(`hgj_infantry` …) · 보스 = `<세력>_boss_<로마자>`(`hgj_boss_zhangjiao` …). - 스켈레탈 리그 → 프레임: 조직 레포 스킬 `skeletal-anim-pipeline/files/scripts/rig_frames_export.py rig <리그 패키지> --parts <작업>/parts --out Assets/Resources/Units/ --clips back_idle,back_ready,back_action,back_damage,back_stop,front_idle,front_ready,front_action,front_damage,front_stop,front_victory,front_failed --px 180 --step 2`(ComfyUI venv python · 실측 482×470 · 15 fps · 3인 11 MB). -- 정지 그림(적 SD 전신 `_rgba.png`) → `rig_frames_export.py static --out Assets/Resources/Units/`(front_idle 1장 · 발 = 불투명 상자 아래). +- 정지 그림(적 SD 전신 `_rgba.png`) → `rig_frames_export.py static --out Assets/Resources/Units/`(front_idle 1장 · 발 = 불투명 상자 아래). 원화 세션 납품 = `C:\ArtRnD\samguk_game\manifest.json` · 파일명 `_rgba.png` → `` 폴더(2026-11-04 1차 `hgj_*` 5종 + 2차 `dz_infantry·spear·cavalry·archer` 반영 완료 · 여포 `dz_boss_lvbu`·`cc_*`·`wei_*` 는 납품 시 같은 명령). +- 전장 배경 = `Assets/Resources/Board/.png`(자산 `boardArt` · 5:8 불투명 · PPU 100 = 전장 20×32) → `Board.Build` 가 있으면 바닥으로 쓰고 격자·진영 띠는 생략. 임포트 규칙(스프라이트 · 4096 · 압축)은 같은 `UnitArtImporter` 의 `Board/` 분기 · 재임포트 메뉴가 두 폴더 처리. - 임포트 설정은 `Editor/UnitArtImporter.cs`(AssetPostprocessor · meta 의 pivot·ppu) 가 자동 적용 · 프레임을 넣거나 meta 를 바꾼 뒤 = 메뉴 `TKS/Reimport Unit Art`(Build/BuildFresh 가 함께 호출). - 재생 = `UnitArt.cs`(Resources 로더 · 캐시) + `FrameAnimator`(대기 loop · 준비 = 조준 중 · 공격·피격 = 1프레임 자세 유지 후 대기 · 승리 = 끝 프레임 유지) · `UnitView` 가 아군 = `back_*` · 적군 = `front_*` 로 고르고 없으면 다른 보기 → 대기. 세로 크기 = `unitArtHeight`(자산) × 반지름 배율 · 발 = 원 중심 아래 0.55 R. diff --git a/README.md b/README.md index 7292896e..89ec0ee2 100644 --- a/README.md +++ b/README.md @@ -22,12 +22,12 @@ Unity 6000.3.23f1 · 2D · 도형 플레이스홀더(아트 리소스는 별도 | 병종 | 경로 위 적 | 최종 목표점 명중 시 | |---|---|---| -| 보병 | 첫 적까지 이동 후 공격(반격 받음) | 추가 이동 1회(이동만) | -| 기병 | 경로 위 모든 적 관통 피해 · 목표점까지 이동 | 제자리로 복귀 | -| 창병 | 보병과 동일 | 대기 — 적군 턴에 반경 안에서 움직이는 적에게 피해 | -| 궁병 | 목표 방향 「슬링샷 거리 + 사거리」 안의 적을 향해 사거리까지 이동 후 사격(반격 없음) · 적이 없으면 목표점까지 이동 | 무조건 크리티컬 | +| 보병 | 첫 유닛(아군·적군)에 부딪히면 알까기처럼 남은 힘만큼 밀어내고 자신은 멈춤 · 적이면 공격(반격 받음) | 추가 이동 1회(이동만) | +| 기병 | 유닛을 무시하고 관통 · 경로 위 적은 모두 피해 · 아군은 지나칠 거리가 안 나오면 직전에 멈춤 | 제자리로 복귀 | +| 창병 | 첫 유닛을 튕기지 않고 밀며 함께 전진 · 적이면 피해(반격 받음) · 아군은 밀기만 | 대기 — 적군 턴에 반경 안에서 움직이는 적에게 피해 | +| 궁병 | 사거리(= 슬링샷 범위) 안의 적은 제자리 사격 · 사거리 밖 +20 % 안의 적은 들어올 만큼만 다가가 사격(반격 없음) · 더 멀면 목표점까지 이동 | 무조건 크리티컬 | -상성: 보병 > 창병 > 기병 > 보병. 궁병은 모두에게 약함(받는 피해 1.5배). +밀린 아군이 적과 닿으면 그 자리에서 공격 1회(조작마다 · 자기 행동 소모 없음). 상성: 보병 > 창병 > 기병 > 보병. 궁병은 모두에게 약함(받는 피해 1.5배) · 근접 유닛과 근접 전투하면 주는 피해 50 % · 받는 피해 +50 %(원거리 사격은 패널티 없음). ## 데이터(SOT)