diff --git a/Assets/Resources/judgeSFX.meta b/Assets/Resources/judgeSFX.meta new file mode 100644 index 00000000..f2fe00e2 --- /dev/null +++ b/Assets/Resources/judgeSFX.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6af0e7cd2ed52724c9b8b42bf60ef2d8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/judgeSFX/good.ogg b/Assets/Resources/judgeSFX/good.ogg new file mode 100644 index 00000000..596a8291 Binary files /dev/null and b/Assets/Resources/judgeSFX/good.ogg differ diff --git a/Assets/Resources/judgeSFX/good.ogg.meta b/Assets/Resources/judgeSFX/good.ogg.meta new file mode 100644 index 00000000..259c092e --- /dev/null +++ b/Assets/Resources/judgeSFX/good.ogg.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: bcec634c6e258c44a803ae3ca618b465 +AudioImporter: + externalObjects: {} + serializedVersion: 8 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 0 + sampleRateOverride: 44100 + compressionFormat: 1 + quality: 1 + conversionMode: 0 + preloadAudioData: 1 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 1 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/judgeSFX/great.ogg b/Assets/Resources/judgeSFX/great.ogg new file mode 100644 index 00000000..20b99ab9 Binary files /dev/null and b/Assets/Resources/judgeSFX/great.ogg differ diff --git a/Assets/Resources/judgeSFX/great.ogg.meta b/Assets/Resources/judgeSFX/great.ogg.meta new file mode 100644 index 00000000..69ecf5e1 --- /dev/null +++ b/Assets/Resources/judgeSFX/great.ogg.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: 36799a159f61a5e489dd0963de4bf661 +AudioImporter: + externalObjects: {} + serializedVersion: 8 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 0 + sampleRateOverride: 44100 + compressionFormat: 1 + quality: 1 + conversionMode: 0 + preloadAudioData: 1 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 1 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/judgeSFX/miss.ogg b/Assets/Resources/judgeSFX/miss.ogg new file mode 100644 index 00000000..60463327 Binary files /dev/null and b/Assets/Resources/judgeSFX/miss.ogg differ diff --git a/Assets/Resources/judgeSFX/miss.ogg.meta b/Assets/Resources/judgeSFX/miss.ogg.meta new file mode 100644 index 00000000..cc40579b --- /dev/null +++ b/Assets/Resources/judgeSFX/miss.ogg.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: 3dcbff412c1c9ec4d8ca931f2d51ab10 +AudioImporter: + externalObjects: {} + serializedVersion: 8 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 0 + sampleRateOverride: 44100 + compressionFormat: 1 + quality: 1 + conversionMode: 0 + preloadAudioData: 1 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 1 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/judgeSFX/perfect.ogg b/Assets/Resources/judgeSFX/perfect.ogg new file mode 100644 index 00000000..4cce624f Binary files /dev/null and b/Assets/Resources/judgeSFX/perfect.ogg differ diff --git a/Assets/Resources/judgeSFX/perfect.ogg.meta b/Assets/Resources/judgeSFX/perfect.ogg.meta new file mode 100644 index 00000000..f51b7c1b --- /dev/null +++ b/Assets/Resources/judgeSFX/perfect.ogg.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: fae24344d433d714fadfa0ca8e285f7f +AudioImporter: + externalObjects: {} + serializedVersion: 8 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 0 + sampleRateOverride: 44100 + compressionFormat: 1 + quality: 1 + conversionMode: 0 + preloadAudioData: 1 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 1 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/op/artworks.meta b/Assets/Resources/op/artworks.meta new file mode 100644 index 00000000..0934d9a0 --- /dev/null +++ b/Assets/Resources/op/artworks.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c036c8921700c58458a4ed5ab3fbea48 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/op/artworks/画板 75.png b/Assets/Resources/op/artworks/画板 75.png new file mode 100644 index 00000000..eb9eecba Binary files /dev/null and b/Assets/Resources/op/artworks/画板 75.png differ diff --git a/Assets/Resources/op/artworks/画板 75.png.meta b/Assets/Resources/op/artworks/画板 75.png.meta new file mode 100644 index 00000000..78ce9312 --- /dev/null +++ b/Assets/Resources/op/artworks/画板 75.png.meta @@ -0,0 +1,155 @@ +fileFormatVersion: 2 +guid: 4ed1f0171d2ac0145a795a7eee628bd2 +TextureImporter: + internalIDToNameTable: + - first: + 213: 1508358750112011512 + second: "\u753B\u677F 75_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: 2 + spriteExtrude: 1 + spriteMeshType: 1 + 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: 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: 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 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: "\u753B\u677F 75_0" + rect: + serializedVersion: 2 + x: 0 + y: 0 + width: 55 + height: 55 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 8f45746aa44cee410800000000000000 + internalID: 1508358750112011512 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/op/artworks/画板 76.png b/Assets/Resources/op/artworks/画板 76.png new file mode 100644 index 00000000..b6760830 Binary files /dev/null and b/Assets/Resources/op/artworks/画板 76.png differ diff --git a/Assets/Resources/op/artworks/画板 76.png.meta b/Assets/Resources/op/artworks/画板 76.png.meta new file mode 100644 index 00000000..a0415ec5 --- /dev/null +++ b/Assets/Resources/op/artworks/画板 76.png.meta @@ -0,0 +1,155 @@ +fileFormatVersion: 2 +guid: ef9f747590c0b3541979026af6c82992 +TextureImporter: + internalIDToNameTable: + - first: + 213: 627408324413374251 + second: "\u753B\u677F 76_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: 2 + spriteExtrude: 1 + spriteMeshType: 1 + 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: 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: 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 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: "\u753B\u677F 76_0" + rect: + serializedVersion: 2 + x: 0 + y: 0 + width: 633 + height: 9 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: b2f38c10c8005b800800000000000000 + internalID: 627408324413374251 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/op/artworks/画板 78.png b/Assets/Resources/op/artworks/画板 78.png new file mode 100644 index 00000000..beaff473 Binary files /dev/null and b/Assets/Resources/op/artworks/画板 78.png differ diff --git a/Assets/Resources/op/artworks/画板 78.png.meta b/Assets/Resources/op/artworks/画板 78.png.meta new file mode 100644 index 00000000..d88fb227 --- /dev/null +++ b/Assets/Resources/op/artworks/画板 78.png.meta @@ -0,0 +1,155 @@ +fileFormatVersion: 2 +guid: 7ca4a39b4ea72be4aa0b80a698bdd99f +TextureImporter: + internalIDToNameTable: + - first: + 213: -2694539428277866217 + second: "\u753B\u677F 78_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: 2 + spriteExtrude: 1 + spriteMeshType: 1 + 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: 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: 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 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: "\u753B\u677F 78_0" + rect: + serializedVersion: 2 + x: 0 + y: 0 + width: 633 + height: 9 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 711b6309aa21b9ad0800000000000000 + internalID: -2694539428277866217 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/op/artworks/画板 79.png b/Assets/Resources/op/artworks/画板 79.png new file mode 100644 index 00000000..54efeddf Binary files /dev/null and b/Assets/Resources/op/artworks/画板 79.png differ diff --git a/Assets/Resources/op/artworks/画板 79.png.meta b/Assets/Resources/op/artworks/画板 79.png.meta new file mode 100644 index 00000000..1fceee8c --- /dev/null +++ b/Assets/Resources/op/artworks/画板 79.png.meta @@ -0,0 +1,255 @@ +fileFormatVersion: 2 +guid: f48684099e472254f881fc44087db10d +TextureImporter: + internalIDToNameTable: + - first: + 213: -7416849779330969551 + second: "\u753B\u677F 79_0" + - first: + 213: -8945369728627073014 + second: "\u753B\u677F 79_1" + - first: + 213: 4729716212365872202 + second: "\u753B\u677F 79_2" + - first: + 213: -1166063591256540292 + second: "\u753B\u677F 79_3" + - first: + 213: 2919094442245778957 + second: "\u753B\u677F 79_4" + 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: 2 + spriteExtrude: 1 + spriteMeshType: 1 + 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: 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: 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 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: "\u753B\u677F 79_0" + rect: + serializedVersion: 2 + x: 1 + y: 5 + width: 18 + height: 21 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 1301b8efb6e021990800000000000000 + internalID: -7416849779330969551 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: "\u753B\u677F 79_1" + rect: + serializedVersion: 2 + x: 31 + y: 5 + width: 18 + height: 21 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: a00a6ac50a9abd380800000000000000 + internalID: -8945369728627073014 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: "\u753B\u677F 79_2" + rect: + serializedVersion: 2 + x: 60 + y: 5 + width: 20 + height: 21 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: a4c497606d353a140800000000000000 + internalID: 4729716212365872202 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: "\u753B\u677F 79_3" + rect: + serializedVersion: 2 + x: 92 + y: 5 + width: 19 + height: 21 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: c7b33a1875f41dfe0800000000000000 + internalID: -1166063591256540292 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: "\u753B\u677F 79_4" + rect: + serializedVersion: 2 + x: 124 + y: 5 + width: 18 + height: 21 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: d0e60efdde4b28820800000000000000 + internalID: 2919094442245778957 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/op/artworks/画板 80.png b/Assets/Resources/op/artworks/画板 80.png new file mode 100644 index 00000000..abde227d Binary files /dev/null and b/Assets/Resources/op/artworks/画板 80.png differ diff --git a/Assets/Resources/op/artworks/画板 80.png.meta b/Assets/Resources/op/artworks/画板 80.png.meta new file mode 100644 index 00000000..e9522c2b --- /dev/null +++ b/Assets/Resources/op/artworks/画板 80.png.meta @@ -0,0 +1,155 @@ +fileFormatVersion: 2 +guid: 6a1563afc10f07f4a91dddedc1542f24 +TextureImporter: + internalIDToNameTable: + - first: + 213: -5639479817726893851 + second: "\u753B\u677F 80_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: 2 + spriteExtrude: 1 + spriteMeshType: 1 + 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: 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: 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 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: "\u753B\u677F 80_0" + rect: + serializedVersion: 2 + x: 0 + y: 0 + width: 55 + height: 48 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 5e0676a2cfa8cb1b0800000000000000 + internalID: -5639479817726893851 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/op/artworks/画板 81.png b/Assets/Resources/op/artworks/画板 81.png new file mode 100644 index 00000000..f2e8ab81 Binary files /dev/null and b/Assets/Resources/op/artworks/画板 81.png differ diff --git a/Assets/Resources/op/artworks/画板 81.png.meta b/Assets/Resources/op/artworks/画板 81.png.meta new file mode 100644 index 00000000..2ba71b7c --- /dev/null +++ b/Assets/Resources/op/artworks/画板 81.png.meta @@ -0,0 +1,155 @@ +fileFormatVersion: 2 +guid: 5ad663b00655c784cb765dc4bef1a70a +TextureImporter: + internalIDToNameTable: + - first: + 213: -1101522076588880424 + second: "\u753B\u677F 81_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: 2 + spriteExtrude: 1 + spriteMeshType: 1 + 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: 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: 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 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: "\u753B\u677F 81_0" + rect: + serializedVersion: 2 + x: 0 + y: 0 + width: 28 + height: 25 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 8dd4ba8e18b96b0f0800000000000000 + internalID: -1101522076588880424 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/op/artworks/背景 副本 2.png b/Assets/Resources/op/artworks/背景 副本 2.png new file mode 100644 index 00000000..71573e2f Binary files /dev/null and b/Assets/Resources/op/artworks/背景 副本 2.png differ diff --git a/Assets/Resources/op/artworks/背景 副本 2.png.meta b/Assets/Resources/op/artworks/背景 副本 2.png.meta new file mode 100644 index 00000000..0e83f844 --- /dev/null +++ b/Assets/Resources/op/artworks/背景 副本 2.png.meta @@ -0,0 +1,155 @@ +fileFormatVersion: 2 +guid: 3f52c0334ac12f746ae80e69fa0a7fb8 +TextureImporter: + internalIDToNameTable: + - first: + 213: -435054604834745923 + second: "\u80CC\u666F \u526F\u672C 2_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: 2 + spriteExtrude: 1 + spriteMeshType: 1 + 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: 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: 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 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: "\u80CC\u666F \u526F\u672C 2_0" + rect: + serializedVersion: 2 + x: 1 + y: 0 + width: 1923 + height: 1081 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: db15de4542066f9f0800000000000000 + internalID: -435054604834745923 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/op/artworks/背景.png b/Assets/Resources/op/artworks/背景.png new file mode 100644 index 00000000..b09987cf Binary files /dev/null and b/Assets/Resources/op/artworks/背景.png differ diff --git a/Assets/Resources/op/artworks/背景.png.meta b/Assets/Resources/op/artworks/背景.png.meta new file mode 100644 index 00000000..821ca048 --- /dev/null +++ b/Assets/Resources/op/artworks/背景.png.meta @@ -0,0 +1,155 @@ +fileFormatVersion: 2 +guid: 596b315de75dacd479b79e1e25a5e2e0 +TextureImporter: + internalIDToNameTable: + - first: + 213: -1843028302627794106 + second: "\u80CC\u666F_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: 2 + spriteExtrude: 1 + spriteMeshType: 1 + 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: 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: 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 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: "\u80CC\u666F_0" + rect: + serializedVersion: 2 + x: 1 + y: 0 + width: 1923 + height: 1081 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 64311e6068f3c66e0800000000000000 + internalID: -1843028302627794106 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/op/beautiful-things-piano-222056.mp3 b/Assets/Resources/op/beautiful-things-piano-222056.mp3 new file mode 100644 index 00000000..ecc8b559 Binary files /dev/null and b/Assets/Resources/op/beautiful-things-piano-222056.mp3 differ diff --git a/Assets/Resources/op/beautiful-things-piano-222056.mp3.meta b/Assets/Resources/op/beautiful-things-piano-222056.mp3.meta new file mode 100644 index 00000000..c52c29b8 --- /dev/null +++ b/Assets/Resources/op/beautiful-things-piano-222056.mp3.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: afef27d42a820784a914abd621cb2c09 +AudioImporter: + externalObjects: {} + serializedVersion: 8 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 0 + sampleRateOverride: 44100 + compressionFormat: 1 + quality: 1 + conversionMode: 0 + preloadAudioData: 1 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 1 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/op/creepy-season-halloween-247588.mp3.meta b/Assets/Resources/op/creepy-season-halloween-247588.mp3.meta index 96ad5e38..f747e2b5 100644 --- a/Assets/Resources/op/creepy-season-halloween-247588.mp3.meta +++ b/Assets/Resources/op/creepy-season-halloween-247588.mp3.meta @@ -11,11 +11,11 @@ AudioImporter: compressionFormat: 1 quality: 1 conversionMode: 0 - preloadAudioData: 0 + preloadAudioData: 1 platformSettingOverrides: {} forceToMono: 0 normalize: 1 - loadInBackground: 0 + loadInBackground: 1 ambisonic: 0 3D: 1 userData: diff --git a/Assets/Resources/op/load_preload.meta b/Assets/Resources/op/load_preload.meta new file mode 100644 index 00000000..6bdbd2e6 --- /dev/null +++ b/Assets/Resources/op/load_preload.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3fc1f3fc8072ab04db6db7e663dd7956 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/op/load_preload/preload_allScene.cs b/Assets/Resources/op/load_preload/preload_allScene.cs new file mode 100644 index 00000000..b68293c3 --- /dev/null +++ b/Assets/Resources/op/load_preload/preload_allScene.cs @@ -0,0 +1,401 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.SceneManagement; +using UnityEngine.UI; + +/// +/// Throttled preload: uses queues and concurrency limits to load scenes and Resources in small time slices +/// to avoid long frames on low-end devices. +/// - scenesToPreload: names of scenes included in Build Settings to preload additively (allowSceneActivation=false) +/// - resourcesToPreload: paths under Resources/ to load via Resources.LoadAsync +/// +public class preload_allScene : MonoBehaviour +{ + [Header("Preload settings")] + public string[] scenesToPreload = new string[0]; + public string[] resourcesToPreload = new string[0]; + + [Header("UI")] + public Text progressText; + [Tooltip("Optional Image whose fillAmount will be driven by the overall progress (0..1)")] + public Image progressFillImage; + [Tooltip("Optional Text to show current loading item: 'ڼأxxx'")] + public Text loadingInfoText; + + [Header("Behavior")] + public bool startOnAwake = true; + + [Header("Fade-out on complete")] + [Tooltip("GameObject to disable after fade completes")] public GameObject fadeOutObject; + [Tooltip("CanvasGroup to fade (if null and fadeOutObject assigned, will search for one on it)")] public CanvasGroup fadeCanvasGroup; + [Tooltip("Duration of fade-out in seconds")] public float fadeOutDuration = 0.5f; + [Tooltip("Delay before starting fade-out after completion")] public float fadeOutDelay = 0f; + + [Header("Throttle")] + [Tooltip("Max concurrent resource loads")] + public int maxConcurrentResourceLoads = 2; + [Tooltip("Max concurrent scene loads")] + public int maxConcurrentSceneLoads = 1; + [Tooltip("Max milliseconds spent per frame on driver work (approx)")] + public int maxMilliSecondsPerFrame = 4; + + // internal queues and trackers + private Queue sceneQueue = new Queue(); + private Queue resourceQueue = new Queue(); + + // scenes currently loading (progress < ~0.9) + private List<(string sceneName, AsyncOperation op)> loadingSceneOps = new List<(string, AsyncOperation)>(); + // scenes loaded to 0.9 and waiting activation + private List<(string sceneName, AsyncOperation op)> readySceneOps = new List<(string, AsyncOperation)>(); + + private List<(string path, ResourceRequest rr)> activeResourceReqs = new List<(string, ResourceRequest)>(); + + private List loadedResources = new List(); + + private Coroutine preloadCoroutine; + + void Awake() + { + fadeOutObject.SetActive(true); + // if UI not assigned, try to auto-find Text components + if (progressText == null) + { + progressText = GetComponentInChildren(true); + } + + if (loadingInfoText == null) + { + // try to find a different Text child (avoid using same as progressText) + var texts = GetComponentsInChildren(true); + foreach (var t in texts) + { + if (t != progressText) + { + loadingInfoText = t; + break; + } + } + } + + // If a fade object is set but no CanvasGroup assigned, try to find one on the object + if (fadeOutObject != null && fadeCanvasGroup == null) + { + fadeCanvasGroup = fadeOutObject.GetComponent() ?? fadeOutObject.GetComponentInChildren(true); + } + } + + void Start() + { + // fadeOutObject.SetActive(true); + // auto-start if configured OR there are items to preload + if (startOnAwake || (scenesToPreload != null && scenesToPreload.Length > 0) || (resourcesToPreload != null && resourcesToPreload.Length > 0)) + { + StartPreload(); + } + } + + public void StartPreload() + { + if (preloadCoroutine != null) return; + + // fill queues + sceneQueue.Clear(); + resourceQueue.Clear(); + + if (scenesToPreload != null) + { + foreach (var s in scenesToPreload) + if (!string.IsNullOrWhiteSpace(s)) sceneQueue.Enqueue(s); + } + if (resourcesToPreload != null) + { + foreach (var r in resourcesToPreload) + if (!string.IsNullOrWhiteSpace(r)) resourceQueue.Enqueue(r); + } + + Debug.Log($"Preload starting. Scenes queued: {sceneQueue.Count}, Resources queued: {resourceQueue.Count}"); + + // ensure UI shows 0% + UpdateProgressText(0f); + UpdateLoadingInfo(""); + + preloadCoroutine = StartCoroutine(PreloadRoutine()); + } + + public void StopPreload() + { + if (preloadCoroutine != null) + { + StopCoroutine(preloadCoroutine); + preloadCoroutine = null; + } + } + + private IEnumerator PreloadRoutine() + { + // Start initial batch + while (sceneQueue.Count > 0 || resourceQueue.Count > 0 || loadingSceneOps.Count > 0 || activeResourceReqs.Count > 0) + { + float frameStart = Time.realtimeSinceStartup; + + // start scene ops up to concurrency + while (loadingSceneOps.Count < maxConcurrentSceneLoads && sceneQueue.Count > 0) + { + string sceneName = sceneQueue.Dequeue(); + UpdateLoadingInfo($"ڼأ{sceneName}"); + AsyncOperation op = null; + try + { + op = SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive); + } + catch (System.Exception ex) + { + Debug.LogWarning($"Preload: failed to start loading scene '{sceneName}': {ex}"); + } + + if (op != null) + { + op.allowSceneActivation = false; + loadingSceneOps.Add((sceneName, op)); + Debug.Log($"Preload: started scene load '{sceneName}'"); + } + + if ((Time.realtimeSinceStartup - frameStart) * 1000f > maxMilliSecondsPerFrame) break; + } + + // start resource reqs up to concurrency + while (activeResourceReqs.Count < maxConcurrentResourceLoads && resourceQueue.Count > 0) + { + string path = resourceQueue.Dequeue(); + UpdateLoadingInfo($"ڼأ{path}"); + ResourceRequest rr = null; + try + { + rr = Resources.LoadAsync(path); + } + catch (System.Exception ex) + { + Debug.LogWarning($"Preload: failed to start loading resource '{path}': {ex}"); + } + + if (rr != null) + { + activeResourceReqs.Add((path, rr)); + Debug.Log($"Preload: started resource load '{path}'"); + } + + if ((Time.realtimeSinceStartup - frameStart) * 1000f > maxMilliSecondsPerFrame) break; + } + + // Poll progress and collect finished resources + for (int i = activeResourceReqs.Count - 1; i >= 0; i--) + { + var tuple = activeResourceReqs[i]; + var rr = tuple.rr; + if (rr.isDone) + { + if (rr.asset != null) + loadedResources.Add(rr.asset); + Debug.Log($"Preload: resource loaded '{tuple.path}'"); + activeResourceReqs.RemoveAt(i); + } + + if ((Time.realtimeSinceStartup - frameStart) * 1000f > maxMilliSecondsPerFrame) break; + } + + // Poll loading scenes and move to ready list when reach ~0.9 + for (int i = loadingSceneOps.Count - 1; i >= 0; i--) + { + var (sceneName, op) = loadingSceneOps[i]; + if (op.progress >= 0.89f) + { + // move to ready list so we free a slot for next scene + readySceneOps.Add((sceneName, op)); + loadingSceneOps.RemoveAt(i); + Debug.Log($"Preload: scene '{sceneName}' reached 0.9 and moved to ready list"); + } + + if ((Time.realtimeSinceStartup - frameStart) * 1000f > maxMilliSecondsPerFrame) break; + } + + // Update progress calculation + float overall = CalculateOverallProgress(); + UpdateProgressText(overall); + + // If there are no active resource requests, no loading scenes, no queued scenes/resources, and ready scenes are present (they are considered loaded), we're done + bool anyLoadingScenes = loadingSceneOps.Count > 0 || sceneQueue.Count > 0; + bool anyActiveResources = activeResourceReqs.Count > 0 || resourceQueue.Count > 0; + + if (!anyLoadingScenes && !anyActiveResources) + { + // All loading work started and finished; readySceneOps contains scenes at 0.9 waiting activation + UpdateProgressText(1f); + UpdateLoadingInfo(""); + preloadCoroutine = null; + Debug.Log("Preload complete (throttled). Scenes ready: " + readySceneOps.Count + ", resources cached: " + loadedResources.Count); + + // start fade+disable if configured + if (fadeOutObject != null) + { + StartCoroutine(FadeAndDisableCoroutine()); + } + + yield break; + } + + // yield one frame to respect budget + yield return null; + } + + // if we exit loop, also mark complete + UpdateProgressText(1f); + UpdateLoadingInfo(""); + preloadCoroutine = null; + if (fadeOutObject != null) + { + StartCoroutine(FadeAndDisableCoroutine()); + } + } + + private float CalculateOverallProgress() + { + float sum = 0f; + int items = 0; + + // queued scenes count as 0 + items += sceneQueue.Count; + // loading scenes contribute normalized progress + items += loadingSceneOps.Count; + // ready scenes count as completed (1) + items += readySceneOps.Count; + + items += resourceQueue.Count + activeResourceReqs.Count; + + if (items == 0) return 1f; + + foreach (var (sceneName, op) in loadingSceneOps) + { + float p = Mathf.Clamp01(op.progress / 0.9f); + sum += p; + } + + // ready scenes are counted as full + sum += readySceneOps.Count * 1f; + + foreach (var (path, rr) in activeResourceReqs) + { + sum += rr.progress; // 0..1 + } + + return Mathf.Clamp01(sum / (float)items); + } + + private void UpdateProgressText(float t) + { + int percent = Mathf.RoundToInt(t * 100f); + + // update fill image if present + if (progressFillImage != null) + { + // clamp to 0..1 + progressFillImage.fillAmount = Mathf.Clamp01(t); + } + + if (progressText != null) + { + progressText.text = percent + "%"; + return; + } + + // If no UI assigned, try to find any in children and cache it + var tcomp = GetComponentInChildren(true); + if (tcomp != null) + { + progressText = tcomp; + progressText.text = percent + "%"; + } + } + + // helper to update loading info text + private void UpdateLoadingInfo(string message) + { + if (loadingInfoText != null) + { + loadingInfoText.text = message; + return; + } + + // try to find and cache a Text child that is not the progress text + var texts = GetComponentsInChildren(true); + foreach (var t in texts) + { + if (t != progressText) + { + loadingInfoText = t; + loadingInfoText.text = message; + return; + } + } + } + + private IEnumerator FadeAndDisableCoroutine() + { + // ensure we have a CanvasGroup reference + if (fadeOutObject == null) yield break; + + if (fadeCanvasGroup == null) + { + fadeCanvasGroup = fadeOutObject.GetComponent() ?? fadeOutObject.GetComponentInChildren(true); + } + + // if there's no CanvasGroup, just disable after delay + if (fadeCanvasGroup == null) + { + if (fadeOutDelay > 0f) yield return new WaitForSeconds(fadeOutDelay); + fadeOutObject.SetActive(false); + yield break; + } + + // optionally wait before fading + if (fadeOutDelay > 0f) yield return new WaitForSeconds(fadeOutDelay); + + float startAlpha = fadeCanvasGroup.alpha; + float elapsed = 0f; + while (elapsed < fadeOutDuration) + { + elapsed += Time.deltaTime; + float frac = Mathf.Clamp01(elapsed / Mathf.Max(0.0001f, fadeOutDuration)); + fadeCanvasGroup.alpha = Mathf.Lerp(startAlpha, 0f, frac); + yield return null; + } + + fadeCanvasGroup.alpha = 0f; + // disable raycasts and interaction + fadeCanvasGroup.blocksRaycasts = false; + fadeCanvasGroup.interactable = false; + + // finally disable the GameObject + fadeOutObject.SetActive(false); + } + + /// + /// Activate a previously preloaded additive scene by name (sets allowSceneActivation=true) + /// + public void ActivatePreloadedScene(string sceneName) + { + for (int i = 0; i < readySceneOps.Count; i++) + { + if (readySceneOps[i].sceneName == sceneName) + { + readySceneOps[i].op.allowSceneActivation = true; + // remove from ready list so further activations don't re-trigger + readySceneOps.RemoveAt(i); + return; + } + } + + // fallback: if scene loaded and already in SceneManager, nothing to do + Debug.LogWarning($"ActivatePreloadedScene: scene '{sceneName}' not found among ready preloaded ops."); + } +} diff --git a/Assets/Resources/op/load_preload/preload_allScene.cs.meta b/Assets/Resources/op/load_preload/preload_allScene.cs.meta new file mode 100644 index 00000000..e9fc1e25 --- /dev/null +++ b/Assets/Resources/op/load_preload/preload_allScene.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: da506281e4a56b749a0cf5b32871ff7b \ No newline at end of file diff --git a/Assets/Resources/op/浮动游戏FloatGamingAlpha.png b/Assets/Resources/op/浮动游戏FloatGamingAlpha.png new file mode 100644 index 00000000..03c12129 Binary files /dev/null and b/Assets/Resources/op/浮动游戏FloatGamingAlpha.png differ diff --git a/Assets/Resources/op/浮动游戏FloatGamingAlpha.png.meta b/Assets/Resources/op/浮动游戏FloatGamingAlpha.png.meta new file mode 100644 index 00000000..79d795aa --- /dev/null +++ b/Assets/Resources/op/浮动游戏FloatGamingAlpha.png.meta @@ -0,0 +1,546 @@ +fileFormatVersion: 2 +guid: 707a9f01ed3cb7f49a8e857e282bbff6 +TextureImporter: + internalIDToNameTable: + - first: + 213: 618455519012696024 + second: "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_0" + - first: + 213: -183108937958106121 + second: "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_1" + - first: + 213: -2747514551019907105 + second: "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_2" + - first: + 213: 4051328773356679532 + second: "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_3" + - first: + 213: 683359258392107949 + second: "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_4" + - first: + 213: -6163899235062800083 + second: "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_5" + - first: + 213: 1303736164742555898 + second: "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_6" + - first: + 213: -584840067683796417 + second: "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_7" + - first: + 213: 2726702000583275308 + second: "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_8" + - first: + 213: 5085403667284274677 + second: "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_9" + - first: + 213: -4973876490265236732 + second: "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_10" + - first: + 213: -877950679927288166 + second: "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_11" + - first: + 213: -7274499578471264150 + second: "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_12" + - first: + 213: -4190085041594533794 + second: "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_13" + - first: + 213: -7912233805109702527 + second: "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_14" + - first: + 213: -40987154313807340 + second: "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_15" + 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: 1 + 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: 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: 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 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_0" + rect: + serializedVersion: 2 + x: 242 + y: 248 + width: 270 + height: 343 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 8dfa1209402359800800000000000000 + internalID: 618455519012696024 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_1" + rect: + serializedVersion: 2 + x: 17 + y: 169 + width: 48 + height: 22 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 7fbdecd1467757df0800000000000000 + internalID: -183108937958106121 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_2" + rect: + serializedVersion: 2 + x: 68 + y: 169 + width: 109 + height: 22 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: fd7dd33a21eded9d0800000000000000 + internalID: -2747514551019907105 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_3" + rect: + serializedVersion: 2 + x: 212 + y: 154 + width: 73 + height: 23 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: c617e34fd06393830800000000000000 + internalID: 4051328773356679532 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_4" + rect: + serializedVersion: 2 + x: 266 + y: 18 + width: 114 + height: 179 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: dab9f6aff97cb7900800000000000000 + internalID: 683359258392107949 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_5" + rect: + serializedVersion: 2 + x: 400 + y: 166 + width: 41 + height: 23 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: d21a7cead4e657aa0800000000000000 + internalID: -6163899235062800083 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_6" + rect: + serializedVersion: 2 + x: 447 + y: 166 + width: 40 + height: 23 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: af86f44622dc71210800000000000000 + internalID: 1303736164742555898 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_7" + rect: + serializedVersion: 2 + x: 503 + y: 154 + width: 74 + height: 43 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: f3aba4b9e0b32e7f0800000000000000 + internalID: -584840067683796417 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_8" + rect: + serializedVersion: 2 + x: 589 + y: 18 + width: 176 + height: 179 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: c23fc19d50137d520800000000000000 + internalID: 2726702000583275308 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_9" + rect: + serializedVersion: 2 + x: 0 + y: 18 + width: 57 + height: 121 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 5fda2f711bbf29640800000000000000 + internalID: 5085403667284274677 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_10" + rect: + serializedVersion: 2 + x: 56 + y: 18 + width: 130 + height: 110 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 40be2115fad39fab0800000000000000 + internalID: -4973876490265236732 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_11" + rect: + serializedVersion: 2 + x: 138 + y: 91 + width: 23 + height: 72 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: a9e0f981284e0d3f0800000000000000 + internalID: -877950679927288166 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_12" + rect: + serializedVersion: 2 + x: 199 + y: 44 + width: 93 + height: 90 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: a60dd72ec29cb0b90800000000000000 + internalID: -7274499578471264150 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_13" + rect: + serializedVersion: 2 + x: 392 + y: 18 + width: 40 + height: 121 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: e58741dcad3d9d5c0800000000000000 + internalID: -4190085041594533794 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_14" + rect: + serializedVersion: 2 + x: 427 + y: 18 + width: 74 + height: 145 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 180599a6649123290800000000000000 + internalID: -7912233805109702527 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_15" + rect: + serializedVersion: 2 + x: 497 + y: 18 + width: 83 + height: 121 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 41a75ca76626e6ff0800000000000000 + internalID: -40987154313807340 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_0": 618455519012696024 + "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_1": -183108937958106121 + "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_10": -4973876490265236732 + "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_11": -877950679927288166 + "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_12": -7274499578471264150 + "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_13": -4190085041594533794 + "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_14": -7912233805109702527 + "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_15": -40987154313807340 + "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_2": -2747514551019907105 + "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_3": 4051328773356679532 + "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_4": 683359258392107949 + "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_5": -6163899235062800083 + "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_6": 1303736164742555898 + "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_7": -584840067683796417 + "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_8": 2726702000583275308 + "\u6D6E\u52A8\u6E38\u620FFloatGamingAlpha_9": 5085403667284274677 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/op/资源 2@4x.png b/Assets/Resources/op/资源 2@4x.png new file mode 100644 index 00000000..23dfc82a Binary files /dev/null and b/Assets/Resources/op/资源 2@4x.png differ diff --git a/Assets/Resources/op/资源 2@4x.png.meta b/Assets/Resources/op/资源 2@4x.png.meta new file mode 100644 index 00000000..87510bb2 --- /dev/null +++ b/Assets/Resources/op/资源 2@4x.png.meta @@ -0,0 +1,442 @@ +fileFormatVersion: 2 +guid: 53623fb5a5a76a04b824351e90b8bb49 +TextureImporter: + internalIDToNameTable: + - first: + 213: 234875645205025765 + second: "\u8D44\u6E90 2@4x_0" + - first: + 213: -1984723200111323927 + second: "\u8D44\u6E90 2@4x_1" + - first: + 213: -3748009902473246706 + second: "\u8D44\u6E90 2@4x_2" + - first: + 213: -1682124729092548499 + second: "\u8D44\u6E90 2@4x_3" + - first: + 213: 8035669634750892275 + second: "\u8D44\u6E90 2@4x_4" + - first: + 213: 5531755780828052498 + second: "\u8D44\u6E90 2@4x_5" + - first: + 213: 4622229789299838445 + second: "\u8D44\u6E90 2@4x_6" + - first: + 213: 3325956370787332270 + second: "\u8D44\u6E90 2@4x_7" + - first: + 213: 2495785389425328509 + second: "\u8D44\u6E90 2@4x_8" + - first: + 213: 8032133374648562538 + second: "\u8D44\u6E90 2@4x_9" + - first: + 213: -6379279424289322708 + second: "\u8D44\u6E90 2@4x_10" + - first: + 213: 4610055813025803884 + second: "\u8D44\u6E90 2@4x_11" + 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: 1 + 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: 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: 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 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: "\u8D44\u6E90 2@4x_0" + rect: + serializedVersion: 2 + x: 148 + y: 155 + width: 41 + height: 21 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 5e316d6a722724300800000000000000 + internalID: 234875645205025765 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: "\u8D44\u6E90 2@4x_1" + rect: + serializedVersion: 2 + x: 190 + y: 155 + width: 92 + height: 21 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 9e453e7d3c8d474e0800000000000000 + internalID: -1984723200111323927 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: "\u8D44\u6E90 2@4x_2" + rect: + serializedVersion: 2 + x: 310 + y: 142 + width: 63 + height: 22 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: e088f6cf9d46cfbc0800000000000000 + internalID: -3748009902473246706 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: "\u8D44\u6E90 2@4x_3" + rect: + serializedVersion: 2 + x: 354 + y: 30 + width: 98 + height: 150 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: d68d98e9874e7a8e0800000000000000 + internalID: -1682124729092548499 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: "\u8D44\u6E90 2@4x_4" + rect: + serializedVersion: 2 + x: 467 + y: 153 + width: 36 + height: 21 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 3f848bf35fe648f60800000000000000 + internalID: 8035669634750892275 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: "\u8D44\u6E90 2@4x_5" + rect: + serializedVersion: 2 + x: 505 + y: 153 + width: 36 + height: 21 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 21c387cf29eb4cc40800000000000000 + internalID: 5531755780828052498 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: "\u8D44\u6E90 2@4x_6" + rect: + serializedVersion: 2 + x: 551 + y: 142 + width: 64 + height: 38 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: ded0275f085752040800000000000000 + internalID: 4622229789299838445 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: "\u8D44\u6E90 2@4x_7" + rect: + serializedVersion: 2 + x: 622 + y: 30 + width: 155 + height: 150 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: ea0f93392bb282e20800000000000000 + internalID: 3325956370787332270 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: "\u8D44\u6E90 2@4x_8" + rect: + serializedVersion: 2 + x: 133 + y: 30 + width: 158 + height: 101 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: d718e44a69fc2a220800000000000000 + internalID: 2495785389425328509 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: "\u8D44\u6E90 2@4x_9" + rect: + serializedVersion: 2 + x: 248 + y: 90 + width: 22 + height: 63 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: a63bc788fbed77f60800000000000000 + internalID: 8032133374648562538 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: "\u8D44\u6E90 2@4x_10" + rect: + serializedVersion: 2 + x: 299 + y: 50 + width: 79 + height: 79 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: c29c648992f3877a0800000000000000 + internalID: -6379279424289322708 + vertices: [] + indices: + edges: [] + weights: [] + - serializedVersion: 2 + name: "\u8D44\u6E90 2@4x_11" + rect: + serializedVersion: 2 + x: 458 + y: 30 + width: 160 + height: 123 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: c6ea02a36553aff30800000000000000 + internalID: 4610055813025803884 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + "\u8D44\u6E90 2@4x_0": 234875645205025765 + "\u8D44\u6E90 2@4x_1": -1984723200111323927 + "\u8D44\u6E90 2@4x_10": -6379279424289322708 + "\u8D44\u6E90 2@4x_11": 4610055813025803884 + "\u8D44\u6E90 2@4x_2": -3748009902473246706 + "\u8D44\u6E90 2@4x_3": -1682124729092548499 + "\u8D44\u6E90 2@4x_4": 8035669634750892275 + "\u8D44\u6E90 2@4x_5": 5531755780828052498 + "\u8D44\u6E90 2@4x_6": 4622229789299838445 + "\u8D44\u6E90 2@4x_7": 3325956370787332270 + "\u8D44\u6E90 2@4x_8": 2495785389425328509 + "\u8D44\u6E90 2@4x_9": 8032133374648562538 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/so.meta b/Assets/Resources/so.meta new file mode 100644 index 00000000..c73380b4 --- /dev/null +++ b/Assets/Resources/so.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 211bb2c8eaae7ad4684c90d668d27835 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/so/ally.meta b/Assets/Resources/so/ally.meta new file mode 100644 index 00000000..3a454d8d --- /dev/null +++ b/Assets/Resources/so/ally.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: de45872e854592b4f9fe42c729492dac +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/so/ally/30201.meta b/Assets/Resources/so/ally/30201.meta new file mode 100644 index 00000000..4e7a339c --- /dev/null +++ b/Assets/Resources/so/ally/30201.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fc984c4f2c669d94cadcf53239965b8a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/so/ally/30201/Ayano.png b/Assets/Resources/so/ally/30201/Ayano.png new file mode 100644 index 00000000..716746cc Binary files /dev/null and b/Assets/Resources/so/ally/30201/Ayano.png differ diff --git a/Assets/Resources/so/ally/30201/Ayano.png.meta b/Assets/Resources/so/ally/30201/Ayano.png.meta new file mode 100644 index 00000000..85162949 --- /dev/null +++ b/Assets/Resources/so/ally/30201/Ayano.png.meta @@ -0,0 +1,155 @@ +fileFormatVersion: 2 +guid: 991800b03b1fd7f44ad3b3e8eb63d7e0 +TextureImporter: + internalIDToNameTable: + - first: + 213: -7736830374416659762 + second: Ayano_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: 2 + spriteExtrude: 1 + spriteMeshType: 1 + 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: 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: 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 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: Ayano_0 + rect: + serializedVersion: 2 + x: 0 + y: 0 + width: 323 + height: 63 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: eca417514c141a490800000000000000 + internalID: -7736830374416659762 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/so/ally/30201_ayano.asset b/Assets/Resources/so/ally/30201_ayano.asset new file mode 100644 index 00000000..1abf4338 --- /dev/null +++ b/Assets/Resources/so/ally/30201_ayano.asset @@ -0,0 +1,57 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bdd198d96872f3b42bdfc7e262ff2eed, type: 3} + m_Name: 30201_ayano + m_EditorClassIdentifier: + ally_heroName: Ayano + ally_heroID: 30201 + ally_heroImage: {fileID: -7736830374416659762, guid: 991800b03b1fd7f44ad3b3e8eb63d7e0, type: 3} + ally_heroProfile: {fileID: 0} + ally_heroIcon: {fileID: 0} + levelStats: + - levelName: Level 1 + levelID: 1 + attack: 0 + maxHP: 100 + damageResistance: 0 + maxMana: 100 + scoreEfficiency: 0 + requiredEXP: 0 + manaGainGood: 1 + manaGainGreat: 2 + manaGainPerfect: 3 + manaGainOnMiss: 5 + damageMultiplierGood: 0.5 + damageMultiplierGreat: 0.75 + damageMultiplierPerfect: 1 + missHpLossBase: 10 + - levelName: Level 2 + levelID: 2 + attack: 0 + maxHP: 100 + damageResistance: 0 + maxMana: 0 + scoreEfficiency: 0 + requiredEXP: 1 + manaGainGood: 1 + manaGainGreat: 2 + manaGainPerfect: 3 + manaGainOnMiss: 5 + damageMultiplierGood: 0.5 + damageMultiplierGreat: 0.75 + damageMultiplierPerfect: 1 + missHpLossBase: 10 + ally_currentEXP: 0 + availableSkills: + - {fileID: 11400000, guid: 9c2d57fabf3a506499779b3d430f595b, type: 2} + selectedSkillIndices: 00000000 + primarySkillIndex: 0 diff --git a/Assets/Resources/so/ally/30201_ayano.asset.meta b/Assets/Resources/so/ally/30201_ayano.asset.meta new file mode 100644 index 00000000..db98e9cd --- /dev/null +++ b/Assets/Resources/so/ally/30201_ayano.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 390a8f8f210be2e489aea46cf4403e24 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/so/ally/30202.meta b/Assets/Resources/so/ally/30202.meta new file mode 100644 index 00000000..c6d76330 --- /dev/null +++ b/Assets/Resources/so/ally/30202.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7f6754e451e8b8c40a22bac6cdf45ce2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/so/ally/30202/YueTao.png b/Assets/Resources/so/ally/30202/YueTao.png new file mode 100644 index 00000000..a1edc5a2 Binary files /dev/null and b/Assets/Resources/so/ally/30202/YueTao.png differ diff --git a/Assets/Resources/so/ally/30202/YueTao.png.meta b/Assets/Resources/so/ally/30202/YueTao.png.meta new file mode 100644 index 00000000..629bb846 --- /dev/null +++ b/Assets/Resources/so/ally/30202/YueTao.png.meta @@ -0,0 +1,155 @@ +fileFormatVersion: 2 +guid: 5f93d010e49316d4594c1065ce5c6d85 +TextureImporter: + internalIDToNameTable: + - first: + 213: 2718893390870541660 + second: YueTao_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: 2 + spriteExtrude: 1 + spriteMeshType: 1 + 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: 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: 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 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: YueTao_0 + rect: + serializedVersion: 2 + x: 0 + y: 0 + width: 323 + height: 63 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: c55fef832237bb520800000000000000 + internalID: 2718893390870541660 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/so/ally/30202_yuetao.asset b/Assets/Resources/so/ally/30202_yuetao.asset new file mode 100644 index 00000000..8d4ea68c --- /dev/null +++ b/Assets/Resources/so/ally/30202_yuetao.asset @@ -0,0 +1,57 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bdd198d96872f3b42bdfc7e262ff2eed, type: 3} + m_Name: 30202_yuetao + m_EditorClassIdentifier: + ally_heroName: Yue Tao + ally_heroID: 30202 + ally_heroImage: {fileID: 2718893390870541660, guid: 5f93d010e49316d4594c1065ce5c6d85, type: 3} + ally_heroProfile: {fileID: 0} + ally_heroIcon: {fileID: 0} + levelStats: + - levelName: Level 1 + levelID: 1 + attack: 6 + maxHP: 114514 + damageResistance: 0 + maxMana: 101 + scoreEfficiency: 0 + requiredEXP: 0 + manaGainGood: 1 + manaGainGreat: 2 + manaGainPerfect: 3 + manaGainOnMiss: 5 + damageMultiplierGood: 0.5 + damageMultiplierGreat: 0.75 + damageMultiplierPerfect: 1 + missHpLossBase: 10 + - levelName: Level 2 + levelID: 2 + attack: 100 + maxHP: 200 + damageResistance: 0 + maxMana: 666 + scoreEfficiency: 0 + requiredEXP: 11 + manaGainGood: 1 + manaGainGreat: 2 + manaGainPerfect: 3 + manaGainOnMiss: 5 + damageMultiplierGood: 0.5 + damageMultiplierGreat: 0.75 + damageMultiplierPerfect: 1 + missHpLossBase: 10 + ally_currentEXP: 12 + availableSkills: + - {fileID: 11400000, guid: 75f453e0c37644343897f37b063bbfd4, type: 2} + selectedSkillIndices: + primarySkillIndex: 0 diff --git a/Assets/Resources/so/ally/30202_yuetao.asset.meta b/Assets/Resources/so/ally/30202_yuetao.asset.meta new file mode 100644 index 00000000..06d4cc7f --- /dev/null +++ b/Assets/Resources/so/ally/30202_yuetao.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b483e2401e5f6284fb91953e2e83111e +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/so/ally/30303.meta b/Assets/Resources/so/ally/30303.meta new file mode 100644 index 00000000..9de7f15f --- /dev/null +++ b/Assets/Resources/so/ally/30303.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3843d751564d952429b1c2f88aecf636 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/so/ally/30303/Moyuri.png b/Assets/Resources/so/ally/30303/Moyuri.png new file mode 100644 index 00000000..29a93a50 Binary files /dev/null and b/Assets/Resources/so/ally/30303/Moyuri.png differ diff --git a/Assets/Resources/so/ally/30303/Moyuri.png.meta b/Assets/Resources/so/ally/30303/Moyuri.png.meta new file mode 100644 index 00000000..9c19b34a --- /dev/null +++ b/Assets/Resources/so/ally/30303/Moyuri.png.meta @@ -0,0 +1,155 @@ +fileFormatVersion: 2 +guid: 893e9ceec19c4cc4d9d0326a6a48e2bd +TextureImporter: + internalIDToNameTable: + - first: + 213: 390925012957057715 + second: Moyuri_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: 2 + spriteExtrude: 1 + spriteMeshType: 1 + 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: 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: 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 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: Moyuri_0 + rect: + serializedVersion: 2 + x: 0 + y: 0 + width: 323 + height: 63 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: 3b2de136a38dc6500800000000000000 + internalID: 390925012957057715 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/so/ally/30303_moyuri.asset b/Assets/Resources/so/ally/30303_moyuri.asset new file mode 100644 index 00000000..33c9d9a2 --- /dev/null +++ b/Assets/Resources/so/ally/30303_moyuri.asset @@ -0,0 +1,57 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bdd198d96872f3b42bdfc7e262ff2eed, type: 3} + m_Name: 30303_moyuri + m_EditorClassIdentifier: + ally_heroName: Moyuri + ally_heroID: 30303 + ally_heroImage: {fileID: 390925012957057715, guid: 893e9ceec19c4cc4d9d0326a6a48e2bd, type: 3} + ally_heroProfile: {fileID: 0} + ally_heroIcon: {fileID: 0} + levelStats: + - levelName: Level 1 + levelID: 1 + attack: 6 + maxHP: 114514 + damageResistance: 0 + maxMana: 101 + scoreEfficiency: 0 + requiredEXP: 0 + manaGainGood: 1 + manaGainGreat: 2 + manaGainPerfect: 3 + manaGainOnMiss: 5 + damageMultiplierGood: 0.5 + damageMultiplierGreat: 0.75 + damageMultiplierPerfect: 1 + missHpLossBase: 10 + - levelName: Level 2 + levelID: 2 + attack: 100 + maxHP: 123 + damageResistance: 0 + maxMana: 100 + scoreEfficiency: 0 + requiredEXP: 11 + manaGainGood: 1 + manaGainGreat: 2 + manaGainPerfect: 3 + manaGainOnMiss: 5 + damageMultiplierGood: 0.5 + damageMultiplierGreat: 0.75 + damageMultiplierPerfect: 1 + missHpLossBase: 10 + ally_currentEXP: 12 + availableSkills: + - {fileID: 11400000, guid: bdc66177d5ae680438237bf717dd26d8, type: 2} + selectedSkillIndices: + primarySkillIndex: 0 diff --git a/Assets/Resources/so/ally/30303_moyuri.asset.meta b/Assets/Resources/so/ally/30303_moyuri.asset.meta new file mode 100644 index 00000000..68ddb073 --- /dev/null +++ b/Assets/Resources/so/ally/30303_moyuri.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f7b88d014e0b54342848b47aedca49c3 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/so/ally/notFound.png b/Assets/Resources/so/ally/notFound.png new file mode 100644 index 00000000..d89d893e Binary files /dev/null and b/Assets/Resources/so/ally/notFound.png differ diff --git a/Assets/Resources/so/ally/notFound.png.meta b/Assets/Resources/so/ally/notFound.png.meta new file mode 100644 index 00000000..cdc3ad9c --- /dev/null +++ b/Assets/Resources/so/ally/notFound.png.meta @@ -0,0 +1,156 @@ +fileFormatVersion: 2 +guid: a8c42276e289c3f4d8df7ebc510e67a4 +TextureImporter: + internalIDToNameTable: + - first: + 213: -8618468658663994465 + second: "\u8F68\u9053\u7F6E\u7A7A\u89D2\u8272\uFF08\u5360\u4F4D\u7B26\uFF09_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: 2 + spriteExtrude: 1 + spriteMeshType: 1 + 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: 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: 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 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: "\u8F68\u9053\u7F6E\u7A7A\u89D2\u8272\uFF08\u5360\u4F4D\u7B26\uFF09_0" + rect: + serializedVersion: 2 + x: 0 + y: 0 + width: 323 + height: 63 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: -1 + bones: [] + spriteID: f9bce74ea6c056880800000000000000 + internalID: -8618468658663994465 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + "\u8F68\u9053\u7F6E\u7A7A\u89D2\u8272\uFF08\u5360\u4F4D\u7B26\uFF09_0": -8618468658663994465 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/so/enemies.meta b/Assets/Resources/so/enemies.meta new file mode 100644 index 00000000..2b31e098 --- /dev/null +++ b/Assets/Resources/so/enemies.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 30cb68bde8fe7e94893865d055e79797 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/so/skill_allySkills.meta b/Assets/Resources/so/skill_allySkills.meta new file mode 100644 index 00000000..a114a620 --- /dev/null +++ b/Assets/Resources/so/skill_allySkills.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e872e5fb91e13ba4381a94ed48c58962 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/so/skill_allySkills/44001_yaoxueyin.asset b/Assets/Resources/so/skill_allySkills/44001_yaoxueyin.asset new file mode 100644 index 00000000..0c77e35d --- /dev/null +++ b/Assets/Resources/so/skill_allySkills/44001_yaoxueyin.asset @@ -0,0 +1,29 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 265d1552ebf55c34a98934707b2c20ce, type: 3} + m_Name: 44001_yaoxueyin + m_EditorClassIdentifier: + skillId: 44001 + displayName: yaoxueyin_skill01 + summaryInfo: + effectType: 4 + defaultSelector: 3 + formula: 0 + defaultDuration: 0 + defaultTickInterval: 0 + requiresSpecificTarget: 0 + operateDirectly: 0 + description: + triggerCondition: 0 + onNoteHitMinThreshold: 1 + noteTriggerType: 2 + onNoteHitCooldown: 0 diff --git a/Assets/Resources/so/skill_allySkills/44001_yaoxueyin.asset.meta b/Assets/Resources/so/skill_allySkills/44001_yaoxueyin.asset.meta new file mode 100644 index 00000000..a197b02a --- /dev/null +++ b/Assets/Resources/so/skill_allySkills/44001_yaoxueyin.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9c2d57fabf3a506499779b3d430f595b +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/so/skill_allySkills/44002_yuetao.asset b/Assets/Resources/so/skill_allySkills/44002_yuetao.asset new file mode 100644 index 00000000..60dd5a84 --- /dev/null +++ b/Assets/Resources/so/skill_allySkills/44002_yuetao.asset @@ -0,0 +1,29 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 265d1552ebf55c34a98934707b2c20ce, type: 3} + m_Name: 44002_yuetao + m_EditorClassIdentifier: + skillId: 44002 + displayName: increaseMana_yuetao + summaryInfo: "44002\u8DC3\u6843\uFF1A\u76F8\u90BB\u53CB\u65B9\u6301\u7EED\u56DE\u84DD" + effectType: 4 + defaultSelector: 3 + formula: 20 + defaultDuration: 5 + defaultTickInterval: 1 + requiresSpecificTarget: 0 + operateDirectly: 0 + description: "44002 \u8DC3\u6843\uFF1A\n\n\u6761\u4EF6\uFF1A\u5728\u6CD5\u529B\u503C\u6EE1\u65F6\u91CA\u653E\u3002\n\u6570\u636E\uFF1A\u516C\u5F0F\u975E\u5B9A\u503C\u8BA1\u7B97\n\n\u5728\u6CD5\u529B\u503C\u6EE1\u65F6\uFF0C\u4E3A\u76F8\u90BB\u7684\u53CB\u519B\u6BCF1\u79D2\u56DE\u590D(\u57FA\u7840\u653B\u51FB\u529B)*0.5+5\u7684\u6CD5\u529B\uFF0C\u6301\u7EED3\u79D2\u3002" + triggerCondition: 2 + onNoteHitMinThreshold: 0 + noteTriggerType: 2 + onNoteHitCooldown: 1 diff --git a/Assets/Resources/so/skill_allySkills/44002_yuetao.asset.meta b/Assets/Resources/so/skill_allySkills/44002_yuetao.asset.meta new file mode 100644 index 00000000..f716567f --- /dev/null +++ b/Assets/Resources/so/skill_allySkills/44002_yuetao.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 75f453e0c37644343897f37b063bbfd4 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/so/skill_allySkills/44003_moyuri.asset b/Assets/Resources/so/skill_allySkills/44003_moyuri.asset new file mode 100644 index 00000000..050c98f0 --- /dev/null +++ b/Assets/Resources/so/skill_allySkills/44003_moyuri.asset @@ -0,0 +1,29 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 265d1552ebf55c34a98934707b2c20ce, type: 3} + m_Name: 44003_moyuri + m_EditorClassIdentifier: + skillId: + displayName: + summaryInfo: + effectType: 0 + defaultSelector: 4 + formula: + defaultDuration: 0 + defaultTickInterval: 1 + requiresSpecificTarget: 0 + operateDirectly: 0 + description: + triggerCondition: 0 + onNoteHitMinThreshold: 1 + noteTriggerType: 2 + onNoteHitCooldown: 0 diff --git a/Assets/Resources/so/skill_allySkills/44003_moyuri.asset.meta b/Assets/Resources/so/skill_allySkills/44003_moyuri.asset.meta new file mode 100644 index 00000000..6cf46d1c --- /dev/null +++ b/Assets/Resources/so/skill_allySkills/44003_moyuri.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bdc66177d5ae680438237bf717dd26d8 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/Main_main.unity b/Assets/Scenes/Main_main.unity index beb76442..753fe221 100644 --- a/Assets/Scenes/Main_main.unity +++ b/Assets/Scenes/Main_main.unity @@ -273,6 +273,83 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 73146554} m_CullTransparentMesh: 1 +--- !u!1 &182328454 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 182328455} + - component: {fileID: 182328457} + - component: {fileID: 182328456} + m_Layer: 0 + m_Name: blackBottom + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &182328455 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 182328454} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1872466268} + - {fileID: 1419788765} + m_Father: {fileID: 849894528} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 1920, y: 1080} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &182328456 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 182328454} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0, b: 0, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &182328457 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 182328454} + m_CullTransparentMesh: 1 --- !u!1 &224223031 GameObject: m_ObjectHideFlags: 0 @@ -671,6 +748,85 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &623677385 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 623677386} + - component: {fileID: 623677388} + - component: {fileID: 623677387} + m_Layer: 0 + m_Name: loadingWhat + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &623677386 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 623677385} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 849894528} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 344.1, y: -384} + m_SizeDelta: {x: 497.7007, y: 140.77} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &623677387 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 623677385} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.9056604, g: 0.9056604, b: 0.9056604, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 12800000, guid: ec651258a51214d47953d3316e0ce983, type: 3} + m_FontSize: 24 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 59 + m_Alignment: 5 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: loadingObject +--- !u!222 &623677388 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 623677385} + m_CullTransparentMesh: 1 --- !u!1 &736871618 GameObject: m_ObjectHideFlags: 0 @@ -897,8 +1053,8 @@ AudioSource: m_Enabled: 1 serializedVersion: 4 OutputAudioMixerGroup: {fileID: 0} - m_audioClip: {fileID: 8300000, guid: 8ed30022249917f4fb5c65d026b896d6, type: 3} - m_Resource: {fileID: 8300000, guid: 8ed30022249917f4fb5c65d026b896d6, type: 3} + m_audioClip: {fileID: 8300000, guid: afef27d42a820784a914abd621cb2c09, type: 3} + m_Resource: {fileID: 8300000, guid: afef27d42a820784a914abd621cb2c09, type: 3} m_PlayOnAwake: 0 m_Volume: 1 m_Pitch: 1 @@ -1074,6 +1230,123 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 816275736} m_CullTransparentMesh: 1 +--- !u!1 &849894527 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 849894528} + - component: {fileID: 849894531} + - component: {fileID: 849894530} + - component: {fileID: 849894529} + - component: {fileID: 849894532} + m_Layer: 0 + m_Name: thisCanvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &849894528 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 849894527} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 182328455} + - {fileID: 1401636780} + - {fileID: 623677386} + m_Father: {fileID: 1903432995} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!114 &849894529 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 849894527} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &849894530 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 849894527} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 1 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 1920, y: 1080} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 + m_PresetInfoIsWorld: 0 +--- !u!223 &849894531 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 849894527} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_VertexColorAlwaysGammaSpace: 1 + m_AdditionalShaderChannelsFlag: 0 + m_UpdateRectTransformForStandalone: 0 + m_SortingLayerID: 0 + m_SortingOrder: 32767 + m_TargetDisplay: 0 +--- !u!225 &849894532 +CanvasGroup: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 849894527} + m_Enabled: 1 + m_Alpha: 1 + m_Interactable: 1 + m_BlocksRaycasts: 1 + m_IgnoreParentGroups: 0 --- !u!1 &958271890 GameObject: m_ObjectHideFlags: 0 @@ -1633,6 +1906,160 @@ Transform: m_Children: [] m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1401636779 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1401636780} + - component: {fileID: 1401636782} + - component: {fileID: 1401636781} + m_Layer: 0 + m_Name: jindu + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1401636780 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1401636779} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 849894528} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -348.63, y: -384} + m_SizeDelta: {x: 497.7007, y: 140.77} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1401636781 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1401636779} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.9056604, g: 0.9056604, b: 0.9056604, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 12800000, guid: ec651258a51214d47953d3316e0ce983, type: 3} + m_FontSize: 24 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 59 + m_Alignment: 3 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: loadingPercent% +--- !u!222 &1401636782 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1401636779} + m_CullTransparentMesh: 1 +--- !u!1 &1419788764 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1419788765} + - component: {fileID: 1419788767} + - component: {fileID: 1419788766} + m_Layer: 0 + m_Name: loadingPanel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1419788765 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1419788764} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 182328455} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: -408.32} + m_SizeDelta: {x: 1192, y: 12} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1419788766 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1419788764} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 9099771840580648462, guid: 6bf71d2cb6281dc4c994526868b3379d, type: 3} + m_Type: 3 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 0 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1419788767 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1419788764} + m_CullTransparentMesh: 1 --- !u!1 &1610130039 GameObject: m_ObjectHideFlags: 0 @@ -2051,6 +2478,143 @@ Canvas: m_SortingLayerID: 0 m_SortingOrder: 1 m_TargetDisplay: 0 +--- !u!1 &1872466267 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1872466268} + - component: {fileID: 1872466270} + - component: {fileID: 1872466269} + m_Layer: 0 + m_Name: logo_fdLogo + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1872466268 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1872466267} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.25, y: 0.25, z: 0.25} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 182328455} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 765, y: 638} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1872466269 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1872466267} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 707a9f01ed3cb7f49a8e857e282bbff6, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1872466270 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1872466267} + m_CullTransparentMesh: 1 +--- !u!1 &1903432994 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1903432995} + - component: {fileID: 1903432996} + m_Layer: 0 + m_Name: logo_and_load + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1903432995 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1903432994} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 659.97345, y: 501.6619, z: -9.434833} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 849894528} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1903432996 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1903432994} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: da506281e4a56b749a0cf5b32871ff7b, type: 3} + m_Name: + m_EditorClassIdentifier: + scenesToPreload: + - gamePlay_gamePlay + - selectYourSongFirst + - Songs_Select + - UI_UI + resourcesToPreload: [] + progressText: {fileID: 1401636781} + progressFillImage: {fileID: 1419788766} + loadingInfoText: {fileID: 623677387} + startOnAwake: 1 + fadeOutObject: {fileID: 849894527} + fadeCanvasGroup: {fileID: 849894532} + fadeOutDuration: 2 + fadeOutDelay: 0.5 + maxConcurrentResourceLoads: 2 + maxConcurrentSceneLoads: 1 + maxMilliSecondsPerFrame: 4 --- !u!1 &1906290265 GameObject: m_ObjectHideFlags: 0 @@ -2233,3 +2797,4 @@ SceneRoots: - {fileID: 1313638918} - {fileID: 1735952444} - {fileID: 777304730} + - {fileID: 1903432995} diff --git a/Assets/Scenes/gamePlay_gamePlay.unity b/Assets/Scenes/gamePlay_gamePlay.unity index 4b5b20a7..65d65809 100644 --- a/Assets/Scenes/gamePlay_gamePlay.unity +++ b/Assets/Scenes/gamePlay_gamePlay.unity @@ -189,7 +189,7 @@ MonoBehaviour: m_PreserveAspect: 0 m_FillCenter: 1 m_FillMethod: 0 - m_FillAmount: 1 + m_FillAmount: 0 m_FillClockwise: 1 m_FillOrigin: 0 m_UseSpriteMesh: 0 @@ -569,7 +569,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: -4278035512617938032, guid: 359d6ebc01b89564185a24ecfdaecc8d, type: 3} + m_Sprite: {fileID: -8618468658663994465, guid: a8c42276e289c3f4d8df7ebc510e67a4, type: 3} m_Type: 0 m_PreserveAspect: 0 m_FillCenter: 1 @@ -637,7 +637,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 0.5882353} + m_Color: {r: 1, g: 1, b: 1, a: 0.19607843} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 @@ -645,10 +645,10 @@ MonoBehaviour: m_PersistentCalls: m_Calls: [] m_Sprite: {fileID: -6758692635247331641, guid: 5c4bf57c045ea4d49818477bab46bd3a, type: 3} - m_Type: 0 + m_Type: 3 m_PreserveAspect: 0 m_FillCenter: 1 - m_FillMethod: 4 + m_FillMethod: 0 m_FillAmount: 1 m_FillClockwise: 1 m_FillOrigin: 0 @@ -855,7 +855,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_text: nowScore/maxScore + m_text: 0/2147483646 m_isRightToLeft: 0 m_fontAsset: {fileID: 11400000, guid: 47babadf44fc728438ae9a924c42227e, type: 2} m_sharedMaterial: {fileID: 6312708493749940865, guid: 47babadf44fc728438ae9a924c42227e, type: 2} @@ -943,6 +943,7 @@ GameObject: serializedVersion: 6 m_Component: - component: {fileID: 79799135} + - component: {fileID: 79799136} m_Layer: 0 m_Name: ally_01 m_TagString: Untagged @@ -972,6 +973,33 @@ Transform: - {fileID: 1353127880} m_Father: {fileID: 1587371259} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &79799136 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 79799134} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d966ccc05a974124baf07b34117841e8, type: 3} + m_Name: + m_EditorClassIdentifier: + slotIndex: 0 + maxHP: 1111 + currentHP: 1111 + maxMana: 100 + currentMana: 0 + damageResistance: 0 + scoreEfficiency: 1 + attack: 0 + baseTrackScore: 1000 + greatRatio: 0.75 + goodRatio: 0.5 + missRatio: 0 + currentScore: 0 + maxTrackScore: 2147483646 + allowOverwriteFromSO: 1 --- !u!1 &96464576 GameObject: m_ObjectHideFlags: 0 @@ -1029,7 +1057,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: -4278035512617938032, guid: 359d6ebc01b89564185a24ecfdaecc8d, type: 3} + m_Sprite: {fileID: -8618468658663994465, guid: a8c42276e289c3f4d8df7ebc510e67a4, type: 3} m_Type: 0 m_PreserveAspect: 0 m_FillCenter: 1 @@ -1924,6 +1952,135 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 211588066} m_CullTransparentMesh: 1 +--- !u!1 &213433698 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 213433700} + - component: {fileID: 213433699} + m_Layer: 0 + m_Name: perfect + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!82 &213433699 +AudioSource: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 213433698} + m_Enabled: 1 + serializedVersion: 4 + OutputAudioMixerGroup: {fileID: 0} + m_audioClip: {fileID: 8300000, guid: fae24344d433d714fadfa0ca8e285f7f, type: 3} + m_Resource: {fileID: 8300000, guid: fae24344d433d714fadfa0ca8e285f7f, type: 3} + m_PlayOnAwake: 0 + m_Volume: 1 + m_Pitch: 1 + Loop: 0 + Mute: 0 + Spatialize: 0 + SpatializePostEffects: 0 + Priority: 128 + DopplerLevel: 1 + MinDistance: 1 + MaxDistance: 500 + Pan2D: 0 + rolloffMode: 0 + BypassEffects: 0 + BypassListenerEffects: 0 + BypassReverbZones: 0 + rolloffCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + panLevelCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + spreadCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + reverbZoneMixCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 +--- !u!4 &213433700 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 213433698} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1374242168} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &219577657 GameObject: m_ObjectHideFlags: 0 @@ -2073,7 +2230,7 @@ MonoBehaviour: m_PreserveAspect: 0 m_FillCenter: 1 m_FillMethod: 0 - m_FillAmount: 1 + m_FillAmount: 0 m_FillClockwise: 1 m_FillOrigin: 0 m_UseSpriteMesh: 0 @@ -2611,7 +2768,7 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: 0.7816, y: -300.75} + m_AnchoredPosition: {x: 0.7816, y: -318.6} m_SizeDelta: {x: 1291.5632, y: 500} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &288692017 @@ -3796,6 +3953,9 @@ GameObject: m_Component: - component: {fileID: 368084896} - component: {fileID: 368084897} + - component: {fileID: 368084898} + - component: {fileID: 368084899} + - component: {fileID: 368084900} m_Layer: 0 m_Name: TeamUI m_TagString: Untagged @@ -3832,6 +3992,15 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 756cb32790bbee94ebb3e3b1cf061392, type: 3} m_Name: m_EditorClassIdentifier: + allySlotIds: f97500005f760000fa750000f97500005f760000 + editorSOFolderPath: Assets/Resources/so/ally + runtimeResourcesFolderPath: so/ally + ally01_object: {fileID: 79799134} + ally02_object: {fileID: 1605862687} + ally03_object: {fileID: 1500657741} + ally04_object: {fileID: 1338578115} + ally05_object: {fileID: 1890740500} + selectedProjectFolderPath: Assets/Resources/so/ally songNametitle: {fileID: 431474993} difficultyName: {fileID: 311523889} difficultyID: {fileID: 1911075704} @@ -3840,8 +4009,8 @@ MonoBehaviour: enemyCounter: {fileID: 1176013885} enemyCounterMax: 0 enemyCurrentCount: 0 - currentTotalScore: {fileID: 1943105383} - comboJudgeType: 0 + currentTotalScore: {fileID: 0} + comboJudgeType: 2 objectFather_ally01: {fileID: 79799134} isAlly01_active: 1 teammate01_characterImage: {fileID: 96464578} @@ -3932,6 +4101,57 @@ MonoBehaviour: currentEnemy_current_scoreText: {fileID: 0} enemy_id: 0 currentEnemy_hurtRedImage: {fileID: 182107135} +--- !u!114 &368084898 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 368084895} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: debeba9c3c2f7334ab04c769534a1f85, type: 3} + m_Name: + m_EditorClassIdentifier: + teamSettingPanelInstance: {fileID: 0} + currentSelectedTeam: 0 + currentSelectedTeamCharacter: -1 +--- !u!114 &368084899 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 368084895} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 53ea14de0f25c18469332fda60802db9, type: 3} + m_Name: + m_EditorClassIdentifier: + defaultDamage: 100 + defaultHeal: 80 + defaultDuration: 5 + defaultTickInterval: 1 + manaGainGood: 1 + manaGainGreat: 2 + manaGainPerfect: 3 + manaGainOnMiss: 5 + damageMultiplierGood: 0.5 + damageMultiplierGreat: 0.75 + damageMultiplierPerfect: 1 + missHpLossBase: 10 +--- !u!114 &368084900 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 368084895} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ac6185c2505b3ec47af065d12a0dd2b6, type: 3} + m_Name: + m_EditorClassIdentifier: --- !u!1 &369395968 stripped GameObject: m_CorrespondingSourceObject: {fileID: 6405457093900378514, guid: 445dee7ff58e8e847bec43634276b24e, type: 3} @@ -4199,7 +4419,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_text: curHP/MaxHP + m_text: 100/100 m_isRightToLeft: 0 m_fontAsset: {fileID: 11400000, guid: 47babadf44fc728438ae9a924c42227e, type: 2} m_sharedMaterial: {fileID: 6312708493749940865, guid: 47babadf44fc728438ae9a924c42227e, type: 2} @@ -4423,6 +4643,7 @@ MonoBehaviour: holdNoteEndPrefabs: [] spawnOffset: 0.1 bpm: 0 + globalHitDelay: 0 judgeConfig: {fileID: 0} --- !u!114 &397604453 MonoBehaviour: @@ -4588,7 +4809,137 @@ MonoBehaviour: - {fileID: 1102374847} spawnOffset: 0.1 bpm: 160 + globalHitDelay: 0 judgeConfig: {fileID: 11400000, guid: f870aa419242e72438b57ac9659f61e9, type: 2} +--- !u!1 &400656413 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 400656415} + - component: {fileID: 400656414} + m_Layer: 0 + m_Name: great + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!82 &400656414 +AudioSource: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 400656413} + m_Enabled: 1 + serializedVersion: 4 + OutputAudioMixerGroup: {fileID: 0} + m_audioClip: {fileID: 8300000, guid: 36799a159f61a5e489dd0963de4bf661, type: 3} + m_Resource: {fileID: 8300000, guid: 36799a159f61a5e489dd0963de4bf661, type: 3} + m_PlayOnAwake: 0 + m_Volume: 1 + m_Pitch: 1 + Loop: 0 + Mute: 0 + Spatialize: 0 + SpatializePostEffects: 0 + Priority: 128 + DopplerLevel: 1 + MinDistance: 1 + MaxDistance: 500 + Pan2D: 0 + rolloffMode: 0 + BypassEffects: 0 + BypassListenerEffects: 0 + BypassReverbZones: 0 + rolloffCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + panLevelCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + spreadCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + reverbZoneMixCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 +--- !u!4 &400656415 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 400656413} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1374242168} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &408709854 GameObject: m_ObjectHideFlags: 0 @@ -4795,6 +5146,7 @@ MonoBehaviour: holdNoteEndPrefabs: [] spawnOffset: 0.1 bpm: 0 + globalHitDelay: 0 judgeConfig: {fileID: 0} --- !u!61 &411632596 BoxCollider2D: @@ -4939,7 +5291,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: -4278035512617938032, guid: 359d6ebc01b89564185a24ecfdaecc8d, type: 3} + m_Sprite: {fileID: -8618468658663994465, guid: a8c42276e289c3f4d8df7ebc510e67a4, type: 3} m_Type: 0 m_PreserveAspect: 0 m_FillCenter: 1 @@ -5086,7 +5438,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: -4278035512617938032, guid: 359d6ebc01b89564185a24ecfdaecc8d, type: 3} + m_Sprite: {fileID: -8618468658663994465, guid: a8c42276e289c3f4d8df7ebc510e67a4, type: 3} m_Type: 0 m_PreserveAspect: 0 m_FillCenter: 1 @@ -5161,7 +5513,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_text: nowScore/maxScore + m_text: 0/2147483646 m_isRightToLeft: 0 m_fontAsset: {fileID: 11400000, guid: 47babadf44fc728438ae9a924c42227e, type: 2} m_sharedMaterial: {fileID: 6312708493749940865, guid: 47babadf44fc728438ae9a924c42227e, type: 2} @@ -5433,7 +5785,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_text: curHP/MaxHP + m_text: 100/100 m_isRightToLeft: 0 m_fontAsset: {fileID: 11400000, guid: 47babadf44fc728438ae9a924c42227e, type: 2} m_sharedMaterial: {fileID: 6312708493749940865, guid: 47babadf44fc728438ae9a924c42227e, type: 2} @@ -6458,7 +6810,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_text: nowScore/maxScore + m_text: 0/2147483646 m_isRightToLeft: 0 m_fontAsset: {fileID: 11400000, guid: 47babadf44fc728438ae9a924c42227e, type: 2} m_sharedMaterial: {fileID: 6312708493749940865, guid: 47babadf44fc728438ae9a924c42227e, type: 2} @@ -7163,7 +7515,7 @@ MonoBehaviour: m_Text: "\u2014\u2014\u2014\u2014Main Keybinding List\u2014\u2014\u2014\u2014\n\"Space\" => (\u51C6\u5907\u5B8C\u6BD5\u65F6)\u542F\u52A8\u8BD5\u73A9\n\u201CEsc\u201D => (\u4E3B\u52A8\u6682\u505C\u65F6)\u7EE7\u7EED\u6E38\u620F\n\u201CBackSpace\u201D - => \u8FD4\u56DE\u4E3B\u754C\u9762\n\n\u2014\u2014\u2014\u2014Command + => \u8FD4\u56DE\u4E3B\u754C\u9762\n\u201CDel\u201D => \u9000\u51FA\u7A0B\u5E8F\n\n\u2014\u2014\u2014\u2014Command for Administrators\u2014\u2014\u2014\u2014\n? -\u5E2E\u52A9\n\u5DF2\u7981\u7528 gameplay_noteDetails \u97F3\u51FB\u79D2\u8868cmd\n\u5DF2\u7981\u7528 gameplay_fenglingyueying \u5F00\u53D1\u8005\u4FEE\u6539\u5668\n\u5DF2\u542F\u7528 @@ -7996,7 +8348,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 0.5882353} + m_Color: {r: 1, g: 1, b: 1, a: 0.19607843} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 @@ -8004,10 +8356,10 @@ MonoBehaviour: m_PersistentCalls: m_Calls: [] m_Sprite: {fileID: -6758692635247331641, guid: 5c4bf57c045ea4d49818477bab46bd3a, type: 3} - m_Type: 0 + m_Type: 3 m_PreserveAspect: 0 m_FillCenter: 1 - m_FillMethod: 4 + m_FillMethod: 0 m_FillAmount: 1 m_FillClockwise: 1 m_FillOrigin: 0 @@ -8508,7 +8860,7 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: -145, y: -273.6} + m_AnchoredPosition: {x: -145, y: -284.37} m_SizeDelta: {x: 1000, y: 500} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &861157999 @@ -9515,7 +9867,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: -4278035512617938032, guid: 359d6ebc01b89564185a24ecfdaecc8d, type: 3} + m_Sprite: {fileID: -8618468658663994465, guid: a8c42276e289c3f4d8df7ebc510e67a4, type: 3} m_Type: 0 m_PreserveAspect: 0 m_FillCenter: 1 @@ -10161,7 +10513,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_text: nowScore/maxScore + m_text: 0/2147483646 m_isRightToLeft: 0 m_fontAsset: {fileID: 11400000, guid: 47babadf44fc728438ae9a924c42227e, type: 2} m_sharedMaterial: {fileID: 6312708493749940865, guid: 47babadf44fc728438ae9a924c42227e, type: 2} @@ -10710,7 +11062,7 @@ MonoBehaviour: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1089378447} - m_Enabled: 0 + m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} m_Name: @@ -10834,6 +11186,7 @@ MonoBehaviour: holdNoteEndPrefabs: [] spawnOffset: 0.1 bpm: 0 + globalHitDelay: 0 judgeConfig: {fileID: 0} --- !u!61 &1090508772 BoxCollider2D: @@ -11122,7 +11475,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_text: nowScore/maxScore + m_text: 0/2147483646 m_isRightToLeft: 0 m_fontAsset: {fileID: 11400000, guid: 47babadf44fc728438ae9a924c42227e, type: 2} m_sharedMaterial: {fileID: 6312708493749940865, guid: 47babadf44fc728438ae9a924c42227e, type: 2} @@ -11410,7 +11763,7 @@ MonoBehaviour: m_PreserveAspect: 0 m_FillCenter: 1 m_FillMethod: 0 - m_FillAmount: 1 + m_FillAmount: 0 m_FillClockwise: 1 m_FillOrigin: 0 m_UseSpriteMesh: 0 @@ -11785,7 +12138,7 @@ MonoBehaviour: m_PreserveAspect: 0 m_FillCenter: 1 m_FillMethod: 0 - m_FillAmount: 1 + m_FillAmount: 0 m_FillClockwise: 1 m_FillOrigin: 0 m_UseSpriteMesh: 0 @@ -12065,7 +12418,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_text: curHP/MaxHP + m_text: 100/100 m_isRightToLeft: 0 m_fontAsset: {fileID: 11400000, guid: 47babadf44fc728438ae9a924c42227e, type: 2} m_sharedMaterial: {fileID: 6312708493749940865, guid: 47babadf44fc728438ae9a924c42227e, type: 2} @@ -12365,7 +12718,7 @@ MonoBehaviour: m_PreserveAspect: 0 m_FillCenter: 1 m_FillMethod: 0 - m_FillAmount: 1 + m_FillAmount: 0 m_FillClockwise: 1 m_FillOrigin: 0 m_UseSpriteMesh: 0 @@ -12654,10 +13007,10 @@ MonoBehaviour: m_PersistentCalls: m_Calls: [] m_Sprite: {fileID: -6758692635247331641, guid: 5c4bf57c045ea4d49818477bab46bd3a, type: 3} - m_Type: 0 + m_Type: 3 m_PreserveAspect: 0 m_FillCenter: 1 - m_FillMethod: 4 + m_FillMethod: 0 m_FillAmount: 1 m_FillClockwise: 1 m_FillOrigin: 0 @@ -12808,7 +13161,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 0.5882353} + m_Color: {r: 1, g: 1, b: 1, a: 0.19607843} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 @@ -12816,10 +13169,10 @@ MonoBehaviour: m_PersistentCalls: m_Calls: [] m_Sprite: {fileID: -6758692635247331641, guid: 5c4bf57c045ea4d49818477bab46bd3a, type: 3} - m_Type: 0 + m_Type: 3 m_PreserveAspect: 0 m_FillCenter: 1 - m_FillMethod: 4 + m_FillMethod: 0 m_FillAmount: 1 m_FillClockwise: 1 m_FillOrigin: 0 @@ -13288,7 +13641,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_text: curHP/MaxHP + m_text: 1111/1111 m_isRightToLeft: 0 m_fontAsset: {fileID: 11400000, guid: 47babadf44fc728438ae9a924c42227e, type: 2} m_sharedMaterial: {fileID: 6312708493749940865, guid: 47babadf44fc728438ae9a924c42227e, type: 2} @@ -13732,7 +14085,7 @@ MonoBehaviour: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1330006470} - m_Enabled: 0 + m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} m_Name: @@ -13847,6 +14200,7 @@ GameObject: serializedVersion: 6 m_Component: - component: {fileID: 1338578116} + - component: {fileID: 1338578117} m_Layer: 0 m_Name: ally_04 m_TagString: Untagged @@ -13876,6 +14230,33 @@ Transform: - {fileID: 1799628405} m_Father: {fileID: 1587371259} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1338578117 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1338578115} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d966ccc05a974124baf07b34117841e8, type: 3} + m_Name: + m_EditorClassIdentifier: + slotIndex: 3 + maxHP: 100 + currentHP: 100 + maxMana: 100 + currentMana: 0 + damageResistance: 0 + scoreEfficiency: 1 + attack: 0 + baseTrackScore: 1000 + greatRatio: 0.75 + goodRatio: 0.5 + missRatio: 0 + currentScore: 0 + maxTrackScore: 2147483646 + allowOverwriteFromSO: 1 --- !u!1 &1342995721 GameObject: m_ObjectHideFlags: 0 @@ -14009,10 +14390,10 @@ MonoBehaviour: m_PersistentCalls: m_Calls: [] m_Sprite: {fileID: -6758692635247331641, guid: 5c4bf57c045ea4d49818477bab46bd3a, type: 3} - m_Type: 0 - m_PreserveAspect: 0 + m_Type: 3 + m_PreserveAspect: 1 m_FillCenter: 1 - m_FillMethod: 4 + m_FillMethod: 0 m_FillAmount: 1 m_FillClockwise: 1 m_FillOrigin: 0 @@ -14540,6 +14921,7 @@ MonoBehaviour: holdNoteEndPrefabs: [] spawnOffset: 0.1 bpm: 0 + globalHitDelay: 0 judgeConfig: {fileID: 0} --- !u!61 &1370459979 BoxCollider2D: @@ -14604,6 +14986,195 @@ MonoBehaviour: yellowEffect: {fileID: 1067482187} purpleEffect: {fileID: 1646396267} blueEffect: {fileID: 628867848} +--- !u!1 &1370940901 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1370940903} + - component: {fileID: 1370940902} + m_Layer: 0 + m_Name: miss + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!82 &1370940902 +AudioSource: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1370940901} + m_Enabled: 1 + serializedVersion: 4 + OutputAudioMixerGroup: {fileID: 0} + m_audioClip: {fileID: 8300000, guid: 3dcbff412c1c9ec4d8ca931f2d51ab10, type: 3} + m_Resource: {fileID: 8300000, guid: 3dcbff412c1c9ec4d8ca931f2d51ab10, type: 3} + m_PlayOnAwake: 0 + m_Volume: 1 + m_Pitch: 1 + Loop: 0 + Mute: 0 + Spatialize: 0 + SpatializePostEffects: 0 + Priority: 128 + DopplerLevel: 1 + MinDistance: 1 + MaxDistance: 500 + Pan2D: 0 + rolloffMode: 0 + BypassEffects: 0 + BypassListenerEffects: 0 + BypassReverbZones: 0 + rolloffCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + panLevelCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + spreadCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + reverbZoneMixCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 +--- !u!4 &1370940903 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1370940901} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1374242168} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1374242166 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1374242168} + - component: {fileID: 1374242167} + m_Layer: 0 + m_Name: judgeSoundManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1374242167 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1374242166} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a7692a74982af114ca6d79307fc43676, type: 3} + m_Name: + m_EditorClassIdentifier: + perfectSource: {fileID: 213433699} + greatSource: {fileID: 400656414} + goodSource: {fileID: 2125793040} + missSource: {fileID: 1370940902} + enablePerfect: 1 + enableGreat: 1 + enableGood: 1 + enableMiss: 0 + perfectClip: {fileID: 8300000, guid: fae24344d433d714fadfa0ca8e285f7f, type: 3} + greatClip: {fileID: 8300000, guid: 36799a159f61a5e489dd0963de4bf661, type: 3} + goodClip: {fileID: 8300000, guid: bcec634c6e258c44a803ae3ca618b465, type: 3} + missClip: {fileID: 8300000, guid: 3dcbff412c1c9ec4d8ca931f2d51ab10, type: 3} +--- !u!4 &1374242168 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1374242166} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 976.3977, y: 102.51129, z: -2.2505946} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 213433700} + - {fileID: 400656415} + - {fileID: 2125793041} + - {fileID: 1370940903} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &1388483219 GameObject: m_ObjectHideFlags: 0 @@ -14846,10 +15417,10 @@ MonoBehaviour: m_PersistentCalls: m_Calls: [] m_Sprite: {fileID: -6758692635247331641, guid: 5c4bf57c045ea4d49818477bab46bd3a, type: 3} - m_Type: 0 + m_Type: 3 m_PreserveAspect: 0 m_FillCenter: 1 - m_FillMethod: 4 + m_FillMethod: 0 m_FillAmount: 1 m_FillClockwise: 1 m_FillOrigin: 0 @@ -14913,7 +15484,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 0.5882353} + m_Color: {r: 1, g: 1, b: 1, a: 0.19607843} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 @@ -14921,10 +15492,10 @@ MonoBehaviour: m_PersistentCalls: m_Calls: [] m_Sprite: {fileID: -6758692635247331641, guid: 5c4bf57c045ea4d49818477bab46bd3a, type: 3} - m_Type: 0 + m_Type: 3 m_PreserveAspect: 0 m_FillCenter: 1 - m_FillMethod: 4 + m_FillMethod: 0 m_FillAmount: 1 m_FillClockwise: 1 m_FillOrigin: 0 @@ -15253,6 +15824,7 @@ MonoBehaviour: holdNoteEndPrefabs: [] spawnOffset: 0.1 bpm: 0 + globalHitDelay: 0 judgeConfig: {fileID: 0} --- !u!61 &1486355885 BoxCollider2D: @@ -15349,6 +15921,7 @@ GameObject: serializedVersion: 6 m_Component: - component: {fileID: 1500657742} + - component: {fileID: 1500657743} m_Layer: 0 m_Name: ally_03 m_TagString: Untagged @@ -15378,6 +15951,33 @@ Transform: - {fileID: 1904135295} m_Father: {fileID: 1587371259} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1500657743 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1500657741} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d966ccc05a974124baf07b34117841e8, type: 3} + m_Name: + m_EditorClassIdentifier: + slotIndex: 2 + maxHP: 100 + currentHP: 100 + maxMana: 100 + currentMana: 100 + damageResistance: 0 + scoreEfficiency: 1 + attack: 0 + baseTrackScore: 1000 + greatRatio: 0.75 + goodRatio: 0.5 + missRatio: 0 + currentScore: 0 + maxTrackScore: 2147483646 + allowOverwriteFromSO: 1 --- !u!1 &1509558882 GameObject: m_ObjectHideFlags: 0 @@ -15775,6 +16375,7 @@ MonoBehaviour: holdNoteEndPrefabs: [] spawnOffset: 0.1 bpm: 0 + globalHitDelay: 0 judgeConfig: {fileID: 0} --- !u!61 &1572820069 BoxCollider2D: @@ -16157,6 +16758,7 @@ GameObject: serializedVersion: 6 m_Component: - component: {fileID: 1605862688} + - component: {fileID: 1605862689} m_Layer: 0 m_Name: ally_02 m_TagString: Untagged @@ -16186,6 +16788,33 @@ Transform: - {fileID: 1412993398} m_Father: {fileID: 1587371259} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1605862689 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1605862687} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d966ccc05a974124baf07b34117841e8, type: 3} + m_Name: + m_EditorClassIdentifier: + slotIndex: 1 + maxHP: 100 + currentHP: 100 + maxMana: 100 + currentMana: 0 + damageResistance: 0 + scoreEfficiency: 1 + attack: 0 + baseTrackScore: 1000 + greatRatio: 0.75 + goodRatio: 0.5 + missRatio: 0 + currentScore: 0 + maxTrackScore: 2147483646 + allowOverwriteFromSO: 1 --- !u!1 &1614078594 GameObject: m_ObjectHideFlags: 0 @@ -16236,7 +16865,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 0.5882353} + m_Color: {r: 1, g: 1, b: 1, a: 0.19607843} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 @@ -16244,10 +16873,10 @@ MonoBehaviour: m_PersistentCalls: m_Calls: [] m_Sprite: {fileID: -6758692635247331641, guid: 5c4bf57c045ea4d49818477bab46bd3a, type: 3} - m_Type: 0 + m_Type: 3 m_PreserveAspect: 0 m_FillCenter: 1 - m_FillMethod: 4 + m_FillMethod: 0 m_FillAmount: 1 m_FillClockwise: 1 m_FillOrigin: 0 @@ -16460,10 +17089,10 @@ MonoBehaviour: m_PersistentCalls: m_Calls: [] m_Sprite: {fileID: -6758692635247331641, guid: 5c4bf57c045ea4d49818477bab46bd3a, type: 3} - m_Type: 0 + m_Type: 3 m_PreserveAspect: 0 m_FillCenter: 1 - m_FillMethod: 4 + m_FillMethod: 0 m_FillAmount: 1 m_FillClockwise: 1 m_FillOrigin: 0 @@ -16947,7 +17576,7 @@ MonoBehaviour: m_PreserveAspect: 0 m_FillCenter: 1 m_FillMethod: 0 - m_FillAmount: 1 + m_FillAmount: 0 m_FillClockwise: 1 m_FillOrigin: 0 m_UseSpriteMesh: 0 @@ -17817,7 +18446,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_text: curHP/MaxHP + m_text: 100/100 m_isRightToLeft: 0 m_fontAsset: {fileID: 11400000, guid: 47babadf44fc728438ae9a924c42227e, type: 2} m_sharedMaterial: {fileID: 6312708493749940865, guid: 47babadf44fc728438ae9a924c42227e, type: 2} @@ -17905,6 +18534,7 @@ GameObject: serializedVersion: 6 m_Component: - component: {fileID: 1890740501} + - component: {fileID: 1890740502} m_Layer: 0 m_Name: ally_05 m_TagString: Untagged @@ -17934,6 +18564,33 @@ Transform: - {fileID: 775038613} m_Father: {fileID: 1587371259} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1890740502 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1890740500} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d966ccc05a974124baf07b34117841e8, type: 3} + m_Name: + m_EditorClassIdentifier: + slotIndex: 4 + maxHP: 100 + currentHP: 100 + maxMana: 100 + currentMana: 0 + damageResistance: 0 + scoreEfficiency: 1 + attack: 0 + baseTrackScore: 1000 + greatRatio: 0.75 + goodRatio: 0.5 + missRatio: 0 + currentScore: 0 + maxTrackScore: 2147483646 + allowOverwriteFromSO: 1 --- !u!1 &1904135294 GameObject: m_ObjectHideFlags: 0 @@ -18312,6 +18969,7 @@ MonoBehaviour: holdNoteEndPrefabs: [] spawnOffset: 0.1 bpm: 0 + globalHitDelay: 0 judgeConfig: {fileID: 0} --- !u!61 &1938112567 BoxCollider2D: @@ -18820,7 +19478,7 @@ MonoBehaviour: m_PreserveAspect: 0 m_FillCenter: 1 m_FillMethod: 0 - m_FillAmount: 1 + m_FillAmount: 0 m_FillClockwise: 1 m_FillOrigin: 0 m_UseSpriteMesh: 0 @@ -18895,7 +19553,7 @@ MonoBehaviour: m_PreserveAspect: 0 m_FillCenter: 1 m_FillMethod: 0 - m_FillAmount: 1 + m_FillAmount: 0 m_FillClockwise: 1 m_FillOrigin: 0 m_UseSpriteMesh: 0 @@ -19944,6 +20602,7 @@ MonoBehaviour: holdNoteEndPrefabs: [] spawnOffset: 0.1 bpm: 0 + globalHitDelay: 0 judgeConfig: {fileID: 0} --- !u!61 &2072610047 BoxCollider2D: @@ -20216,10 +20875,10 @@ MonoBehaviour: m_PersistentCalls: m_Calls: [] m_Sprite: {fileID: -6758692635247331641, guid: 5c4bf57c045ea4d49818477bab46bd3a, type: 3} - m_Type: 0 + m_Type: 3 m_PreserveAspect: 0 m_FillCenter: 1 - m_FillMethod: 4 + m_FillMethod: 0 m_FillAmount: 1 m_FillClockwise: 1 m_FillOrigin: 0 @@ -20334,6 +20993,7 @@ MonoBehaviour: holdNoteEndPrefabs: [] spawnOffset: 0.1 bpm: 0 + globalHitDelay: 0 judgeConfig: {fileID: 0} --- !u!61 &2112693515 BoxCollider2D: @@ -20557,6 +21217,135 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 2120816908} m_CullTransparentMesh: 1 +--- !u!1 &2125793039 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2125793041} + - component: {fileID: 2125793040} + m_Layer: 0 + m_Name: good + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!82 &2125793040 +AudioSource: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2125793039} + m_Enabled: 1 + serializedVersion: 4 + OutputAudioMixerGroup: {fileID: 0} + m_audioClip: {fileID: 8300000, guid: bcec634c6e258c44a803ae3ca618b465, type: 3} + m_Resource: {fileID: 8300000, guid: bcec634c6e258c44a803ae3ca618b465, type: 3} + m_PlayOnAwake: 0 + m_Volume: 1 + m_Pitch: 1 + Loop: 0 + Mute: 0 + Spatialize: 0 + SpatializePostEffects: 0 + Priority: 128 + DopplerLevel: 1 + MinDistance: 1 + MaxDistance: 500 + Pan2D: 0 + rolloffMode: 0 + BypassEffects: 0 + BypassListenerEffects: 0 + BypassReverbZones: 0 + rolloffCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + panLevelCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + spreadCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + reverbZoneMixCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 +--- !u!4 &2125793041 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2125793039} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1374242168} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &2138889110 GameObject: m_ObjectHideFlags: 0 @@ -21001,6 +21790,7 @@ MonoBehaviour: holdNoteEndPrefabs: [] spawnOffset: 0.1 bpm: 0 + globalHitDelay: 0 judgeConfig: {fileID: 0} --- !u!114 &176508373887267660 MonoBehaviour: @@ -21322,6 +22112,7 @@ MonoBehaviour: holdNoteEndPrefabs: [] spawnOffset: 0.1 bpm: 0 + globalHitDelay: 0 judgeConfig: {fileID: 0} --- !u!61 &2411783544221426195 BoxCollider2D: @@ -21774,6 +22565,7 @@ MonoBehaviour: holdNoteEndPrefabs: [] spawnOffset: 0.1 bpm: 0 + globalHitDelay: 0 judgeConfig: {fileID: 0} --- !u!114 &3721014538685850233 MonoBehaviour: @@ -22166,6 +22958,7 @@ MonoBehaviour: holdNoteEndPrefabs: [] spawnOffset: 0.1 bpm: 0 + globalHitDelay: 0 judgeConfig: {fileID: 0} --- !u!114 &4363530835118640843 MonoBehaviour: @@ -22404,6 +23197,7 @@ MonoBehaviour: holdNoteEndPrefabs: [] spawnOffset: 0.1 bpm: 0 + globalHitDelay: 0 judgeConfig: {fileID: 0} --- !u!114 &4387330747821330999 MonoBehaviour: @@ -22784,6 +23578,7 @@ MonoBehaviour: holdNoteEndPrefabs: [] spawnOffset: 0.1 bpm: 0 + globalHitDelay: 0 judgeConfig: {fileID: 0} --- !u!114 &9221553951272782130 MonoBehaviour: @@ -22845,3 +23640,4 @@ SceneRoots: - {fileID: 180857950} - {fileID: 368084896} - {fileID: 146358649} + - {fileID: 1374242168} diff --git a/Assets/scripts/Combat.meta b/Assets/scripts/Combat.meta new file mode 100644 index 00000000..7266ce77 --- /dev/null +++ b/Assets/scripts/Combat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 718e488bcee5b6a4c8eedc073040d3a3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/scripts/Combat/AllyCombatant.cs b/Assets/scripts/Combat/AllyCombatant.cs new file mode 100644 index 00000000..a07fab37 --- /dev/null +++ b/Assets/scripts/Combat/AllyCombatant.cs @@ -0,0 +1,680 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.UI; +using TMPro; + +[ExecuteAlways] +/// +/// AllyCombatant 󶨵Ѿʱ GameObjectΪ ally_01..ally_05 +/// ʵ ICombatant ӿԹ EffectSystem á +/// - teamUIController ȡ UI òͬʾѪ/ +/// - ʱ TeamCharacterDataInfo AllyHero_SO /Ȼ +/// - ʼֵΪֵʼΪ 0 +/// +public class AllyCombatant : MonoBehaviour, ICombatant +{ + public int slotIndex = 0; // 0..4 Ӧ ally_01..ally_05 + + // runtime stats + public int maxHP = 100; + public int currentHP = 100; + public int maxMana = 100; + public int currentMana = 0; + public float damageResistance = 0f; // 0..1 + public float scoreEfficiency = 1f; + + private bool isDead = false; // new: dead flag + + // add attack stat to be available at runtime + [Tooltip("ʱʹã AllyHero_SO.levelStats[0].attack 䣨ڣ")] + public int attack = 0; + + // scoring fields + [Header("Scoring")] + [Tooltip("Base score value for a perfect hit on this track")] + public int baseTrackScore = 1000; + + [Tooltip("Score multiplier for Great (e.g. 0.75)")] + public float greatRatio = 0.75f; + [Tooltip("Score multiplier for Good (e.g. 0.5)")] + public float goodRatio = 0.5f; + [Tooltip("Score multiplier for Miss (e.g. 0)")] + public float missRatio = 0f; + + [Tooltip("ɫǰ÷֣ۼӣʾ UI currentScore ı")] + public int currentScore = 0; + + [Tooltip("ޣΪ int.MaxValue - 1")] + public int maxTrackScore = int.MaxValue - 1; + + // When true, InitializeStatsFromData() will overwrite inspector values on Start. + // Set to false if you want to keep manual inspector values when entering Play mode. + public bool allowOverwriteFromSO = true; + + // UI refs (resolved from teamUIController) + private Image characterImage; + private Image healthImage; + private Image fadeHealthImage; + private Image manaImage; + private Image fadeManaImage; + private TextMeshProUGUI nameText; + private TextMeshProUGUI healthRateText; + private TextMeshProUGUI currentScoreText; + private Image hurtRedImage; + + private Coroutine fadeHealthCoroutine; + private Coroutine fadeManaCoroutine; + private List activeBuffs = new List(); + + private void Awake() + { + // ensure GameObject name matches pattern so EffectSystem can find it + gameObject.name = $"ally_0{Mathf.Clamp(slotIndex + 1, 1, 5)}"; + } + + private void Start() + { + // Resolve UI and optionally pull data from SO + ResolveUIReferences(); + if (allowOverwriteFromSO) + InitializeStatsFromData(); + + // Ensure runtime invariants + currentHP = Mathf.Clamp(currentHP, 0, Mathf.Max(1, maxHP)); + currentMana = Mathf.Clamp(currentMana, 0, Mathf.Max(1, maxMana)); + + UpdateUIImmediate(); + // Ensure score UI shows initial value + UpdateScoreUI(); + } + + // Allow editing in inspector to immediately reflect on UI (editor only) + private void OnValidate() + { + // Avoid heavy editor-only operations, but resolve UI references so inspector changes show + ResolveUIReferences(); + // Clamp values to valid ranges + if (maxHP < 1) maxHP = 1; + if (maxMana < 1) maxMana = 1; + currentHP = Mathf.Clamp(currentHP, 0, maxHP); + currentMana = Mathf.Clamp(currentMana, 0, maxMana); + + // Do not start coroutines from OnValidate - update immediately + UpdateUIImmediate(); + + // If user adjusts currentMana in inspector while in Play mode, attempt to trigger mana-full behaviors + // Guard to avoid calling TryCastOnFullMana before singletons are initialized + if (Application.isPlaying && SkillBuilder.Instance != null) + { + TryCastOnFullMana(); + } + } + + private void ResolveUIReferences() + { + // Try singleton first, fallback to scene search (works in editor) + var ui = teamUIController.Instance ?? FindObjectOfType(); + if (ui == null) return; + switch (slotIndex) + { + case 0: + characterImage = ui.teammate01_characterImage; + healthImage = ui.teammate01_healthImage; + fadeHealthImage = ui.teammate01_fadehealthImage; + manaImage = ui.teammate01_manaImage; + fadeManaImage = ui.teammate01_fadeManaImage; + nameText = ui.teammate01_nameText; + healthRateText = ui.teammate01_healthRate; + currentScoreText = ui.teammate01_current_scoreText; + hurtRedImage = ui.teammate01_hurtRedImage; + break; + case 1: + characterImage = ui.teammate02_characterImage; + healthImage = ui.teammate02_healthImage; + fadeHealthImage = ui.teammate02_fadehealthImage; + manaImage = ui.teammate02_manaImage; + fadeManaImage = ui.teammate02_fadeManaImage; + nameText = ui.teammate02_nameText; + healthRateText = ui.teammate02_healthRate; + currentScoreText = ui.teammate02_current_scoreText; + hurtRedImage = ui.teammate02_hurtRedImage; + break; + case 2: + characterImage = ui.teammate03_characterImage; + healthImage = ui.teammate03_healthImage; + fadeHealthImage = ui.teammate03_fadehealthImage; + manaImage = ui.teammate03_manaImage; + fadeManaImage = ui.teammate03_fadeManaImage; + nameText = ui.teammate03_nameText; + healthRateText = ui.teammate03_healthRate; + currentScoreText = ui.teammate03_current_scoreText; + hurtRedImage = ui.teammate03_hurtRedImage; + break; + case 3: + characterImage = ui.teammate04_characterImage; + healthImage = ui.teammate04_healthImage; + fadeHealthImage = ui.teammate04_fadehealthImage; + manaImage = ui.teammate04_manaImage; + fadeManaImage = ui.teammate04_fadeManaImage; + nameText = ui.teammate04_nameText; + healthRateText = ui.teammate04_healthRate; + currentScoreText = ui.teammate04_current_scoreText; + hurtRedImage = ui.teammate04_hurtRedImage; + break; + case 4: + characterImage = ui.teammate05_characterImage; + healthImage = ui.teammate05_healthImage; + fadeHealthImage = ui.teammate05_fadehealthImage; + manaImage = ui.teammate05_manaImage; + fadeManaImage = ui.teammate05_fadeManaImage; + nameText = ui.teammate05_nameText; + healthRateText = ui.teammate05_healthRate; + currentScoreText = ui.teammate05_current_scoreText; + hurtRedImage = ui.teammate05_hurtRedImage; + break; + } + + // If the assigned TMP field is null, attempt to resolve from the UI parent's object (teamUIController keeps objectFather references) + if (currentScoreText == null) + { + GameObject parent = null; + switch (slotIndex) + { + case 0: parent = ui.objectFather_ally01; break; + case 1: parent = ui.objectFather_ally02; break; + case 2: parent = ui.objectFather_ally03; break; + case 3: parent = ui.objectFather_ally04; break; + case 4: parent = ui.objectFather_ally05; break; + } + if (parent != null) + { + var tmp = parent.GetComponentInChildren(true); + if (tmp != null) + { + currentScoreText = tmp; + // also assign back to teamUIController so other systems can find it + switch (slotIndex) + { + case 0: ui.teammate01_current_scoreText = tmp; break; + case 1: ui.teammate02_current_scoreText = tmp; break; + case 2: ui.teammate03_current_scoreText = tmp; break; + case 3: ui.teammate04_current_scoreText = tmp; break; + case 4: ui.teammate05_current_scoreText = tmp; break; + } + Debug.Log($"[AllyCombatant] Resolved currentScoreText for slot {slotIndex+1} from parent {parent.name} -> {tmp.gameObject.name}"); + } + else + { + // legacy UnityEngine.UI.Text fallback + var legacy = parent.GetComponentInChildren(true); + if (legacy != null) + { + var go = legacy.gameObject; + var created = go.GetComponent() ?? go.AddComponent(); + created.text = legacy.text; + currentScoreText = created; + switch (slotIndex) + { + case 0: ui.teammate01_current_scoreText = created; break; + case 1: ui.teammate02_current_scoreText = created; break; + case 2: ui.teammate03_current_scoreText = created; break; + case 3: ui.teammate04_current_scoreText = created; break; + case 4: ui.teammate05_current_scoreText = created; break; + } + Debug.LogWarning($"[AllyCombatant] Found legacy Text for slot {slotIndex+1} under {parent.name}. Added/used TMP component on {go.name} and copied text."); + } + } + } + } + } + + private void InitializeStatsFromData() + { + // Try TeamCharacterDataInfo first + var arr = teamUIController.Instance?.GetCurrentAllySOs(); + if (arr != null && slotIndex >= 0 && slotIndex < arr.Length) + { + var so = arr[slotIndex]; + if (so != null) + { + // TeamCharacterDataInfo has limited fields; use CharacterMaxHealth if present + if (so.CharacterMaxHealth > 0) + { + maxHP = so.CharacterMaxHealth; + } + if (!string.IsNullOrEmpty(so.CharacterName) && nameText != null) + { + nameText.text = so.CharacterName; + } + if (characterImage != null && so.CharacterImage_gameplay != null) + { + characterImage.sprite = so.CharacterImage_gameplay.sprite; + } + } + } + + // If more detailed info exists in AllyHero_SO, try to load by ally ID + int id = -1; + if (teamUIController.Instance != null && teamUIController.Instance.allySlotIds != null && slotIndex < teamUIController.Instance.allySlotIds.Count) + id = teamUIController.Instance.allySlotIds[slotIndex]; + + if (id > 0) + { + var all = Resources.LoadAll(""); + foreach (var a in all) + { + if (a != null && a.ally_heroID == id) + { + // pick effective level based on current EXP if available + if (a.levelStats != null && a.levelStats.Count > 0) + { + var eff = a.GetEffectiveLevelForCurrentEXP(); + if (eff != null) + { + maxHP = eff.maxHP; + maxMana = eff.maxMana; + damageResistance = eff.damageResistance; + scoreEfficiency = eff.scoreEfficiency; + attack = eff.attack; // populate attack from SO effective level + } + else + { + var lvl = a.levelStats[0]; + maxHP = lvl.maxHP; + maxMana = lvl.maxMana; + damageResistance = lvl.damageResistance; + scoreEfficiency = lvl.scoreEfficiency; + attack = lvl.attack; + } + } + + if (nameText != null) nameText.text = a.ally_heroName; + if (characterImage != null && a.ally_heroProfile != null) characterImage.sprite = a.ally_heroProfile; + break; + } + } + } + } + + // Scoring API + public void AddScoreForJudge(string judge) + { + int add = 0; + switch (judge) + { + case "Perfect": + add = baseTrackScore; + break; + case "Great": + add = Mathf.FloorToInt(baseTrackScore * greatRatio); + break; + case "Good": + add = Mathf.FloorToInt(baseTrackScore * goodRatio); + break; + case "Miss": + add = Mathf.FloorToInt(baseTrackScore * missRatio); + break; + default: + add = 0; + break; + } + // apply scoreEfficiency or other modifiers here + add = Mathf.FloorToInt(add * scoreEfficiency); + + currentScore = Mathf.Clamp(currentScore + add, 0, maxTrackScore); + UpdateScoreUI(); + // update global total + ScoreManager.Instance?.RecalculateTotal(); + } + + // Add an arbitrary score delta directly (used by skills to modify single judge or grant/penalize score) + public void AddScoreDirect(int delta) + { + currentScore = Mathf.Clamp(currentScore + delta, 0, maxTrackScore); + UpdateScoreUI(); + ScoreManager.Instance?.RecalculateTotal(); + } + + private void UpdateScoreUI() + { + string value = $"{currentScore}/{maxTrackScore}"; + if (currentScoreText != null) + { + currentScoreText.text = value; + Debug.Log($"[AllyCombatant] Updated slot {slotIndex+1} score UI -> {value} (target {currentScoreText.gameObject.name})"); + return; + } + + // As a fallback, try to write directly to teamUIController.Instance fields if available + var ui = teamUIController.Instance; + if (ui != null) + { + switch (slotIndex) + { + case 0: + if (ui.teammate01_current_scoreText != null) { ui.teammate01_current_scoreText.text = value; Debug.Log($"[AllyCombatant] Fallback wrote to ui.teammate01_current_scoreText: {value}"); } + break; + case 1: + if (ui.teammate02_current_scoreText != null) { ui.teammate02_current_scoreText.text = value; Debug.Log($"[AllyCombatant] Fallback wrote to ui.teammate02_current_scoreText: {value}"); } + break; + case 2: + if (ui.teammate03_current_scoreText != null) { ui.teammate03_current_scoreText.text = value; Debug.Log($"[AllyCombatant] Fallback wrote to ui.teammate03_current_scoreText: {value}"); } + break; + case 3: + if (ui.teammate04_current_scoreText != null) { ui.teammate04_current_scoreText.text = value; Debug.Log($"[AllyCombatant] Fallback wrote to ui.teammate04_current_scoreText: {value}"); } + break; + case 4: + if (ui.teammate05_current_scoreText != null) { ui.teammate05_current_scoreText.text = value; Debug.Log($"[AllyCombatant] Fallback wrote to ui.teammate05_current_scoreText: {value}"); } + break; + } + } + } + + // Public setters that update UI and optionally animate fade bars + public void SetCurrentHP(int hp, bool animateFade = true) + { + if (isDead) return; // dead characters cannot change HP + int old = currentHP; + currentHP = Mathf.Clamp(hp, 0, maxHP); + if (currentHP <= 0) isDead = true; + UpdateHealthVisuals(old, animateFade); + } + + public void ModifyHP(int delta, bool animateFade = true) + { + if (isDead && delta > 0) + { + // cannot heal a dead unit + return; + } + SetCurrentHP(currentHP + delta, animateFade); + } + + public void SetMaxHP(int newMax, bool keepCurrentRatio = true) + { + if (newMax < 1) newMax = 1; + float ratio = maxHP > 0 ? (float)currentHP / maxHP : 1f; + maxHP = newMax; + if (keepCurrentRatio) + currentHP = Mathf.Clamp(Mathf.RoundToInt(ratio * maxHP), 0, maxHP); + else + currentHP = Mathf.Clamp(currentHP, 0, maxHP); + UpdateUIImmediate(); + } + + public void SetCurrentMana(int mana, bool animateFade = true) + { + if (isDead) return; // dead characters cannot change mana + int old = currentMana; + currentMana = Mathf.Clamp(mana, 0, maxMana); + UpdateManaVisuals(old, animateFade); + TryCastOnFullMana(); + } + + public void ModifyMana(int delta, bool animateFade = true) + { + if (isDead && delta > 0) + { + // dead units cannot gain mana + return; + } + SetCurrentMana(currentMana + delta, animateFade); + } + + public void SetMaxMana(int newMax, bool keepCurrentRatio = true) + { + if (newMax < 1) newMax = 1; + float ratio = maxMana > 0 ? (float)currentMana / maxMana : 1f; + maxMana = newMax; + if (keepCurrentRatio) + currentMana = Mathf.Clamp(Mathf.RoundToInt(ratio * maxMana), 0, maxMana); + else + currentMana = Mathf.Clamp(currentMana, 0, maxMana); + UpdateUIImmediate(); + } + + private void UpdateHealthVisuals(int oldHP, bool animateFade) + { + // main bar should snap quickly to new value, while fade bar lerps towards it + if (healthImage != null) + { + float newFill = maxHP > 0 ? (float)currentHP / maxHP : 0f; + // snap main bar quickly for visual pop + healthImage.fillAmount = Mathf.MoveTowards(healthImage.fillAmount, newFill, 1f); + } + + if (healthRateText != null) + healthRateText.text = $"{currentHP}/{maxHP}"; + + if (fadeHealthCoroutine != null) StopCoroutine(fadeHealthCoroutine); + if (fadeHealthImage != null) + { + float target = healthImage != null ? healthImage.fillAmount : maxHP > 0 ? (float)currentHP / maxHP : 0f; + if (animateFade && Application.isPlaying) + fadeHealthCoroutine = StartCoroutine(FadeHealthCoroutine(target)); + else + fadeHealthImage.fillAmount = target; + } + + // if HP decreased, show hurt flash; if dead, keep hurt overlay visible + if (currentHP < oldHP && hurtRedImage != null && Application.isPlaying) + { + StopCoroutine("HurtFlash"); + StartCoroutine(HurtFlash()); + } + if (isDead && hurtRedImage != null) + { + Color c = hurtRedImage.color; + c.a = 1f; + hurtRedImage.color = c; // keep overlay visible when dead + } + } + + private void UpdateManaVisuals(int oldMana, bool animateFade) + { + // main bar snaps, fade bar lerps to new value for visual effect + if (manaImage != null) + { + float newFill = maxMana > 0 ? (float)currentMana / maxMana : 0f; + manaImage.fillAmount = Mathf.MoveTowards(manaImage.fillAmount, newFill, 1f); + } + + if (fadeManaCoroutine != null) StopCoroutine(fadeManaCoroutine); + if (fadeManaImage != null) + { + float target = manaImage != null ? manaImage.fillAmount : maxMana > 0 ? (float)currentMana / maxMana : 0f; + if (animateFade && Application.isPlaying) + fadeManaCoroutine = StartCoroutine(FadeManaCoroutine(target)); + else + fadeManaImage.fillAmount = target; + } + } + + private void UpdateUIImmediate() + { + if (healthImage != null) + { + healthImage.fillAmount = maxHP > 0 ? (float)currentHP / maxHP : 0f; + } + if (fadeHealthImage != null) + { + // keep fade bar equal to main bar immediately + fadeHealthImage.fillAmount = healthImage != null ? healthImage.fillAmount : maxHP > 0 ? (float)currentHP / maxHP : 0f; + } + if (manaImage != null) + { + manaImage.fillAmount = maxMana > 0 ? (float)currentMana / maxMana : 0f; + } + if (fadeManaImage != null) + { + fadeManaImage.fillAmount = manaImage != null ? manaImage.fillAmount : maxMana > 0 ? (float)currentMana / maxMana : 0f; + } + if (healthRateText != null) + { + healthRateText.text = $"{currentHP}/{maxHP}"; + } + } + + private IEnumerator FadeHealthCoroutine(float targetFill) + { + if (fadeHealthImage == null) yield break; + float start = fadeHealthImage.fillAmount; + float duration = 0.6f; + float t = 0f; + while (t < duration) + { + t += Time.deltaTime; + fadeHealthImage.fillAmount = Mathf.Lerp(start, targetFill, t / duration); + yield return null; + } + fadeHealthImage.fillAmount = targetFill; + } + + private IEnumerator FadeManaCoroutine(float targetFill) + { + if (fadeManaImage == null) yield break; + float start = fadeManaImage.fillAmount; + float duration = 0.4f; + float t = 0f; + while (t < duration) + { + t += Time.deltaTime; + fadeManaImage.fillAmount = Mathf.Lerp(start, targetFill, t / duration); + yield return null; + } + fadeManaImage.fillAmount = targetFill; + } + + public void ReceiveDamage(float amount, GameObject source) + { + float effective = amount * (1f - damageResistance); + int delta = Mathf.CeilToInt(effective); + ModifyHP(-delta, true); + } + + private IEnumerator HurtFlash() + { + if (hurtRedImage == null) yield break; + Color c = hurtRedImage.color; + c.a = 1f; + hurtRedImage.color = c; + // when injured, remain visible a bit longer; if dead, keep it on + if (isDead) + { + yield break; + } + yield return new WaitForSeconds(0.2f); + float dur = 0.4f; + float t = 0f; + while (t < dur) + { + t += Time.deltaTime; + c.a = Mathf.Lerp(1f, 0f, t / dur); + hurtRedImage.color = c; + yield return null; + } + c.a = 0f; + hurtRedImage.color = c; + } + + public void ReceiveHeal(float amount, GameObject source) + { + int delta = Mathf.CeilToInt(amount); + ModifyHP(delta, true); + } + + public void ApplyBuff(Buff buff, GameObject source) + { + if (buff == null) return; + activeBuffs.Add(buff); + // simple immediate apply: multiply stats + if (buff.attackMultiplier != 1f) { attack = Mathf.RoundToInt(attack * buff.attackMultiplier); } + if (buff.scoreMultiplier != 1f) scoreEfficiency *= buff.scoreMultiplier; + // UI/visual could be added + } + + public void RemoveBuff(string buffId) + { + var b = activeBuffs.Find(x => x.buffId == buffId); + if (b != null) + { + activeBuffs.Remove(b); + if (b.scoreMultiplier != 1f) scoreEfficiency /= b.scoreMultiplier; + // cannot easily restore attack without storing original; keep simple + } + } + + private void TryCastOnFullMana() + { + if (currentMana >= maxMana && Application.isPlaying) + { + // Ensure SkillBuilder singleton exists before attempting to cast. + if (SkillBuilder.Instance == null) + { + Debug.LogWarning($"[AllyCombatant] Slot {slotIndex + 1} cannot cast right now: SkillBuilder.Instance is null. Will not attempt cast."); + return; + } + + int prevMana = currentMana; + // Attempt to cast primary skill configured in SO via SkillBuilder + CastSkill(); + // Reset mana after casting + currentMana = 0; + // Update visuals using previous mana as old value so fade works + UpdateManaVisuals(prevMana, true); + } + } + + private void CastSkill() + { + // Use SkillBuilder to invoke the primary skill defined in the AllyHero_SO for this slot + if (SkillBuilder.Instance == null) + { + Debug.LogWarning($"[AllyCombatant] Slot {slotIndex + 1} cannot cast: SkillBuilder.Instance is null."); + return; + } + + var so = SkillBuilder.Instance.GetAllyHeroSOBySlot(slotIndex); + if (so == null) + { + // Can't locate SO for this slot; attempt best-effort: call UsePrimarySkillForSlot which will log details + Debug.LogWarning($"[AllyCombatant] Slot {slotIndex + 1}: AllyHero_SO not found for slot. Falling back to UsePrimarySkillForSlot."); + SkillBuilder.Instance.UsePrimarySkillForSlot(slotIndex, -1f, null); + return; + } + + var def = so.GetPrimarySkill(); + if (def == null) + { + Debug.LogWarning($"[AllyCombatant] Slot {slotIndex + 1} cannot cast: primary skill not set in SO."); + return; + } + + // Only auto-cast here if the skill's trigger condition matches ManaFull + if (def.triggerCondition == SkillDefinition.SkillTrigger.OnManaFull) + { + // Use the SkillDefinition API to ensure selector/resolution/operateDirectly are respected + SkillBuilder.Instance.UseSkillDefinition(def, slotIndex, -1f, null); + Debug.Log($"[AllyCombatant] Slot {slotIndex + 1} cast primary skill '{def.skillId}' due to ManaFull."); + } + else + { + Debug.Log($"[AllyCombatant] Slot {slotIndex + 1} primary skill '{def.skillId}' not set to trigger on ManaFull (trigger={def.triggerCondition}); skipping cast."); + } + } + + public void TriggerOnManaFull() + { + if (currentMana >= maxMana) + { + TryCastOnFullMana(); + } + } + + [ContextMenu("Test Fill Mana")] + private void TestFillMana() + { + SetCurrentMana(maxMana, true); + } +} diff --git a/Assets/scripts/Combat/AllyCombatant.cs.meta b/Assets/scripts/Combat/AllyCombatant.cs.meta new file mode 100644 index 00000000..1f3722d6 --- /dev/null +++ b/Assets/scripts/Combat/AllyCombatant.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d966ccc05a974124baf07b34117841e8 \ No newline at end of file diff --git a/Assets/scripts/Combat/Buff.cs b/Assets/scripts/Combat/Buff.cs new file mode 100644 index 00000000..d406c412 --- /dev/null +++ b/Assets/scripts/Combat/Buff.cs @@ -0,0 +1,32 @@ +using System; +using UnityEngine; + +[Serializable] +public class Buff +{ + // Unique identifier for this buff instance + public string buffId; + + // Duration in seconds + public float duration = 0f; + + // Optional human-readable description/type + public string description = string.Empty; + + // Multipliers / modifiers that systems may use + public float attackMultiplier = 1f; // multiply outgoing attack + public float scoreMultiplier = 1f; // multiply scoring efficiency + public float healReceivedMultiplier = 1f; // multiply heals received + + // Flat modifications (if needed) + public int flatHP = 0; + public int flatMana = 0; + + // Convenience constructor + public Buff() { buffId = Guid.NewGuid().ToString(); } + + public Buff(string id) + { + buffId = id; + } +} \ No newline at end of file diff --git a/Assets/scripts/Combat/Buff.cs.meta b/Assets/scripts/Combat/Buff.cs.meta new file mode 100644 index 00000000..635697d8 --- /dev/null +++ b/Assets/scripts/Combat/Buff.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 25fcea503b24fdc4e89adbc8dd2bd409 \ No newline at end of file diff --git a/Assets/scripts/Combat/CombatCommon.cs b/Assets/scripts/Combat/CombatCommon.cs new file mode 100644 index 00000000..7c33e5d3 --- /dev/null +++ b/Assets/scripts/Combat/CombatCommon.cs @@ -0,0 +1,37 @@ +using System; +using UnityEngine; + +// Shared types used by combat/effect/skill systems +public enum Selector +{ + Self, + AllAllies, + AllAlliesExceptSelf, + AdjacentAllies, + CurrentEnemies, + AllEntities +} + +public enum EffectType +{ + DamageSingleEnemy, + DamageOverTimeEnemy, + HealSingleSelf, + HealOverTimeSelf, + HealGroupSingle, + HealGroupOverTime, + BuffDuration, + DebuffDuration, + IncreaseManaOverTime, + ReduceEnemyHealOverTime, + ScoreMultiplier, + AddScore +} + +public interface ICombatant +{ + void ReceiveDamage(float amount, GameObject source); + void ReceiveHeal(float amount, GameObject source); + void ApplyBuff(Buff buff, GameObject source); + void RemoveBuff(string buffId); +} diff --git a/Assets/scripts/Combat/CombatCommon.cs.meta b/Assets/scripts/Combat/CombatCommon.cs.meta new file mode 100644 index 00000000..0bc53797 --- /dev/null +++ b/Assets/scripts/Combat/CombatCommon.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: b949a850de06357409a6342e542319b2 \ No newline at end of file diff --git a/Assets/scripts/Combat/EffectSystem.cs b/Assets/scripts/Combat/EffectSystem.cs new file mode 100644 index 00000000..a545209b --- /dev/null +++ b/Assets/scripts/Combat/EffectSystem.cs @@ -0,0 +1,453 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +/// +/// EffectSystem ṩЧͳһַӿڡ +/// - ѡΧSelectorĿ꼯ϣԼȫѾԼѾѾϵˡˣ +/// - ЧͣEffectType˼ʱ/˺///ȡ +/// +/// ĿʵӦʵ ICombatant ӿԱ EffectSystem ܵͳһ˺//ȣûʵ֣־ѡ +/// +/// ýűΪܣ弼ãֻṩ ApplyEffect(...) ȷűá +/// +public class EffectSystem : MonoBehaviour +{ + public static EffectSystem Instance { get; private set; } + + private void Awake() + { + if (Instance == null) Instance = this; + else Destroy(gameObject); + } + + /// + /// ApplyEffect: ָѡΧĿӦЧ + /// - selector: Ŀѡ + /// - effectType: Чͣʱ/ȣ + /// - amount: ֵ˺Чǿȣ + /// - duration: ʱ䣨ԳЧ Buff/Debuff ЧʱЧΪ 0 + /// - source: ߣ Self/AlliesExceptSelf жϻ¼ + /// - specificTarget: selector Ϊ CurrentEnemies ָֻʱɴĿ + /// - tickInterval: Ч tick 룩Ĭ 1 + /// + public void ApplyEffect(Selector selector, EffectType effectType, float amount, float duration = 0f, GameObject source = null, GameObject specificTarget = null, float tickInterval = 1f) + { + List targets = ResolveTargets(selector, source, specificTarget); + + if (targets == null || targets.Count == 0) + { + Debug.LogWarning($"[EffectSystem] No targets resolved for selector={selector}"); + return; + } + + switch (effectType) + { + case EffectType.DamageSingleEnemy: + // apply instantaneous damage to first applicable enemy in targets + if (targets.Count > 0) + ApplyInstantDamage(targets[0], amount, source); + break; + + case EffectType.DamageOverTimeEnemy: + foreach (var t in targets) + StartCoroutine(ApplyDamageOverTimeCoroutine(t, amount, duration, tickInterval, source)); + break; + + case EffectType.HealSingleSelf: + if (targets.Count > 0) + ApplyInstantHeal(targets[0], amount, source); + break; + + case EffectType.HealOverTimeSelf: + foreach (var t in targets) + StartCoroutine(ApplyHealOverTimeCoroutine(t, amount, duration, tickInterval, source)); + break; + + case EffectType.HealGroupSingle: + foreach (var t in targets) + ApplyInstantHeal(t, amount, source); + break; + + case EffectType.HealGroupOverTime: + foreach (var t in targets) + StartCoroutine(ApplyHealOverTimeCoroutine(t, amount, duration, tickInterval, source)); + break; + + case EffectType.BuffDuration: + // create a simple buff with id+duration; additional fields can be filled by caller when using Buff instances directly + Buff buff = new Buff { buffId = Guid.NewGuid().ToString(), duration = duration }; + foreach (var t in targets) + StartCoroutine(ApplyTimedBuffCoroutine(t, buff, source)); + break; + + case EffectType.DebuffDuration: + Buff debuff = new Buff { buffId = Guid.NewGuid().ToString(), duration = duration }; + foreach (var t in targets) + StartCoroutine(ApplyTimedDebuffCoroutine(t, debuff, source)); + break; + + case EffectType.IncreaseManaOverTime: + foreach (var t in targets) + StartCoroutine(ApplyIncreaseManaOverTimeCoroutine(t, amount, duration, tickInterval, source)); + break; + + case EffectType.ReduceEnemyHealOverTime: + // create a debuff that marks heal reduction in its description; enforcement depends on ICombatant.ReceiveHeal implementation + Buff healReductionDebuff = new Buff { buffId = Guid.NewGuid().ToString(), duration = duration, description = "ReduceHeal" }; + foreach (var t in targets) + StartCoroutine(ApplyTimedDebuffCoroutine(t, healReductionDebuff, source)); + break; + + case EffectType.ScoreMultiplier: + // create a buff that multiplies scoring efficiency + Buff scoreBuff = new Buff { buffId = Guid.NewGuid().ToString(), duration = duration, scoreMultiplier = amount }; + foreach (var t in targets) + StartCoroutine(ApplyTimedBuffCoroutine(t, scoreBuff, source)); + break; + + case EffectType.AddScore: + // amount interpreted as integer delta to add immediately to ally tracks + foreach (var t in targets) + { + if (t == null) continue; + var ally = t.GetComponent(); + if (ally != null) + { + ally.AddScoreDirect(Mathf.CeilToInt(amount)); + } + else + { + // if target does not have AllyCombatant, try to find ICombatant and warn + var ic = t.GetComponent(); + if (ic != null) + { + Debug.LogWarning($"[EffectSystem] AddScore: target {t.name} implements ICombatant but is not AllyCombatant; cannot AddScoreDirect"); + } + else + { + Debug.LogWarning($"[EffectSystem] AddScore: target {t.name} does not support AddScore"); + } + } + } + break; + + default: + Debug.LogWarning($"[EffectSystem] Unhandled EffectType {effectType}"); + break; + } + } + + // Resolve targets based on selector. Tries several strategies: + // - If selector == Self -> source only + // - AllAllies / AllAlliesExceptSelf -> find GameObjects named ally_01..ally_05, and also fall back to objects with tag "Ally" + // - AdjacentAllies -> use AllyCombatant.slotIndex (from source) and teamUIController helpers + // - CurrentEnemies -> specificTarget if provided else all objects with tag "Enemy" + // - AllEntities -> find all enemies + allies + private List ResolveTargets(Selector selector, GameObject source, GameObject specificTarget) + { + List list = new List(); + + switch (selector) + { + case Selector.Self: + if (source != null) list.Add(source); + break; + + case Selector.AllAllies: + list.AddRange(FindAllAllies()); + break; + + case Selector.AllAlliesExceptSelf: + list.AddRange(FindAllAllies()); + if (source != null) + list.RemoveAll(g => g == null || g == source || g.gameObject == source.gameObject); + list.RemoveAll(g => g == null || g == source); + break; + + case Selector.AdjacentAllies: + // find adjacent allies of the source (left/right). Use teamUIController if available. + if (source == null) + { + Debug.LogWarning("[EffectSystem] AdjacentAllies selector requires a non-null source GameObject"); + break; + } + + // try to use AllyCombatant.slotIndex if present + var allyComp = source.GetComponent(); + int slotIndex = -1; + if (allyComp != null) + { + slotIndex = allyComp.slotIndex; + } + else + { + // try to parse name like "ally_01" + var n = source.name; + for (int i = 1; i <= 5; i++) + { + if (n.Contains($"ally_0{i}")) { slotIndex = i - 1; break; } + } + } + + if (slotIndex >= 0) + { + var ui = teamUIController.Instance; + if (ui != null) + { + try + { + var adj = ui.GetAdjacentAllyIndices(slotIndex); + foreach (var idx in adj) + { + var go = ui.GetAllyObjectBySlot(idx); + if (go != null) list.Add(go); + else + { + var named = GameObject.Find($"ally_0{idx + 1}"); + if (named != null) list.Add(named); + } + } + } + catch (Exception ex) + { + Debug.LogWarning($"[EffectSystem] teamUIController does not expose adjacent helpers: {ex.Message}"); + int left = slotIndex - 1; + int right = slotIndex + 1; + if (left >= 0) + { + var g = GameObject.Find($"ally_0{left + 1}"); if (g != null) list.Add(g); + } + if (right <= 4) + { + var g = GameObject.Find($"ally_0{right + 1}"); if (g != null) list.Add(g); + } + } + } + else + { + int left = slotIndex - 1; + int right = slotIndex + 1; + if (left >= 0) + { + var g = GameObject.Find($"ally_0{left + 1}"); if (g != null) list.Add(g); + } + if (right <= 4) + { + var g = GameObject.Find($"ally_0{right + 1}"); if (g != null) list.Add(g); + } + } + } + else + { + Debug.LogWarning("[EffectSystem] Could not determine slot index for source when resolving AdjacentAllies"); + } + + break; + + case Selector.CurrentEnemies: + if (specificTarget != null) list.Add(specificTarget); + else list.AddRange(FindAllEnemies()); + break; + + case Selector.AllEntities: + list.AddRange(FindAllAllies()); + list.AddRange(FindAllEnemies()); + break; + } + + // remove nulls and duplicates + list.RemoveAll(x => x == null); + var uniq = new List(); + foreach (var g in list) + if (!uniq.Contains(g)) uniq.Add(g); + return uniq; + } + + private IEnumerable FindAllAllies() + { + List allies = new List(); + // try names ally_01..ally_05 + for (int i = 1; i <= 5; i++) + { + string name = $"ally_0{i}"; // ally_01..ally_05 + var go = GameObject.Find(name); + if (go != null) allies.Add(go); + } + + // also include objects tagged "Ally" + try + { + var tagged = GameObject.FindGameObjectsWithTag("Ally"); + foreach (var g in tagged) + if (!allies.Contains(g)) allies.Add(g); + } + catch { /* tag might not exist; ignore */ } + + return allies; + } + + private IEnumerable FindAllEnemies() + { + List enemies = new List(); + // try to find object named "thisEnemy" (single) or many by tag + var single = GameObject.Find("thisEnemy"); + if (single != null) enemies.Add(single); + + try + { + var tagged = GameObject.FindGameObjectsWithTag("Enemy"); + foreach (var g in tagged) + if (!enemies.Contains(g)) enemies.Add(g); + } + catch { } + + return enemies; + } + + #region Instant / OverTime Helpers + private void ApplyInstantDamage(GameObject target, float amount, GameObject source) + { + if (target == null) return; + var comp = target.GetComponent(); + if (comp != null) + { + comp.ReceiveDamage(amount, source); + } + else + { + Debug.LogWarning($"[EffectSystem] Target {target.name} does not implement ICombatant -> cannot apply damage"); + } + } + + private void ApplyInstantHeal(GameObject target, float amount, GameObject source) + { + if (target == null) return; + var comp = target.GetComponent(); + if (comp != null) + { + comp.ReceiveHeal(amount, source); + } + else + { + Debug.LogWarning($"[EffectSystem] Target {target.name} does not implement ICombatant -> cannot apply heal"); + } + } + + private IEnumerator ApplyDamageOverTimeCoroutine(GameObject target, float totalAmount, float duration, float tickInterval, GameObject source) + { + if (target == null) yield break; + var comp = target.GetComponent(); + if (comp == null) + { + Debug.LogWarning($"[EffectSystem] Target {target.name} does not implement ICombatant -> cannot apply DOT"); + yield break; + } + + if (duration <= 0f) + { + comp.ReceiveDamage(totalAmount, source); + yield break; + } + + int ticks = Mathf.Max(1, Mathf.CeilToInt(duration / tickInterval)); + float perTick = totalAmount / ticks; + float elapsed = 0f; + while (elapsed < duration) + { + comp.ReceiveDamage(perTick, source); + yield return new WaitForSeconds(tickInterval); + elapsed += tickInterval; + } + } + + private IEnumerator ApplyHealOverTimeCoroutine(GameObject target, float totalAmount, float duration, float tickInterval, GameObject source) + { + if (target == null) yield break; + var comp = target.GetComponent(); + if (comp == null) + { + Debug.LogWarning($"[EffectSystem] Target {target.name} does not implement ICombatant -> cannot apply HOT"); + yield break; + } + + if (duration <= 0f) + { + comp.ReceiveHeal(totalAmount, source); + yield break; + } + + int ticks = Mathf.Max(1, Mathf.CeilToInt(duration / tickInterval)); + float perTick = totalAmount / ticks; + float elapsed = 0f; + while (elapsed < duration) + { + comp.ReceiveHeal(perTick, source); + yield return new WaitForSeconds(tickInterval); + elapsed += tickInterval; + } + } + + private IEnumerator ApplyIncreaseManaOverTimeCoroutine(GameObject target, float totalAmount, float duration, float tickInterval, GameObject source) + { + if (target == null) yield break; + var comp = target.GetComponent(); + // If target implements a method to add mana, call it; otherwise try to find AllyCombatant component + var ally = target.GetComponent(); + if (ally == null && comp == null) + { + Debug.LogWarning($"[EffectSystem] Target {target.name} cannot receive mana -> no AllyCombatant or ICombatant found"); + yield break; + } + + if (duration <= 0f) + { + // immediate add totalAmount to mana if ally present + if (ally != null) ally.ModifyMana(Mathf.CeilToInt(totalAmount), true); + yield break; + } + + int ticks = Mathf.Max(1, Mathf.CeilToInt(duration / tickInterval)); + float perTick = totalAmount / ticks; + float elapsed = 0f; + while (elapsed < duration) + { + if (ally != null) ally.ModifyMana(Mathf.CeilToInt(perTick), true); + yield return new WaitForSeconds(tickInterval); + elapsed += tickInterval; + } + } + + private IEnumerator ApplyTimedBuffCoroutine(GameObject target, Buff buff, GameObject source) + { + if (target == null) yield break; + var comp = target.GetComponent(); + if (comp == null) + { + Debug.LogWarning($"[EffectSystem] Target {target.name} does not implement ICombatant -> cannot apply Buff"); + yield break; + } + + comp.ApplyBuff(buff, source); + yield return new WaitForSeconds(buff.duration); + comp.RemoveBuff(buff.buffId); + } + + private IEnumerator ApplyTimedDebuffCoroutine(GameObject target, Buff debuff, GameObject source) + { + // For now debuff is same as buff but may be handled differently by ICombatant implementation + if (target == null) yield break; + var comp = target.GetComponent(); + if (comp == null) + { + Debug.LogWarning($"[EffectSystem] Target {target.name} does not implement ICombatant -> cannot apply Debuff"); + yield break; + } + + comp.ApplyBuff(debuff, source); + yield return new WaitForSeconds(debuff.duration); + comp.RemoveBuff(debuff.buffId); + } + #endregion +} diff --git a/Assets/scripts/Combat/EffectSystem.cs.meta b/Assets/scripts/Combat/EffectSystem.cs.meta new file mode 100644 index 00000000..3e79781a --- /dev/null +++ b/Assets/scripts/Combat/EffectSystem.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ac6185c2505b3ec47af065d12a0dd2b6 \ No newline at end of file diff --git a/Assets/scripts/Combat/ScoreManager.cs b/Assets/scripts/Combat/ScoreManager.cs new file mode 100644 index 00000000..a74740ca --- /dev/null +++ b/Assets/scripts/Combat/ScoreManager.cs @@ -0,0 +1,127 @@ +using UnityEngine; +using TMPro; +using UnityEngine.UI; + +public class ScoreManager : MonoBehaviour +{ + public static ScoreManager Instance { get; private set; } + + public int totalScore = 0; + + private void Awake() + { + if (Instance == null) Instance = this; + else Destroy(gameObject); + } + + public void RecalculateTotal() + { + int sum = 0; + int[] currents = new int[5]; + int[] maxes = new int[5]; + for (int i = 1; i <= 5; i++) + { + var go = GameObject.Find($"ally_0{i}"); + if (go == null) { currents[i - 1] = 0; maxes[i - 1] = 0; continue; } + var ally = go.GetComponent(); + if (ally != null) + { + currents[i - 1] = ally.currentScore; + maxes[i - 1] = ally.maxTrackScore; + } + else + { + currents[i - 1] = 0; + maxes[i - 1] = 0; + } + + sum += currents[i - 1]; + } + totalScore = sum; + // update UI if available + if (teamUIController.Instance != null) + { + var ui = teamUIController.Instance; + + // helper lambda to set text on TMP or legacy Text under a parent fallback + void SetScoreText(TextMeshProUGUI assignedTmp, GameObject parent, int cur, int max, string slotName) + { + string value = cur + "/" + max; + if (assignedTmp != null) + { + assignedTmp.text = value; + Debug.Log($"[ScoreManager] Wrote to assigned TMP for {slotName}: '{value}' -> {assignedTmp.gameObject.name}"); + return; + } + // try find TMP in parent + if (parent != null) + { + var tmp = parent.GetComponentInChildren(true); + if (tmp != null) + { + tmp.text = value; + Debug.Log($"[ScoreManager] Wrote to TMP in parent {parent.name} for {slotName}: '{value}' -> {tmp.gameObject.name}"); + return; + } + var legacy = parent.GetComponentInChildren(true); + if (legacy != null) + { + legacy.text = value; + Debug.Log($"[ScoreManager] Wrote to legacy Text in parent {parent.name} for {slotName}: '{value}' -> {legacy.gameObject.name}"); + return; + } + } + Debug.LogWarning($"[ScoreManager] Could not find UI to write score for {slotName}. assignedTmp is null and parent '{parent?.name}' has no TMP/Text children."); + } + + // Update each slot: use the explicit TMP fields if set; otherwise try parent object fields + SetScoreText(ui.teammate01_current_scoreText, ui.objectFather_ally01, currents[0], maxes[0], "teammate01"); + SetScoreText(ui.teammate02_current_scoreText, ui.objectFather_ally02, currents[1], maxes[1], "teammate02"); + SetScoreText(ui.teammate03_current_scoreText, ui.objectFather_ally03, currents[2], maxes[2], "teammate03"); + SetScoreText(ui.teammate04_current_scoreText, ui.objectFather_ally04, currents[3], maxes[3], "teammate04"); + SetScoreText(ui.teammate05_current_scoreText, ui.objectFather_ally05, currents[4], maxes[4], "teammate05"); + + // update total score (try TMP first, then legacy Text) + if (ui.currentTotalScore != null) + { + var go = ui.currentTotalScore.gameObject; + if (go != null) + { + var tmpComp = go.GetComponent(); + if (tmpComp != null) + { + tmpComp.text = totalScore.ToString(); + Debug.Log($"[ScoreManager] Wrote total to TMP: {totalScore} -> {tmpComp.gameObject.name}"); + } + else + { + var legacyComp = go.GetComponent(); + if (legacyComp != null) + { + legacyComp.text = totalScore.ToString(); + Debug.Log($"[ScoreManager] Wrote total to legacy Text: {totalScore} -> {legacyComp.gameObject.name}"); + } + else + { + ui.currentTotalScore.text = totalScore.ToString(); // fallback + Debug.Log($"[ScoreManager] Wrote total to currentTotalScore field fallback: {totalScore}"); + } + } + } + else + { + ui.currentTotalScore.text = totalScore.ToString(); + Debug.Log($"[ScoreManager] Wrote total to currentTotalScore fallback (no go): {totalScore}"); + } + } + else + { + Debug.LogWarning("[ScoreManager] teamUIController.currentTotalScore is null; cannot display total score."); + } + } + else + { + Debug.LogWarning("[ScoreManager] teamUIController.Instance is null; cannot update UI."); + } + } +} diff --git a/Assets/scripts/Combat/ScoreManager.cs.meta b/Assets/scripts/Combat/ScoreManager.cs.meta new file mode 100644 index 00000000..9faf1e29 --- /dev/null +++ b/Assets/scripts/Combat/ScoreManager.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 1e98dd46b2f96dd42a078225abf0f31a \ No newline at end of file diff --git a/Assets/scripts/Combat/SkillBuilder.cs b/Assets/scripts/Combat/SkillBuilder.cs new file mode 100644 index 00000000..1b3b8518 --- /dev/null +++ b/Assets/scripts/Combat/SkillBuilder.cs @@ -0,0 +1,938 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +/// +/// SkillBuilder: жɿٵõļܺ +/// - ÿΪһ public ܱҪʩ source, Ŀ specificTarget ȣ +/// - ڲ EffectSystem.Instance.ApplyEffect(...)ͳһʹ Selector EffectType +/// - ṩòamount, duration, tickIntervalԲУ +/// +/// ÷ʾ: +/// SkillBuilder.Instance.ExecuteSkill("Fireball", EffectType.DamageSingleEnemy, 120f, Selector.CurrentEnemies, caster, target); +/// SkillBuilder.Instance.ApplyScoreMultiplier(caster, Selector.AllAllies, 1.5f, 5f); // 5 ڶ÷ֳ 1.5 +/// +public class SkillBuilder : MonoBehaviour +{ + public static SkillBuilder Instance { get; private set; } + + private void Awake() + { + if (Instance == null) Instance = this; + else Destroy(gameObject); + } + + // ----------------------------- ģ ----------------------------- + public float defaultDamage = 100f; + public float defaultHeal = 80f; + public float defaultDuration = 5f; + public float defaultTickInterval = 1f; + + [Header("Shared note-hit auto-skill settings")] + // These defaults remain as a global fallback but the preferred source is per-level fields in AllyHero_SO + [Tooltip("(Fallback) Mana gained on Good judge if SO level value not present")] public int manaGainGood = 1; + [Tooltip("(Fallback) Mana gained on Great judge if SO level value not present")] public int manaGainGreat = 2; + [Tooltip("(Fallback) Mana gained on Perfect judge if SO level value not present")] public int manaGainPerfect = 3; + [Tooltip("(Fallback) Mana gained on Miss judge if SO level value not present")] public int manaGainOnMiss = 5; + + [Tooltip("(Fallback) Damage multiplier applied to ally base attack for Good hits if SO level value not present")] public float damageMultiplierGood = 0.5f; + [Tooltip("(Fallback) Damage multiplier applied to ally base attack for Great hits if SO level value not present")] public float damageMultiplierGreat = 0.75f; + [Tooltip("(Fallback) Damage multiplier applied to ally base attack for Perfect hits if SO level value not present")] public float damageMultiplierPerfect = 1f; + + [Tooltip("(Fallback) Base HP loss on Miss will be (missHpLossBase * (1 - damageResistance)) if SO level value not present")] public float missHpLossBase = 10f; + + // Placeholder: if you want to route damage through EffectSystem later, use this. + public void DealDamageFromAllyToEnemies(int slotIndex, float amount) + { + Debug.Log($"[SkillBuilder] DealDamageFromAllyToEnemies (placeholder): slot={slotIndex} amount={amount}"); + // Future: integrate with EffectSystem/Enemy system here. Example (commented): + // var caster = GetAllyObjectBySlot(slotIndex); + // global::EffectSystem.Instance?.ApplyEffect(Selector.CurrentEnemies, EffectType.DamageSingleEnemy, amount, 0f, caster, null); + } + + private void ApplySharedOnNoteHit(int trackIndex, string judgeResult) + { + if (trackIndex < 0) return; + var allyGO = GetAllyObjectBySlot(trackIndex); + if (allyGO == null) return; + var ally = allyGO.GetComponent(); + var so = GetAllyHeroSOBySlot(trackIndex); + // try to obtain per-level params from SO if present + AllyHero_SO.AllyLevelInfo levelInfo = so != null ? (so.GetEffectiveLevelForCurrentEXP()) : null; + + int manaGain = 0; + float damageMult = 0f; + if (levelInfo != null) + { + switch (judgeResult) + { + case "Perfect": manaGain = levelInfo.manaGainPerfect; damageMult = levelInfo.damageMultiplierPerfect; break; + case "Great": manaGain = levelInfo.manaGainGreat; damageMult = levelInfo.damageMultiplierGreat; break; + case "Good": manaGain = levelInfo.manaGainGood; damageMult = levelInfo.damageMultiplierGood; break; + default: manaGain = levelInfo.manaGainOnMiss; break; + } + } + else + { + switch (judgeResult) + { + case "Perfect": manaGain = manaGainPerfect; damageMult = damageMultiplierPerfect; break; + case "Great": manaGain = manaGainGreat; damageMult = damageMultiplierGreat; break; + case "Good": manaGain = manaGainGood; damageMult = damageMultiplierGood; break; + default: manaGain = manaGainOnMiss; break; + } + } + + if (ally != null && manaGain != 0) + { + ally.ModifyMana(manaGain, true); + Debug.Log($"[SkillBuilder] Applied mana gain {manaGain} to slot {trackIndex} due to judge {judgeResult}"); + } + + if (judgeResult == "Miss") + { + if (ally != null) + { + float missBase = (levelInfo != null) ? levelInfo.missHpLossBase : missHpLossBase; + // apply damage reduction by damageResistance: final loss = missBase * (1 - damageResistance) + float loss = missBase * (1f - ally.damageResistance); + ally.ModifyHP(-Mathf.CeilToInt(loss), true); + Debug.Log($"[SkillBuilder] Applied miss HP loss {loss} to slot {trackIndex} (damageResistance={ally.damageResistance})"); + } + } + else + { + if (damageMult > 0f) + { + int baseAtk = GetAllyBaseAttack(so); + // damage should scale with (1 - damageResistance) of enemies when applied; here we pass raw amount = baseAtk * damageMult + float dmg = baseAtk * damageMult; + DealDamageFromAllyToEnemies(trackIndex, dmg); + } + } + } + + // ----------------------------- ͨüִнӿ ----------------------------- + // ִͨУ, Ч, ֵ, Ŀѡ, ʩ, ѡĿ, ʱ tick + public void ExecuteSkill(string skillName, EffectType effectType, float amount, Selector selector, GameObject caster, GameObject specificTarget = null, float duration = 0f, float tickInterval = 1f) + { + if (global::EffectSystem.Instance == null) + { + Debug.LogWarning($"ExecuteSkill failed: EffectSystem.Instance is null"); + return; + } + // basic logging + Debug.Log($"[SkillBuilder] ExecuteSkill: {skillName} type={effectType} amount={amount} selector={selector} caster={(caster?caster.name:"null")} target={(specificTarget?specificTarget.name:"null")} duration={duration}"); + + // call EffectSystem using GameObject API (keeps compatibility with existing EffectSystem) + global::EffectSystem.Instance.ApplyEffect(selector, effectType, amount, duration, caster, specificTarget, tickInterval); + } + + // New overload: execute by slot index (no GameObject required externally) + public void ExecuteSkillBySlot(string skillName, EffectType effectType, float amount, Selector selector, int casterSlotIndex = -1, int specificTargetSlot = -1, float duration = 0f, float tickInterval = 1f) + { + GameObject casterGO = casterSlotIndex >= 0 ? GetAllyObjectBySlot(casterSlotIndex) : null; + GameObject targetGO = specificTargetSlot >= 0 ? GetAllyObjectBySlot(specificTargetSlot) : null; + ExecuteSkill(skillName, effectType, amount, selector, casterGO, targetGO, duration, tickInterval); + } + + // ----------------------------- Ŀűʹã EffectSystem Ľһ£ ----------------------------- + // ط selector GameObject б㼼ܽűвֱӸ ICombatant.Buff + public List ResolveTargetsLocal(Selector selector, GameObject source = null, GameObject specificTarget = null) + { + List list = new List(); + switch (selector) + { + case Selector.Self: + if (source != null) list.Add(source); + break; + case Selector.AllAllies: + for (int i = 1; i <= 5; i++) { var go = GameObject.Find($"ally_0{i}"); if (go != null) list.Add(go); } + try { var tagged = GameObject.FindGameObjectsWithTag("Ally"); foreach (var g in tagged) if (!list.Contains(g)) list.Add(g); } catch { } + break; + case Selector.AllAlliesExceptSelf: + for (int i = 1; i <= 5; i++) { var go = GameObject.Find($"ally_0{i}"); if (go != null) list.Add(go); } + try { var tagged = GameObject.FindGameObjectsWithTag("Ally"); foreach (var g in tagged) if (!list.Contains(g)) list.Add(g); } catch { } + if (source != null) list.RemoveAll(g => g == null || g == source); + break; + case Selector.AdjacentAllies: + if (source == null) break; + int slotIndex = -1; + var ac = source.GetComponent(); + if (ac != null) slotIndex = ac.slotIndex; + else + { + var n = source.name; + for (int i = 1; i <= 5; i++) if (n.Contains($"ally_0{i}")) { slotIndex = i - 1; break; } + } + + var ui = teamUIController.Instance; + // Additional attempt: if source isn't AllyCombatant and name parse failed, try to match source to UI slots (or child of slot object) + if (slotIndex < 0 && ui != null) + { + for (int i = 0; i < 5; i++) + { + var slotObj = ui.GetAllyObjectBySlot(i); + if (slotObj == null) continue; + if (slotObj == source) { slotIndex = i; break; } + // if source is a child of the slot object + if (source.transform.IsChildOf(slotObj.transform)) { slotIndex = i; break; } + } + } + + if (slotIndex >= 0) + { + if (ui != null) + { + var adj = ui.GetAdjacentAllyIndices(slotIndex); + foreach (var idx in adj) + { + var go = ui.GetAllyObjectBySlot(idx); + if (go != null) list.Add(go); + else { var named = GameObject.Find($"ally_0{idx + 1}"); if (named != null) list.Add(named); } + } + } + else + { + int left = slotIndex - 1, right = slotIndex + 1; + if (left >= 0) { var g = GameObject.Find($"ally_0{left + 1}"); if (g != null) list.Add(g); } + if (right <= 4) { var g = GameObject.Find($"ally_0{right + 1}"); if (g != null) list.Add(g); } + } + } + else + { + Debug.LogWarning("[SkillBuilder] ResolveTargetsLocal: could not determine slot index for AdjacentAllies for source=" + (source?source.name:"null")); + } + break; + case Selector.CurrentEnemies: + if (specificTarget != null) list.Add(specificTarget); + else { try { var tagged = GameObject.FindGameObjectsWithTag("Enemy"); foreach (var g in tagged) if (!list.Contains(g)) list.Add(g); } catch { var single = GameObject.Find("thisEnemy"); if (single != null) list.Add(single); } } + break; + case Selector.AllEntities: + for (int i = 1; i <= 5; i++) { var go = GameObject.Find($"ally_0{i}"); if (go != null) list.Add(go); } + try { var tagged = GameObject.FindGameObjectsWithTag("Ally"); foreach (var g in tagged) if (!list.Contains(g)) list.Add(g); } catch { } + try { var taggedE = GameObject.FindGameObjectsWithTag("Enemy"); foreach (var g in taggedE) if (!list.Contains(g)) list.Add(g); } catch { var single = GameObject.Find("thisEnemy"); if (single != null && !list.Contains(single)) list.Add(single); } + break; + } + list.RemoveAll(x => x == null); + var uniq = new List(); + foreach (var g in list) if (!uniq.Contains(g)) uniq.Add(g); + return uniq; + } + + // ----------------------------- Ӱ API ----------------------------- + // ֱ޸ȫܷ֣Ч + public void ModifyTotalScore(int delta) + { + if (ScoreManager.Instance == null) { Debug.LogWarning("ModifyTotalScore: ScoreManager.Instance == null"); return; } + // adjust total and attempt to update UI + ScoreManager.Instance.totalScore += delta; + // try to force UI update via ScoreManager.RecalculateTotal() is not appropriate because it recalculates from allies + // so instead update displayed total directly if teamUIController present + if (teamUIController.Instance != null && teamUIController.Instance.currentTotalScore != null) + { + teamUIController.Instance.currentTotalScore.text = ScoreManager.Instance.totalScore.ToString(); + } + } + + // ޸ĵѾķʱ + public void ModifySingleAllyScoreDirect(GameObject allyObject, int delta) + { + if (allyObject == null) return; + var ally = allyObject.GetComponent(); + if (ally != null) + { + ally.AddScoreDirect(delta); + } + } + + // Slot-based: modify single ally by slot index (no GameObject required) + public void ModifySingleAllyScoreDirectBySlot(int slotIndex, int delta) + { + var go = GetAllyObjectBySlot(slotIndex); + if (go == null) return; + var ally = go.GetComponent(); + if (ally != null) ally.AddScoreDirect(delta); + } + + // һĿӦһԵķ/ͷӦã + public void ModifyGroupScoreDirect(Selector selector, GameObject caster, int delta) + { + var targets = ResolveTargetsLocal(selector, caster); + foreach (var t in targets) + { + var ally = t.GetComponent(); + if (ally != null) ally.AddScoreDirect(delta); + } + } + + // ʱߣ򽵵ͣĿķʣʹ EffectSystem.ScoreMultiplierƼ + public void ApplyScoreMultiplier(Selector selector, GameObject caster, float multiplier, float duration) + { + if (multiplier <= 0f) { Debug.LogWarning("ApplyScoreMultiplier: invalid multiplier"); return; } + global::EffectSystem.Instance.ApplyEffect(selector, EffectType.ScoreMultiplier, multiplier, duration, caster, null); + } + + // Slot-based helper: apply score multiplier to a single slot + public void ApplyScoreMultiplierToSlot(int slotIndex, float multiplier, float duration) + { + if (multiplier <= 0f) { Debug.LogWarning("ApplyScoreMultiplierToSlot: invalid multiplier"); return; } + var go = GetAllyObjectBySlot(slotIndex); + if (go == null) { Debug.LogWarning($"ApplyScoreMultiplierToSlot: no ally object for slot {slotIndex}"); return; } + global::EffectSystem.Instance.ApplyEffect(Selector.Self, EffectType.ScoreMultiplier, multiplier, duration, go, null); + } + + // Slot-based helper: add flat score to a single slot (immediate) + public void AddScoreToSlot(int slotIndex, int delta) + { + var go = GetAllyObjectBySlot(slotIndex); + if (go == null) { Debug.LogWarning($"AddScoreToSlot: no ally object for slot {slotIndex}"); return; } + global::EffectSystem.Instance.ApplyEffect(Selector.Self, EffectType.AddScore, delta, 0f, go, null); + } + + private IEnumerator ApplyBuffToTargetsCoroutine(Buff buff, List targets, GameObject source) + { + if (buff == null) yield break; + foreach (var t in targets) + { + if (t == null) continue; + var comp = t.GetComponent(); + if (comp != null) comp.ApplyBuff(buff, source); + else Debug.LogWarning($"ApplyBuffToTargets: target {t.name} has no ICombatant"); + } + if (buff.duration > 0f) + yield return new WaitForSeconds(buff.duration); + else + yield break; + + foreach (var t in targets) + { + if (t == null) continue; + var comp = t.GetComponent(); + if (comp != null) comp.RemoveBuff(buff.buffId); + } + } + + // ----------------------------- бݼʾ ----------------------------- + public void DealSingleEnemyDamage(GameObject caster, GameObject enemyTarget, float amount) + { + if (enemyTarget == null) { Debug.LogWarning("DealSingleEnemyDamage: enemyTarget == null"); return; } + ExecuteSkill("DealSingleEnemyDamage", EffectType.DamageSingleEnemy, amount, Selector.CurrentEnemies, caster, enemyTarget); + } + + public void ApplyDamageOverTimeToEnemies(GameObject caster, Selector selector, float totalAmount, float duration, float tickInterval = 1f, GameObject specificTarget = null) + { + if (duration <= 0f) duration = defaultDuration; + if (tickInterval <= 0f) tickInterval = defaultTickInterval; + ExecuteSkill("DamageOverTime", EffectType.DamageOverTimeEnemy, totalAmount, selector, caster, specificTarget, duration, tickInterval); + } + + public void HealSelf(GameObject caster, float amount) + { + ExecuteSkill("HealSelf", EffectType.HealSingleSelf, amount, Selector.Self, caster, caster); + } + + public void HealSelfOverTime(GameObject caster, float totalAmount, float duration, float tickInterval = 1f) + { + ExecuteSkill("HealSelfOverTime", EffectType.HealOverTimeSelf, totalAmount, Selector.Self, caster, caster, duration, tickInterval); + } + + public void HealGroupSingle(GameObject caster, float amount, bool includeSelf = true) + { + var sel = includeSelf ? Selector.AllAllies : Selector.AllAlliesExceptSelf; + ExecuteSkill("HealGroupSingle", EffectType.HealGroupSingle, amount, sel, caster); + } + + public void HealGroupOverTime(GameObject caster, float totalAmount, float duration, float tickInterval = 1f, bool includeSelf = true) + { + var sel = includeSelf ? Selector.AllAllies : Selector.AllAlliesExceptSelf; + ExecuteSkill("HealGroupOverTime", EffectType.HealGroupOverTime, totalAmount, sel, caster, null, duration, tickInterval); + } + + public void IncreaseManaOverTime(GameObject caster, Selector selector, float totalAmount, float duration, float tickInterval = 1f, GameObject specificTarget = null) + { + ExecuteSkill("IncreaseManaOverTime", EffectType.IncreaseManaOverTime, totalAmount, selector, caster, specificTarget, duration, tickInterval); + } + + public void ReduceEnemyHealOverTime(GameObject caster, Selector selector, float duration, GameObject specificTarget = null) + { + ExecuteSkill("ReduceEnemyHealOverTime", EffectType.ReduceEnemyHealOverTime, 0f, selector, caster, specificTarget, duration); + } + + public void HealAdjacentAllies(GameObject caster, float amount) + { + ExecuteSkill("HealAdjacentAllies", EffectType.HealGroupSingle, amount, Selector.AdjacentAllies, caster); + } + + public void IncreaseManaAdjacentAllies(GameObject caster, float totalAmount, float duration, float tickInterval = 1f) + { + ExecuteSkill("IncreaseManaAdjacentAllies", EffectType.IncreaseManaOverTime, totalAmount, Selector.AdjacentAllies, caster, null, duration, tickInterval); + } + + public void Hero_A_Ultimate(GameObject caster, GameObject enemyTarget) + { + DealSingleEnemyDamage(caster, enemyTarget, defaultDamage * 2f); + HealAdjacentAllies(caster, defaultHeal * 0.5f); + } + + public void MassHeal(GameObject caster) + { + HealGroupOverTime(caster, defaultHeal * 5f, 4f, 1f, true); + } + + // ----------------------------- SO ֵ helpers ----------------------------- + // ȡijλ ally GameObject0-based slot index + public GameObject GetAllyObjectBySlot(int slotIndex) + { + var ui = teamUIController.Instance; + if (ui != null) return ui.GetAllyObjectBySlot(slotIndex); + var named = GameObject.Find($"ally_0{slotIndex + 1}"); + return named; + } + + // ݲλ AllyHero_SOʱ Resources в ally_heroID + public AllyHero_SO GetAllyHeroSOBySlot(int slotIndex) + { + if (teamUIController.Instance == null || teamUIController.Instance.allySlotIds == null) return null; + if (slotIndex < 0 || slotIndex >= teamUIController.Instance.allySlotIds.Count) return null; + int id = teamUIController.Instance.allySlotIds[slotIndex]; + if (id <= 0) return null; + + var all = Resources.LoadAll(""); + foreach (var a in all) + { + if (a != null && a.ally_heroID == id) return a; + } + return null; + } + + // ݵǰѡЧĵȼϢ null ʾδҵ + private AllyHero_SO.AllyLevelInfo GetEffectiveLevelInfo(AllyHero_SO so) + { + if (so == null || so.levelStats == null || so.levelStats.Count == 0) return null; + // choose the highest requiredEXP that is <= ally_currentEXP + AllyHero_SO.AllyLevelInfo best = null; + int currentExp = so.ally_currentEXP; + foreach (var lvl in so.levelStats) + { + if (best == null) + { + if (currentExp >= lvl.requiredEXP) best = lvl; + } + else + { + if (currentExp >= lvl.requiredEXP && lvl.requiredEXP >= best.requiredEXP) best = lvl; + } + } + // if no level matched (all requiredEXP > currentExp), fallback to lowest level (index 0) + if (best == null) return so.levelStats[0]; + return best; + } + + // ȡӢۻʹõǰƥĵȼ attackû򷵻 0 + public int GetAllyBaseAttack(AllyHero_SO so) + { + if (so == null) return 0; + var eff = GetEffectiveLevelInfo(so); + if (eff != null) return eff.attack; + if (so.levelStats != null && so.levelStats.Count > 0) return so.levelStats[0].attack; + return 0; + } + + // ͳһ㼼ֵ inputValue == -1 ʱʹ skillStatic + allyAttack + // ֱʹ inputValue EffectType Ҫת + public float ComputeSkillValue(GameObject caster, int slotIndex, float inputValue, int skillStatic) + { + if (inputValue != -1f) return inputValue; + var so = GetAllyHeroSOBySlot(slotIndex); + int allyAtk = GetAllyBaseAttack(so); + return skillStatic + allyAtk; + } + + // ----------------------------- λͨýӿ ----------------------------- + // ͨڱλĽɫͷʱô˺ + // slotIndex: 0-based λskillId: Զ弼ܱʶeffectType,value,selector,durationȲͬǰԼ + public void AllySlotSkill(int slotIndex, string skillId, EffectType effectType, float value, Selector selector, float duration = 0f, GameObject specificTarget = null, float tickInterval = 1f) + { + GameObject caster = GetAllyObjectBySlot(slotIndex); + if (caster == null) + { + Debug.LogWarning($"AllySlotSkill: no caster found for slot {slotIndex}"); + return; + } + + // determine skill-specific static values (ʾskill01 Ĺ̶˺Ϊ 50) + int skillStaticDamage = 0; + switch (skillId) + { + case "skill01": skillStaticDamage = 50; break; + case "skill_heal_small": skillStaticDamage = 30; break; + // ڴӸ༼ֵܾ̬ + default: skillStaticDamage = 0; break; + } + + float finalValue = ComputeSkillValue(caster, slotIndex, value, skillStaticDamage); + + // ⴦ effectType ǵ˺ϣеʹ CurrentEnemiesselector ɵ÷ + ExecuteSkill($"slot{slotIndex + 1}_{skillId}", effectType, finalValue, selector, caster, specificTarget, duration, tickInterval); + } + + // New: invoke a SkillDefinition directly (respects staticValue and SO attack when value == -1) + public void UseSkillDefinition(SkillDefinition def, int slotIndex, float inputValue = -1f, GameObject specificTarget = null) + { + if (def == null) { Debug.LogWarning("UseSkillDefinition: null def"); return; } + GameObject caster = GetAllyObjectBySlot(slotIndex); + if (caster == null) + { + Debug.LogWarning($"UseSkillDefinition: no caster GameObject found for slot {slotIndex}. Proceeding with null caster."); + } + + float amount = 0f; + // If caller provided explicit inputValue use it + if (inputValue != -1f) + { + amount = inputValue; + } + else + { + // Build variables from SO and caster; formula can be a plain number too + var so = GetAllyHeroSOBySlot(slotIndex); + var vars = new Dictionary(); + vars["slot"] = slotIndex; + vars["attack"] = GetAllyBaseAttack(so); + if (so != null && so.levelStats != null && so.levelStats.Count > 0) + { + var eff = GetEffectiveLevelInfo(so); + var lvl = eff ?? so.levelStats[0]; + vars["maxHP"] = lvl.maxHP; + vars["maxMana"] = lvl.maxMana; + vars["damageResistance"] = lvl.damageResistance; + vars["scoreEfficiency"] = lvl.scoreEfficiency; + vars["attack"] = lvl.attack; // ensure attack from SO levelStats is available + } + else + { + vars["maxHP"] = 0f; + vars["maxMana"] = 0f; + vars["damageResistance"] = 0f; + vars["scoreEfficiency"] = 1f; + } + if (so != null) vars["ally_currentEXP"] = so.ally_currentEXP; + else vars["ally_currentEXP"] = 0f; + + if (string.IsNullOrWhiteSpace(def.formula)) + { + Debug.LogWarning($"UseSkillDefinition: skill {def.skillId} has empty formula, defaulting to 0"); + amount = 0f; + } + else + { + if (!SkillDefinition.TryEvaluateFormula(def.formula, vars, out float fresult)) + { + Debug.LogWarning($"UseSkillDefinition: formula evaluation failed for skill {def.skillId}, defaulting to 0"); + amount = 0f; + } + else + { + amount = fresult; + } + } + } + + // Convert formula result (interpreted as per-tick when skill is sustained) to total amount + // amount now represents the formula result (per-tick for sustained effects, instant for single-instance) + float amountPerTick = amount; + float amountTotal = amountPerTick; + if (!def.IsSingleInstance) + { + // compute ticks based on def duration and effective tick interval + float tickInterval = def.GetEffectiveTickInterval(); + int ticks = Mathf.Max(1, Mathf.CeilToInt(def.defaultDuration / tickInterval)); + amountTotal = amountPerTick * ticks; + } + + // If this skill is intended to be triggered by note hits, treat it as a one-time application + // (do not multiply by duration ticks). This prevents OnNoteHit triggers from unexpectedly + // applying sustained totals (e.g. 5s * perTick) when the designer expects a single effect. + if (def.triggerCondition == SkillDefinition.SkillTrigger.OnNoteHit) + { + amountTotal = amountPerTick; + } + + if (def.operateDirectly) + { + // Resolve targets as GameObjects but operate on their AllyCombatant / ICombatant data directly + List targets = ResolveTargetsLocal(def.defaultSelector, caster, specificTarget); + if (targets == null || targets.Count == 0) + { + Debug.LogWarning($"UseSkillDefinition: no targets for direct operation skill {def.skillId}"); + return; + } + + foreach (var t in targets) + { + if (t == null) continue; + var ally = t.GetComponent(); + var ic = t.GetComponent(); + + switch (def.effectType) + { + case EffectType.DamageSingleEnemy: + // treat as damage to an enemy; if target has AllyCombatant, apply negative HP + if (ally != null) ally.ModifyHP(-Mathf.CeilToInt(amountTotal), true); + else if (ic != null) ic.ReceiveDamage(amountTotal, caster); + break; + case EffectType.DamageOverTimeEnemy: + // sustained: start coroutine to apply per-tick damage rather than instant total + if (def.defaultDuration <= 0f) + { + if (ally != null) ally.ModifyHP(-Mathf.CeilToInt(amountPerTick), true); + else if (ic != null) ic.ReceiveDamage(amountPerTick, caster); + } + else + { + StartCoroutine(ApplyDamageOverTimeDirect(t, amountTotal, def.defaultDuration, def.GetEffectiveTickInterval(), caster)); + } + break; + case EffectType.HealSingleSelf: + case EffectType.HealGroupSingle: + if (ally != null) ally.ModifyHP(Mathf.CeilToInt(amountTotal), true); + else if (ic != null) ic.ReceiveHeal(amountTotal, caster); + break; + case EffectType.HealOverTimeSelf: + case EffectType.HealGroupOverTime: + if (def.defaultDuration <= 0f) + { + if (ally != null) ally.ModifyHP(Mathf.CeilToInt(amountPerTick), true); + else ic?.ReceiveHeal(amountPerTick, caster); + } + else + { + StartCoroutine(ApplyHealOverTimeDirect(t, amountTotal, def.defaultDuration, def.GetEffectiveTickInterval(), caster)); + } + break; + case EffectType.IncreaseManaOverTime: + if (ally != null) + { + if (def.defaultDuration <= 0f) + { + // single instance - amountPerTick equals immediate amount + ally.ModifyMana(Mathf.CeilToInt(amountPerTick), true); + } + else + { + // for sustained, pass total amount (amountTotal) to coroutine which expects total + StartCoroutine(ApplyIncreaseManaOverTimeDirect(ally, amountTotal, def.defaultDuration, def.GetEffectiveTickInterval())); + } + } + break; + case EffectType.ReduceEnemyHealOverTime: + var deb = new Buff { buffId = System.Guid.NewGuid().ToString(), duration = def.defaultDuration, healReceivedMultiplier = 0.5f }; + if (ic != null) ic.ApplyBuff(deb, caster); + break; + case EffectType.BuffDuration: + case EffectType.DebuffDuration: + var b = new Buff { buffId = System.Guid.NewGuid().ToString(), duration = def.defaultDuration }; + if (def.effectType == EffectType.BuffDuration) b.scoreMultiplier = 1.5f; + if (ic != null) ic.ApplyBuff(b, caster); + break; + default: + // non-direct path handled below, but keep compatibility + ExecuteSkill(def.displayName ?? def.skillId, def.effectType, amountTotal, def.defaultSelector, caster, specificTarget, def.defaultDuration, def.defaultTickInterval); + break; + } + } + } + else + { + // For non-direct path, EffectSystem expects 'amount' to be total amount for sustained effects + ExecuteSkill(def.displayName ?? def.skillId, def.effectType, amountTotal, def.defaultSelector, caster, specificTarget, def.defaultDuration, def.defaultTickInterval); + } + } + + // Use the selected skill index from an AllyHero_SO for a given slot (calls UseSkillDefinition) + public void UseSelectedSkillForSlot(int slotIndex, int selectedSkillIndex, float inputValue = -1f, GameObject specificTarget = null) + { + var so = GetAllyHeroSOBySlot(slotIndex); + if (so == null || so.availableSkills == null || selectedSkillIndex < 0 || selectedSkillIndex >= so.availableSkills.Length) + { + Debug.LogWarning($"UseSelectedSkillForSlot: invalid selection for slot {slotIndex}"); + return; + } + UseSkillDefinition(so.availableSkills[selectedSkillIndex], slotIndex, inputValue, specificTarget); + } + + // Use the primary skill configured in the AllyHero_SO for this slot (primarySkillIndex dropdown) + public void UsePrimarySkillForSlot(int slotIndex, float inputValue = -1f, GameObject specificTarget = null) + { + var so = GetAllyHeroSOBySlot(slotIndex); + if (so == null) + { + Debug.LogWarning($"UsePrimarySkillForSlot: no SO for slot {slotIndex}"); + return; + } + int idx = so.primarySkillIndex; + if (idx < 0) { Debug.LogWarning($"UsePrimarySkillForSlot: primarySkillIndex not set for slot {slotIndex}"); return; } + UseSelectedSkillForSlot(slotIndex, idx, inputValue, specificTarget); + } + + // Called at game start to trigger any allies whose primary skill is set to trigger on game start + public void TriggerOnGameStart() + { + if (teamUIController.Instance == null || teamUIController.Instance.allySlotIds == null) return; + int slots = teamUIController.Instance.allySlotIds.Count; + for (int i = 0; i < slots; i++) + { + var so = GetAllyHeroSOBySlot(i); + if (so == null) continue; + var def = so.GetPrimarySkill(); + if (def == null) continue; + if (def.triggerCondition == SkillDefinition.SkillTrigger.OnGameStart) + { + Debug.Log($"[SkillBuilder] TriggerOnGameStart: casting primary skill {def.skillId} for slot {i}"); + UsePrimarySkillForSlot(i, -1f, null); + } + } + } + + private Dictionary _lastOnNoteHitTriggerTime = new Dictionary(); + + // Called when a note on a particular track is hit (judgeResult e.g. "Perfect"/"Great"/"Good"). + // Will cast the primary skill for the ally in that track if its primary skill is configured to trigger on note hit. + // noteType indicates whether the hit event came from a Tap or Hold (tail) + public bool NotifyNoteHit(int trackIndex, string judgeResult, SkillDefinition.NoteTypeTrigger noteType = SkillDefinition.NoteTypeTrigger.Tap) + { + // Always apply shared per-note behavior (mana gain / miss penalty / reserved damage) regardless of SO-defined primary skill + try { ApplySharedOnNoteHit(trackIndex, judgeResult); } catch (System.Exception ex) { Debug.LogError($"[SkillBuilder] ApplySharedOnNoteHit threw: {ex}"); } + Debug.Log($"[SkillBuilder] NotifyNoteHit RECEIVED: track={trackIndex} judge={judgeResult} noteType={noteType}"); + if (trackIndex < 0) { Debug.Log("[SkillBuilder] NotifyNoteHit: invalid trackIndex"); return false; } + var so = GetAllyHeroSOBySlot(trackIndex); + if (so == null) + { + Debug.Log($"[SkillBuilder] NotifyNoteHit: no SO found for slot {trackIndex}, attempting fallback resolution..."); + // Dump current UI slot ids for diagnostics + if (teamUIController.Instance != null && teamUIController.Instance.allySlotIds != null) + { + Debug.Log($"[SkillBuilder] teamUIController.allySlotIds = [{string.Join(",", teamUIController.Instance.allySlotIds)}]"); + } + // Try to find ally GameObject named by convention + var foundGO = GameObject.Find($"ally_0{trackIndex + 1}"); + if (foundGO != null) + { + Debug.Log($"[SkillBuilder] Found GameObject by name ally_0{trackIndex + 1}: {foundGO.name}"); + // try to map to UI slot + var ui = teamUIController.Instance; + if (ui != null && ui.allySlotIds != null) + { + for (int i = 0; i < ui.allySlotIds.Count; i++) + { + var slotObj = ui.GetAllyObjectBySlot(i); + if (slotObj == null) continue; + if (slotObj == foundGO || foundGO.transform.IsChildOf(slotObj.transform)) + { + Debug.Log($"[SkillBuilder] Resolved fallback slot {i} for GameObject {foundGO.name}"); + trackIndex = i; // override + so = GetAllyHeroSOBySlot(trackIndex); + break; + } + } + } + } + if (so == null) + { + Debug.Log($"[SkillBuilder] NotifyNoteHit: still no SO for resolved slot {trackIndex}, aborting NotifyNoteHit"); + return false; + } + } + var def = so.GetPrimarySkill(); + if (def == null) { Debug.Log($"[SkillBuilder] NotifyNoteHit: no primary skill for slot {trackIndex}"); return false; } + + Debug.Log($"[SkillBuilder] NotifyNoteHit: skill={def.skillId} noteTriggerType={def.noteTriggerType} onNoteHitMinThreshold={def.onNoteHitMinThreshold} cooldown={def.onNoteHitCooldown}"); + + // Treat Hold events as Tap-equivalent by default to improve compatibility: many skills expect Tap/Either + var effectiveNoteType = noteType; + if (noteType == SkillDefinition.NoteTypeTrigger.Hold) + { + // Only convert to Tap-equivalent for checking; keep original in logs + effectiveNoteType = SkillDefinition.NoteTypeTrigger.Tap; + Debug.Log($"[SkillBuilder] NotifyNoteHit: treating incoming Hold event as Tap-equivalent for skill checks (track={trackIndex})"); + } + + // Respect note type (Tap/Hold/Either) + switch (def.noteTriggerType) + { + case SkillDefinition.NoteTypeTrigger.Tap: + // accept Tap (and treat Hold as Tap-equivalent) + if (effectiveNoteType != SkillDefinition.NoteTypeTrigger.Tap) + { + Debug.Log($"[SkillBuilder] NotifyNoteHit: skill {def.skillId} requires Tap but event is {noteType}, rejecting"); + return false; + } + break; + case SkillDefinition.NoteTypeTrigger.Hold: + if (noteType != SkillDefinition.NoteTypeTrigger.Hold) + { + Debug.Log($"[SkillBuilder] NotifyNoteHit: skill {def.skillId} requires Hold but event is {noteType}, rejecting"); + return false; + } + break; + case SkillDefinition.NoteTypeTrigger.Either: + // accept both + break; + } + + // Map judgeResult to numeric quality + int quality = JudgeQualityFromString(judgeResult); + Debug.Log($"[SkillBuilder] NotifyNoteHit: judgeResult='{judgeResult}' mappedQuality={quality}"); + // Special case: if threshold == Miss, only trigger on Miss (quality == 0) + if (def.onNoteHitMinThreshold == SkillDefinition.NoteTriggerThreshold.Miss) + { + if (quality != 0) + { + Debug.Log($"[SkillBuilder] NotifyNoteHit: skill {def.skillId} is Miss-only but quality={quality}, rejecting"); + return false; + } + } + else + { + int required = (int)def.onNoteHitMinThreshold; // Good=1, Great=2, Perfect=3 + if (quality < required) + { + Debug.Log($"[SkillBuilder] NotifyNoteHit: skill {def.skillId} requires quality>={required} but got {quality}, rejecting"); + // not high enough + return false; + } + } + + // cooldown: per slot+skill + string key = $"{trackIndex}:{def.skillId}"; + float now = Time.time; + if (def.onNoteHitCooldown > 0f) + { + if (_lastOnNoteHitTriggerTime.TryGetValue(key, out float last)) + { + if (now - last < def.onNoteHitCooldown) + { + Debug.Log($"[SkillBuilder] NotifyNoteHit: skill {def.skillId} on cooldown for slot {trackIndex}"); + // still cooling down + return false; + } + } + } + + // Passed checks -> invoke primary skill for slot + Debug.Log($"[SkillBuilder] NotifyNoteHit: triggering primary skill {def.skillId} for slot {trackIndex} due to note hit {judgeResult} (noteType={noteType})"); + UsePrimarySkillForSlot(trackIndex, -1f, null); + _lastOnNoteHitTriggerTime[key] = now; + return true; + } + + private int JudgeQualityFromString(string judge) + { + switch (judge) + { + case "Perfect": return 3; + case "Great": return 2; + case "Good": return 1; + default: return 0; // Miss or unknown + } + } + + /* + Explanation of caster and enemyTarget: + - GameObject caster: the GameObject that performs (casts) the skill. For ally skills this should be the in-scene ally GameObject (usually name ally_01..ally_05) and should have AllyCombatant / ICombatant components. SkillBuilder uses slotIndex -> GetAllyObjectBySlot to resolve this. + - GameObject specificTarget / enemyTarget: when a skill targets a specific unit (single enemy or ally), pass that GameObject here. If null, the selected Selector determines the set of targets (e.g. CurrentEnemies without specificTarget will resolve all enemies). Use Enemy GameObjects found by tag 'Enemy' or name 'thisEnemy', or keep a reference to the spawned enemy instance you want. + + How to assign/choose: + - Caster: when you call from gameplay code, pass the caster GameObject (or call UseSelectedSkillForSlot with slot index so SkillBuilder resolves caster for you). + - EnemyTarget: if your skill should hit a specific enemy instance, supply that enemy's GameObject (for example from Enemy spawn manager or from collision detection). If you want to apply to all enemies, pass null and use Selector.CurrentEnemies. + */ + + // ----------------------------- ʾΪ3 װһݺûʾ ----------------------------- + // 3(2) ļ1ѭûǩ_ally03skill01(EffectType, value, Selector, duration) + public void _ally03skill01(EffectType effectType, float value, Selector selector, float duration = 0f, GameObject specificTarget = null) + { + AllySlotSkill(2, "skill01", effectType, value, selector, duration, specificTarget); + } + + // Coroutine helper for IncreaseManaOverTime + private IEnumerator ApplyIncreaseManaOverTimeDirect(AllyCombatant ally, float totalAmount, float duration, float tickInterval) + { + if (ally == null) yield break; + if (duration <= 0f || tickInterval <= 0f) + { + ally.ModifyMana(Mathf.CeilToInt(totalAmount), true); + yield break; + } + int ticks = Mathf.Max(1, Mathf.CeilToInt(duration / tickInterval)); + float perTick = totalAmount / ticks; + float elapsed = 0f; + while (elapsed < duration) + { + ally.ModifyMana(Mathf.CeilToInt(perTick), true); + yield return new WaitForSeconds(tickInterval); + elapsed += tickInterval; + } + } + + // Coroutine helpers for direct DoT/HoT on GameObject targets + private IEnumerator ApplyDamageOverTimeDirect(GameObject target, float totalAmount, float duration, float tickInterval, GameObject source) + { + if (target == null) yield break; + var ic = target.GetComponent(); + var ally = target.GetComponent(); + if (ally == null && ic == null) + { + Debug.LogWarning($"ApplyDamageOverTimeDirect: target {target.name} cannot receive damage"); + yield break; + } + + if (duration <= 0f || tickInterval <= 0f) + { + if (ally != null) ally.ModifyHP(-Mathf.CeilToInt(totalAmount), true); + else ic?.ReceiveDamage(totalAmount, source); + yield break; + } + + int ticks = Mathf.Max(1, Mathf.CeilToInt(duration / tickInterval)); + float perTick = totalAmount / ticks; + float elapsed = 0f; + while (elapsed < duration) + { + if (ally != null) ally.ModifyHP(-Mathf.CeilToInt(perTick), true); + else ic?.ReceiveDamage(perTick, source); + yield return new WaitForSeconds(tickInterval); + elapsed += tickInterval; + } + } + + private IEnumerator ApplyHealOverTimeDirect(GameObject target, float totalAmount, float duration, float tickInterval, GameObject source) + { + if (target == null) yield break; + var ic = target.GetComponent(); + var ally = target.GetComponent(); + if (ally == null && ic == null) + { + Debug.LogWarning($"ApplyHealOverTimeDirect: target {target.name} cannot receive heal"); + yield break; + } + + if (duration <= 0f || tickInterval <= 0f) + { + if (ally != null) ally.ModifyHP(Mathf.CeilToInt(totalAmount), true); + else ic?.ReceiveHeal(totalAmount, source); + yield break; + } + + int ticks = Mathf.Max(1, Mathf.CeilToInt(duration / tickInterval)); + float perTick = totalAmount / ticks; + float elapsed = 0f; + while (elapsed < duration) + { + if (ally != null) ally.ModifyHP(Mathf.CeilToInt(perTick), true); + else ic?.ReceiveHeal(perTick, source); + yield return new WaitForSeconds(tickInterval); + elapsed += tickInterval; + } + } +} diff --git a/Assets/scripts/Combat/SkillBuilder.cs.meta b/Assets/scripts/Combat/SkillBuilder.cs.meta new file mode 100644 index 00000000..7e96a9d1 --- /dev/null +++ b/Assets/scripts/Combat/SkillBuilder.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 53ea14de0f25c18469332fda60802db9 \ No newline at end of file diff --git a/Assets/scripts/Combat/SkillDefinition.cs b/Assets/scripts/Combat/SkillDefinition.cs new file mode 100644 index 00000000..b8f6c9fe --- /dev/null +++ b/Assets/scripts/Combat/SkillDefinition.cs @@ -0,0 +1,263 @@ +using UnityEngine; +using System; +using System.Collections.Generic; +using System.Globalization; + +[CreateAssetMenu(fileName = "NewSkillDefinition", menuName = "Combat/SkillDefinition")] +public class SkillDefinition : ScriptableObject +{ + public enum SkillTrigger + { + None, + OnGameStart, + OnNoteHit, + OnManaFull + } + + [Header("ʶ (Identity)")] + [Tooltip("ܵڲΨһ IDڴʶ˼")] + public string skillId; + + [Tooltip(" UI ʾ")] + public string displayName; + + [Tooltip("ע/ժҪʱοӰ")] + [TextArea(1,2)] + public string summaryInfo; + + [Header("Ч (Effect)")] + [Tooltip("ܵЧͣ缴ʱ˺˺ơ/")] + public EffectType effectType = EffectType.DamageSingleEnemy; + + [Tooltip("ĬĿѡĬõĿ귶Χ/Ѿ/зȣ")] + public Selector defaultSelector = Selector.CurrentEnemies; + + [Tooltip("ѡ FromFormula ʱʹõıʽַ֧ʹ AllyHero_SO ֵֶͬΪ: attack, maxHP, maxMana, damageResistance, scoreEfficiency, ally_currentEXP, slotʾ: 'attack * 1.5 + maxHP * 0.1 + 20'ֻдһ֣ '120'̶ֵָͬ")] + [TextArea(2,4)] + public string formula = ""; + + [Tooltip("Ĭϳʱ䣨룩ڳЧ Buff ijʱΪ 0 Ϊһ/ʱܣᰴ tick ַ")] + public float defaultDuration = 0f; + + [Tooltip("Ĭϴ룩ڳЧÿδÿѪΪ 0 Ϊһ/ʱ")] + public float defaultTickInterval = 1f; + + [Header("־ (Flags)")] + [Tooltip("ǷָĿ꣨true ʾ˼ͨҪ specificTarget")] + public bool requiresSpecificTarget = false; // if true, skill usually targets a specific GameObject + + [Tooltip("ǷֱĿݣtrue ʾ SkillBuilder ֱӵ ICombatant/AllyCombatantͨ EffectSystem ַ")] + public bool operateDirectly = false; // if true, SkillBuilder will operate on ICombatant/AllyCombatant fields directly and update UI, instead of calling EffectSystem + + [Tooltip("ܵעʱд˵")] + [TextArea(8,4)] + public string description; + + [Header(" (Trigger)")] + [Tooltip("ܴϷʱʱֵʱ")] + public SkillTrigger triggerCondition = SkillTrigger.None; + + [Tooltip(" triggerCondition == OnNoteHit ʱЧﵽжʱѡ Miss/Good/Great/Perfectر˵ѡ Miss ʾжΪ Miss ʱжGood/Great/Perfectᴥ")] + public NoteTriggerThreshold onNoteHitMinThreshold = NoteTriggerThreshold.Good; + + [Tooltip(" triggerCondition == OnNoteHit ʱЧָ˼ Tap/HoldβΣ Either⣩ѡ Holdֻгβλᴥѡ Tap̰Either ߾ɣ Hold Կɱʽã")] + public NoteTypeTrigger noteTriggerType = NoteTypeTrigger.Either; + + [Tooltip(" triggerCondition == OnNoteHit ʱЧȴʱ䣨룩ȴʱٴжᴥ")] + public float onNoteHitCooldown = 0f; + + // Minimum judge quality required to trigger on note hit + public enum NoteTriggerThreshold + { + // Ϊ Miss ʱܽжΪ Missquality == 0ʱ + Miss = 0, + Good = 1, + Great = 2, + Perfect = 3 + } + + // ָӦ Tap/ Hold/ Either + public enum NoteTypeTrigger + { + Tap, + Hold, + Either + } + + // ʱԣ defaultDuration defaultTickInterval Ϊ 0 ʱһԼʱ + public bool IsSingleInstance => defaultDuration <= 0f || defaultTickInterval <= 0f; + + // ʵڷַļΪһԼ򷵻 0 + public float GetEffectiveTickInterval() + { + return IsSingleInstance ? 0f : Mathf.Max(0.0001f, defaultTickInterval); + } + + private void OnValidate() + { + // ֵ֤ΪǸ + if (defaultDuration < 0f) defaultDuration = 0f; + if (defaultTickInterval < 0f) defaultTickInterval = 0f; + if (onNoteHitCooldown < 0f) onNoteHitCooldown = 0f; + } + + // --- Simple expression evaluator used when valueMode == FromFormula --- + // Supports variables (alphanumeric), floats, operators + - * / and parentheses. + public static bool TryEvaluateFormula(string expr, Dictionary variables, out float result) + { + result = 0f; + if (string.IsNullOrWhiteSpace(expr)) return false; + try + { + var tokens = Tokenize(expr); + var rpn = ToRPN(tokens); + result = EvalRPN(rpn, variables); + return true; + } + catch (Exception e) + { + Debug.LogWarning($"SkillDefinition: failed to evaluate formula '{expr}': {e.Message}"); + return false; + } + } + + // tokenization + private enum TokType { Number, Ident, Op, LParen, RParen } + private struct Token { public TokType type; public string text; } + + private static List Tokenize(string s) + { + var outp = new List(); + int i = 0; + while (i < s.Length) + { + char c = s[i]; + if (char.IsWhiteSpace(c)) { i++; continue; } + if (c == '(') { outp.Add(new Token { type = TokType.LParen, text = "(" }); i++; continue; } + if (c == ')') { outp.Add(new Token { type = TokType.RParen, text = ")" }); i++; continue; } + if ("+-*/".IndexOf(c) >= 0) + { + outp.Add(new Token { type = TokType.Op, text = c.ToString() }); i++; continue; + } + if (char.IsDigit(c) || c == '.') + { + int start = i; + while (i < s.Length && (char.IsDigit(s[i]) || s[i] == '.')) i++; + outp.Add(new Token { type = TokType.Number, text = s.Substring(start, i - start) }); + continue; + } + if (char.IsLetter(c) || c == '_') + { + int start = i; + while (i < s.Length && (char.IsLetterOrDigit(s[i]) || s[i] == '_')) i++; + outp.Add(new Token { type = TokType.Ident, text = s.Substring(start, i - start) }); + continue; + } + throw new Exception($"Invalid char in formula: '{c}'"); + } + // Handle unary plus/minus: when + or - appears at start or after operator or left paren + var fixedTokens = new List(); + for (int idx = 0; idx < outp.Count; idx++) + { + var t = outp[idx]; + if (t.type == TokType.Op && (t.text == "-" || t.text == "+")) + { + bool unary = (idx == 0) || (outp[idx - 1].type == TokType.Op) || (outp[idx - 1].type == TokType.LParen); + if (unary) + { + // insert 0 before unary +/- to convert unary into binary (0 +/- x) + fixedTokens.Add(new Token { type = TokType.Number, text = "0" }); + } + } + fixedTokens.Add(t); + } + return fixedTokens; + } + + private static int Precedence(string op) + { + if (op == "+" || op == "-") return 1; + if (op == "*" || op == "/") return 2; + return 0; + } + + private static List ToRPN(List tokens) + { + var output = new List(); + var stack = new Stack(); + foreach (var t in tokens) + { + if (t.type == TokType.Number || t.type == TokType.Ident) + { + output.Add(t); + } + else if (t.type == TokType.Op) + { + while (stack.Count > 0 && stack.Peek().type == TokType.Op && Precedence(stack.Peek().text) >= Precedence(t.text)) + { + output.Add(stack.Pop()); + } + stack.Push(t); + } + else if (t.type == TokType.LParen) + { + stack.Push(t); + } + else if (t.type == TokType.RParen) + { + while (stack.Count > 0 && stack.Peek().type != TokType.LParen) + { + output.Add(stack.Pop()); + } + if (stack.Count == 0) throw new Exception("Mismatched parentheses"); + stack.Pop(); // pop LParen + } + } + while (stack.Count > 0) + { + var tk = stack.Pop(); + if (tk.type == TokType.LParen || tk.type == TokType.RParen) throw new Exception("Mismatched parentheses"); + output.Add(tk); + } + return output; + } + + private static float EvalRPN(List rpn, Dictionary vars) + { + var st = new Stack(); + foreach (var t in rpn) + { + if (t.type == TokType.Number) + { + if (!float.TryParse(t.text, NumberStyles.Float, CultureInfo.InvariantCulture, out float v)) throw new Exception($"Invalid number '{t.text}'"); + st.Push(v); + } + else if (t.type == TokType.Ident) + { + if (vars != null && vars.TryGetValue(t.text, out float v)) st.Push(v); + else + { + // unknown identifiers treat as 0 but warn + Debug.LogWarning($"SkillDefinition: unknown variable '{t.text}' in formula, treated as 0"); + st.Push(0f); + } + } + else if (t.type == TokType.Op) + { + if (st.Count < 2) throw new Exception("Insufficient values for operator"); + float b = st.Pop(); float a = st.Pop(); + switch (t.text) + { + case "+": st.Push(a + b); break; + case "-": st.Push(a - b); break; + case "*": st.Push(a * b); break; + case "/": st.Push(a / b); break; + default: throw new Exception($"Unsupported operator {t.text}"); + } + } + else throw new Exception("Invalid token in RPN"); + } + if (st.Count != 1) throw new Exception("Invalid expression evaluation"); + return st.Pop(); + } +} diff --git a/Assets/scripts/Combat/SkillDefinition.cs.meta b/Assets/scripts/Combat/SkillDefinition.cs.meta new file mode 100644 index 00000000..334f3840 --- /dev/null +++ b/Assets/scripts/Combat/SkillDefinition.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 265d1552ebf55c34a98934707b2c20ce \ No newline at end of file diff --git a/Assets/scripts/Data/AllyHero_SO.cs b/Assets/scripts/Data/AllyHero_SO.cs new file mode 100644 index 00000000..eb0b9210 --- /dev/null +++ b/Assets/scripts/Data/AllyHero_SO.cs @@ -0,0 +1,107 @@ +using UnityEngine; +using System.Collections.Generic; + +[CreateAssetMenu(fileName = "NewAllyHero", menuName = "SO_Data/AllyHero")] +public class AllyHero_SO : ScriptableObject +{ + [Header("ѷӢۻϢ")] + public string ally_heroName; + public int ally_heroID; + + [Header("Ӣ")] + public Sprite ally_heroImage; + [Header("Ӣ۾ͷ")] + public Sprite ally_heroProfile; + [Header("Ӣ۹icon")] + public Sprite ally_heroIcon; + + [Header("ȼб")] + public List levelStats = new List(); + + [System.Serializable] + public class AllyLevelInfo + { + [Tooltip("ȼƻʶ")] + public string levelName; + public int levelID; + + [Tooltip("")] + public int attack = 0; + + [Tooltip("ֵ")] + public int maxHP = 100; + + [Tooltip("˺ (0..1), ڼ˺")] + public float damageResistance = 0f; + + [Tooltip("ֵ")] + public int maxMana = 100; + + [Tooltip("÷Ч")] + public float scoreEfficiency = 1f; + + [Tooltip("ȼ辭")] + public int requiredEXP; + + // --- ÿȼĹвڽ --- + [Header("Note-hit shared parameters")] + [Tooltip("Good жʱõķֵ")] + public int manaGainGood = 1; + [Tooltip("Great жʱõķֵ")] + public int manaGainGreat = 2; + [Tooltip("Perfect жʱõķֵ")] + public int manaGainPerfect = 3; + [Tooltip("Miss жʱõķֵ")] + public int manaGainOnMiss = 5; + + [Tooltip("Good жʱӢ۹˺ʣ 0.5 ʾ 50% Ļ˺")] + public float damageMultiplierGood = 0.5f; + [Tooltip("Great жʱӢ۹˺ʣ 0.75 ʾ 75% Ļ˺")] + public float damageMultiplierGreat = 0.75f; + [Tooltip("Perfect жʱӢ۹˺ʣ 1.0 ʾ 100% Ļ˺")] + public float damageMultiplierPerfect = 1f; + + [Tooltip("Miss ʱɵĻʧտѪ (missHpLossBase * (1 - damageResistance)) 㣬Կǿ")] + public float missHpLossBase = 10f; + } + + [Header("ǰ")] + public int ally_currentEXP; + + [Header("Skills")] + public SkillDefinition[] availableSkills; + [Tooltip("Indexes into availableSkills for preselected skills; empty means none selected")] + public int[] selectedSkillIndices = new int[0]; + + [Tooltip("Primary selected skill index into availableSkills (-1 = none)")] + public int primarySkillIndex = -1; + + public SkillDefinition GetPrimarySkill() + { + if (availableSkills == null || primarySkillIndex < 0 || primarySkillIndex >= availableSkills.Length) return null; + return availableSkills[primarySkillIndex]; + } + + // Return the AllyLevelInfo that corresponds to the current ally_currentEXP. + // Picks the highest level whose requiredEXP <= ally_currentEXP. If none match, returns levelStats[0] if present, otherwise null. + public AllyLevelInfo GetEffectiveLevelForCurrentEXP() + { + if (levelStats == null || levelStats.Count == 0) return null; + AllyLevelInfo best = null; + int currentExp = ally_currentEXP; + foreach (var lvl in levelStats) + { + if (lvl == null) continue; + if (best == null) + { + if (currentExp >= lvl.requiredEXP) best = lvl; + } + else + { + if (currentExp >= lvl.requiredEXP && lvl.requiredEXP >= best.requiredEXP) best = lvl; + } + } + if (best == null) return levelStats[0]; + return best; + } +} diff --git a/Assets/scripts/Data/AllyHero_SO.cs.meta b/Assets/scripts/Data/AllyHero_SO.cs.meta new file mode 100644 index 00000000..ccaa9719 --- /dev/null +++ b/Assets/scripts/Data/AllyHero_SO.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: bdd198d96872f3b42bdfc7e262ff2eed \ No newline at end of file diff --git a/Assets/scripts/Data/BossData_SO.cs b/Assets/scripts/Data/BossData_SO.cs new file mode 100644 index 00000000..caa22e60 --- /dev/null +++ b/Assets/scripts/Data/BossData_SO.cs @@ -0,0 +1,9 @@ +using UnityEngine; + +[CreateAssetMenu(fileName = "NewBossData", menuName = "SO_Data/BossData")] +public class BossData_SO : EnemyData_SO +{ + [Header("bossϢ")] + [Tooltip("ֵ")] + public int enemy_maxMana; +} diff --git a/Assets/scripts/Data/BossData_SO.cs.meta b/Assets/scripts/Data/BossData_SO.cs.meta new file mode 100644 index 00000000..56b5d5f8 --- /dev/null +++ b/Assets/scripts/Data/BossData_SO.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d5b254d6c08a7d94f99406da53f22341 \ No newline at end of file diff --git a/Assets/scripts/Data/EnemyData_SO.cs b/Assets/scripts/Data/EnemyData_SO.cs new file mode 100644 index 00000000..34714a56 --- /dev/null +++ b/Assets/scripts/Data/EnemyData_SO.cs @@ -0,0 +1,24 @@ +using UnityEngine; + +[CreateAssetMenu(fileName = "NewEnemyData", menuName = "SO_Data/EnemyData")] +public class EnemyData_SO : ScriptableObject +{ + [Header("Ϣ")] + [Tooltip("")] + public string enemyName; + public Sprite enemy_Image; + public Sprite enemy_Profile; + + [Tooltip("ID")] + public int enemyID; + + [Header("Stats")] + [Tooltip("ֵ")] + public int enemy_maxHP; + + [Tooltip("˺")] + public float enemy_damageResistance; + + [Tooltip("")] + public int enemy_baseAttack; +} diff --git a/Assets/scripts/Data/EnemyData_SO.cs.meta b/Assets/scripts/Data/EnemyData_SO.cs.meta new file mode 100644 index 00000000..b022759a --- /dev/null +++ b/Assets/scripts/Data/EnemyData_SO.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: a8cdb6ddbbe019f498476071245f3237 \ No newline at end of file diff --git a/Assets/scripts/Data/Player_SO.cs b/Assets/scripts/Data/Player_SO.cs new file mode 100644 index 00000000..2bbe41f3 --- /dev/null +++ b/Assets/scripts/Data/Player_SO.cs @@ -0,0 +1,12 @@ +using UnityEngine; + +[CreateAssetMenu(fileName = "PlayerDefaultSO", menuName = "SO_Data/PlayerSO")] +public class Player_SO : ScriptableObject +{ + [Header("Ϣ")] + public string player_name; + + public int player_ID; // steam ID + + public int player_EXP; +} \ No newline at end of file diff --git a/Assets/scripts/Data/Player_SO.cs.meta b/Assets/scripts/Data/Player_SO.cs.meta new file mode 100644 index 00000000..a7c99bae --- /dev/null +++ b/Assets/scripts/Data/Player_SO.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 27e379f45b1bb88449756219caee2f89 \ No newline at end of file diff --git a/Assets/scripts/Team/TeamSetting.cs b/Assets/scripts/Team/TeamSetting.cs index a6181f5e..cf6a432f 100644 --- a/Assets/scripts/Team/TeamSetting.cs +++ b/Assets/scripts/Team/TeamSetting.cs @@ -8,7 +8,8 @@ public class TeamSetting { public TeamSetting(List teamList, int leaderId) { - this.teamIdList = teamIdList; + // assign passed-in list to the backing field + this.teamIdList = teamList ?? new List(); LeaderId = leaderId; } diff --git a/Assets/scripts/UI/PauseManager.cs b/Assets/scripts/UI/PauseManager.cs index d26c4133..0a3a436e 100644 --- a/Assets/scripts/UI/PauseManager.cs +++ b/Assets/scripts/UI/PauseManager.cs @@ -1,5 +1,9 @@ using UnityEngine; using System; +using UnityEngine.SceneManagement; +#if UNITY_EDITOR +using UnityEditor; +#endif /// /// Simple pause manager. Call Pause(true) to pause or Pause(false) to resume. @@ -32,10 +36,30 @@ public class PauseManager : MonoBehaviour void Update() { + // Delete = immediate quit (stop play in editor or quit app) + if (Input.GetKeyDown(KeyCode.Delete)) + { +#if UNITY_EDITOR + EditorApplication.isPlaying = false; +#else + Application.Quit(); +#endif + return; + } + if (Input.GetKeyDown(KeyCode.Escape)) { TogglePause(); } + + // ͣ״̬Ұ Backspace ʱ + if (IsPaused && Input.GetKeyDown(KeyCode.Backspace)) + { + // ָʱ¼Ȼ + Pause(false); + // ȷĿеƥ + SceneManager.LoadScene("Main_main"); + } } /// diff --git a/Assets/scripts/gamePlay_gameplay/GameManager.cs b/Assets/scripts/gamePlay_gameplay/GameManager.cs index a1003ecc..f4726c5f 100644 --- a/Assets/scripts/gamePlay_gameplay/GameManager.cs +++ b/Assets/scripts/gamePlay_gameplay/GameManager.cs @@ -21,22 +21,39 @@ public class GameManager : MonoBehaviour [Header("Debug / Test")] public Text banflagTextUI; + private bool pauseSubscribed = false; + + private void SubscribeToPauseManager() + { + if (pauseSubscribed) return; + // prefer the singleton, but try to find in scene if null + var pm = PauseManager.Instance ?? FindObjectOfType(); + if (pm != null) + { + pm.OnPauseStateChanged += HandlePauseStateChanged; + pauseSubscribed = true; + } + } + + private void UnsubscribeFromPauseManager() + { + if (!pauseSubscribed) return; + var pm = PauseManager.Instance ?? FindObjectOfType(); + if (pm != null) + { + pm.OnPauseStateChanged -= HandlePauseStateChanged; + } + pauseSubscribed = false; + } + private void OnEnable() { - // ͣ¼ - if (PauseManager.Instance != null) - { - PauseManager.Instance.OnPauseStateChanged += HandlePauseStateChanged; - } + SubscribeToPauseManager(); } private void OnDisable() { - // ȡͣ¼ - if (PauseManager.Instance != null) - { - PauseManager.Instance.OnPauseStateChanged -= HandlePauseStateChanged; - } + UnsubscribeFromPauseManager(); } private void HandlePauseStateChanged(bool isPaused) @@ -282,7 +299,8 @@ public class GameManager : MonoBehaviour } // Pause the system until Space pressed - // Use PauseManager instead of directly setting Time.timeScale + // Ensure we are subscribed before invoking pause so we track audio state + SubscribeToPauseManager(); PauseManager.Instance?.Pause(true); UpdateStatusOnConsole("Paused: press Space to start playback"); diff --git a/Assets/scripts/gamePlay_gameplay/HoldNote.cs b/Assets/scripts/gamePlay_gameplay/HoldNote.cs index 89569b88..80c946c2 100644 --- a/Assets/scripts/gamePlay_gameplay/HoldNote.cs +++ b/Assets/scripts/gamePlay_gameplay/HoldNote.cs @@ -1,4 +1,5 @@ using System.Collections; +using System.Collections.Generic; using UnityEngine; public enum NoteSegment { None, Start, Middle, End } @@ -40,6 +41,8 @@ public class HoldNote : BaseNote [Header("判定区间配置")] public NoteJudgeConfig judgeConfig; // 判定区间配置,需在预制体或生成时赋值 + private bool _hasTriggeredOnThisHold = false; // ensure single trigger per hold note + private void Awake() { controller = GetComponent(); @@ -92,6 +95,8 @@ public class HoldNote : BaseNote { this.id = id; this.trackIndex = trackIndex; + // also set BaseNote.TrackIndex so other systems using TrackIndex property work consistently + this.TrackIndex = trackIndex; this.speed = speed; this.startTime = time; this.delay = delay; @@ -346,6 +351,28 @@ public class HoldNote : BaseNote JudgeManager.Instance.RegisterStartJudged(noteID, true); isHoldActive = true; // 成功判定Start,长按状态激活 PlayHitAnimation(); + + // Trigger skills configured to fire on note hits for this slot when the Start is successfully hit. + if (!_hasTriggeredOnThisHold) + { + try + { + Debug.Log($"[HoldNote] Triggering SkillBuilder on START for slot {trackIndex} with result={result}"); + // Prefer Hold type notification so skills expecting Hold can react. If it fails, fallback to Tap. + bool triggered = SkillBuilder.Instance?.NotifyNoteHit(this.trackIndex, result, SkillDefinition.NoteTypeTrigger.Hold) ?? false; + if (!triggered) + { + Debug.Log($"[HoldNote] START Hold notify did not trigger skill for slot {trackIndex}, trying Tap fallback"); + triggered = SkillBuilder.Instance?.NotifyNoteHit(this.trackIndex, result, SkillDefinition.NoteTypeTrigger.Tap) ?? false; + } + Debug.Log($"[HoldNote] START skill trigger result for slot {trackIndex}: {triggered}"); + } + catch (System.Exception ex) + { + Debug.LogError($"[HoldNote] NotifyNoteHit(Start) threw: {ex}"); + } + _hasTriggeredOnThisHold = true; // avoid triggering again at End + } } else { @@ -353,8 +380,26 @@ public class HoldNote : BaseNote Debug.Log($"[HoldNote] START Miss(偏差={offset:F2}秒): {noteColor}"); JudgeManager.Instance.RegisterStartJudged(noteID, false); // 明确标记未判定 isHoldActive = false; // Start Miss,长按状态不激活 + + // For Miss we should still notify shared logic once so it behaves like short notes + try + { + // Treat as Tap-type miss for compatibility + bool triggered = SkillBuilder.Instance?.NotifyNoteHit(this.trackIndex, result, SkillDefinition.NoteTypeTrigger.Tap) ?? false; + Debug.Log($"[HoldNote] START Miss NotifyNoteHit fired for slot {trackIndex}: {triggered}"); + } + catch (System.Exception ex) + { + Debug.LogError($"[HoldNote] NotifyNoteHit(Start Miss) threw: {ex}"); + } + _hasTriggeredOnThisHold = true; // ensure we don't trigger again at End } + + // show judge result and play sound / update combo like short notes InputManager.Instance?.ShowJudgeResult(trackIndex, result); + JudgeSoundManager.Instance?.PlayJudgeSound(result); + teamUIController.Instance?.OnJudgeResult(result); + StartCoroutine(DelayedReturn()); } @@ -442,6 +487,88 @@ public class HoldNote : BaseNote } InputManager.Instance?.ShowJudgeResult(trackIndex, result); teamUIController.Instance?.OnJudgeResult(result); // 新增:更新combo计数 + // Notify SkillBuilder so Hold notes can trigger skills configured for Hold + if (!_hasTriggeredOnThisHold) + { + var sb = SkillBuilder.Instance; + if (sb == null) + { + Debug.LogWarning($"[HoldNote] SkillBuilder.Instance is null when trying to notify for track {TrackIndex}"); + } + else + { + var so = sb.GetAllyHeroSOBySlot(TrackIndex); + var def = so?.GetPrimarySkill(); + Debug.Log($"[HoldNote] About to NotifyNoteHit: TrackIndex={TrackIndex} trackIndexField={trackIndex} so={(so!=null?so.name:"null")} skill={(def!=null?def.skillId:"null")} trigger={(def!=null?def.triggerCondition.ToString():"-")}"); + } + + bool triggeredHold = false; + bool triggeredTap = false; + + // Build candidate slot indices to try: prefer instance field, then BaseNote.TrackIndex, then try to match UI slots + var candidates = new List(); + candidates.Add(this.trackIndex); + if (!candidates.Contains(this.TrackIndex)) candidates.Add(this.TrackIndex); + // try to resolve by matching this object to UI slots + var ui = teamUIController.Instance; + if (ui != null) + { + for (int i = 0; i < ui.allySlotIds.Count; i++) + { + var slotObj = ui.GetAllyObjectBySlot(i); + if (slotObj == null) continue; + if (slotObj == this.gameObject || this.gameObject.transform.IsChildOf(slotObj.transform)) + { + if (!candidates.Contains(i)) candidates.Add(i); + break; + } + } + } + + Debug.Log($"[HoldNote] NotifyNoteHit candidate slots: {string.Join(",", candidates)}"); + + // Try each candidate: prefer Hold notification. Stop on first successful trigger. + foreach (var slot in candidates) + { + try + { + triggeredHold = SkillBuilder.Instance?.NotifyNoteHit(slot, result, SkillDefinition.NoteTypeTrigger.Hold) ?? false; + } + catch (System.Exception ex) + { + Debug.LogError($"[HoldNote] NotifyNoteHit(Hold) threw for slot {slot}: {ex}"); + } + if (triggeredHold) + { + Debug.Log($"[HoldNote] NotifyNoteHit succeeded (Hold) for slot {slot}"); + break; + } + } + + // If no candidate triggered via Hold, try Tap fallback on same candidate list + if (!triggeredHold) + { + foreach (var slot in candidates) + { + try + { + triggeredTap = SkillBuilder.Instance?.NotifyNoteHit(slot, result, SkillDefinition.NoteTypeTrigger.Tap) ?? false; + } + catch (System.Exception ex) + { + Debug.LogError($"[HoldNote] NotifyNoteHit(Tap) threw for slot {slot}: {ex}"); + } + if (triggeredTap) + { + Debug.Log($"[HoldNote] NotifyNoteHit succeeded (Tap fallback) for slot {slot}"); + break; + } + } + } + + _hasTriggeredOnThisHold = true; + Debug.Log($"[HoldNote] Hold end NotifyNoteHit called: TrackIndex={TrackIndex} trackIndexField={trackIndex} result={result} triggeredHold={triggeredHold} triggeredTap={triggeredTap}"); + } Debug.Log($"[HoldNote] END判定结果: {noteColor} {result} (release={releaseTime:F2}, target={scheduledEndTime:F2})"); ReturnToPool(); } @@ -507,6 +634,7 @@ public class HoldNote : BaseNote isJudged = false; isHoldActive = false; // 重置长按标记 hasBeenHeldFromStart = false; // 重置 + _hasTriggeredOnThisHold = false; // 重置 if (autoReturnCoroutine != null) { diff --git a/Assets/scripts/gamePlay_gameplay/JudgeSoundManager.cs b/Assets/scripts/gamePlay_gameplay/JudgeSoundManager.cs new file mode 100644 index 00000000..64297ba0 --- /dev/null +++ b/Assets/scripts/gamePlay_gameplay/JudgeSoundManager.cs @@ -0,0 +1,123 @@ +using UnityEngine; + +/// +/// Centralized judge sound player. Assign four AudioSources (one per judgement) in the Inspector. +/// Designed to be low-latency: each judgement has a dedicated AudioSource and PlayOneShot is used. +/// Place this component on a persistent gameobject in the scene (or your audio container). +/// +public class JudgeSoundManager : MonoBehaviour +{ + public static JudgeSoundManager Instance { get; private set; } + + [Header("AudioSources (assign dedicated AudioSource for each judgement)")] + public AudioSource perfectSource; + public AudioSource greatSource; + public AudioSource goodSource; + public AudioSource missSource; + + [Header("Enable/Disable per-judgement playback")] + [Tooltip("Toggle whether Perfect sounds are played")] + public bool enablePerfect = true; + [Tooltip("Toggle whether Great sounds are played")] + public bool enableGreat = true; + [Tooltip("Toggle whether Good sounds are played")] + public bool enableGood = true; + [Tooltip("Toggle whether Miss sounds are played")] + public bool enableMiss = true; + + [Header("Fallback clips (optional, used if the assigned AudioSource has no clip)")] + public AudioClip perfectClip; + public AudioClip greatClip; + public AudioClip goodClip; + public AudioClip missClip; + + private void Awake() + { + if (Instance == null) + { + Instance = this; + // Do not automatically destroy; leave lifecycle to scene management + } + else + { + Destroy(gameObject); + return; + } + + // Ensure AudioSources are configured for low latency + ConfigureSource(perfectSource); + ConfigureSource(greatSource); + ConfigureSource(goodSource); + ConfigureSource(missSource); + } + + private void ConfigureSource(AudioSource src) + { + if (src == null) return; + src.playOnAwake = false; + // keep 3D off for UI/flat sounds + src.spatialBlend = 0f; + // ensure not looping + src.loop = false; + } + + public enum JudgeResult { Perfect, Great, Good, Miss } + + public void PlayJudgeSound(string result) + { + if (string.IsNullOrEmpty(result)) return; + switch (result) + { + case "Perfect": PlayJudgeSound(JudgeResult.Perfect); break; + case "Great": PlayJudgeSound(JudgeResult.Great); break; + case "Good": PlayJudgeSound(JudgeResult.Good); break; + case "Miss": PlayJudgeSound(JudgeResult.Miss); break; + default: break; + } + } + + public void PlayJudgeSound(JudgeResult r) + { + // honor inspector toggles to allow disabling specific judgement sounds + switch (r) + { + case JudgeResult.Perfect: + if (!enablePerfect) return; + PlayOnSource(perfectSource, perfectClip); + break; + case JudgeResult.Great: + if (!enableGreat) return; + PlayOnSource(greatSource, greatClip); + break; + case JudgeResult.Good: + if (!enableGood) return; + PlayOnSource(goodSource, goodClip); + break; + case JudgeResult.Miss: + if (!enableMiss) return; + PlayOnSource(missSource, missClip); + break; + } + } + + private void PlayOnSource(AudioSource src, AudioClip fallbackClip) + { + if (src != null) + { + // Prefer PlayOneShot so sources can overlap and we don't need to manage clip state + if (src.clip != null) + { + src.PlayOneShot(src.clip); + } + else if (fallbackClip != null) + { + src.PlayOneShot(fallbackClip); + } + } + else if (fallbackClip != null) + { + // no dedicated source provided: play via a temporary one-shot using AudioSource.PlayClipAtPoint at camera position + AudioSource.PlayClipAtPoint(fallbackClip, Camera.main != null ? Camera.main.transform.position : Vector3.zero); + } + } +} diff --git a/Assets/scripts/gamePlay_gameplay/JudgeSoundManager.cs.meta b/Assets/scripts/gamePlay_gameplay/JudgeSoundManager.cs.meta new file mode 100644 index 00000000..2c6b5ceb --- /dev/null +++ b/Assets/scripts/gamePlay_gameplay/JudgeSoundManager.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: a7692a74982af114ca6d79307fc43676 \ No newline at end of file diff --git a/Assets/scripts/gamePlay_gameplay/Note.cs b/Assets/scripts/gamePlay_gameplay/Note.cs index f93ebd82..6ace12d3 100644 --- a/Assets/scripts/gamePlay_gameplay/Note.cs +++ b/Assets/scripts/gamePlay_gameplay/Note.cs @@ -76,22 +76,18 @@ public class Note : BaseNote { Debug.Log($"{keyToPress}: Miss"); judgeResult = "Miss"; - InputManager.Instance?.ShowJudgeResult(TrackIndex, judgeResult); - JudgeMiss(); - return; + // Do not return here - let shared post-judge logic run so NotifyNoteHit is invoked for Miss as well } else { Debug.Log($"{keyToPress}: Miss"); judgeResult = "Miss"; - InputManager.Instance?.ShowJudgeResult(TrackIndex, judgeResult); - JudgeMiss(); - return; + // Do not return here - let shared post-judge logic run so NotifyNoteHit is invoked for Miss as well } } else { - // ݾ߼ + // fallback timing if (timeDifference <= 0.08f) { Debug.Log($"{keyToPress}: Perfect"); @@ -106,17 +102,18 @@ public class Note : BaseNote { Debug.Log($"{keyToPress}: Miss"); judgeResult = "Miss"; - InputManager.Instance?.ShowJudgeResult(TrackIndex, judgeResult); - JudgeMiss(); - return; + // Do not return here - let shared post-judge logic run so NotifyNoteHit is invoked for Miss as well } } - // ʾжı + // ʾжϢ if (!string.IsNullOrEmpty(judgeResult)) { InputManager.Instance?.ShowJudgeResult(TrackIndex, judgeResult); - teamUIController.Instance?.OnJudgeResult(judgeResult); // combo + JudgeSoundManager.Instance?.PlayJudgeSound(judgeResult); + teamUIController.Instance?.OnJudgeResult(judgeResult); // combo + // Notify SkillBuilder about this note hit so OnNoteHit skills may trigger (tap notes) + try { SkillBuilder.Instance?.NotifyNoteHit(TrackIndex, judgeResult, SkillDefinition.NoteTypeTrigger.Tap); } catch { } } Judge(); } @@ -152,7 +149,10 @@ public class Note : BaseNote Debug.Log($"{keyToPress} Miss"); // Ensure UI shows Miss and combo is updated when a note auto-misses InputManager.Instance?.ShowJudgeResult(TrackIndex, "Miss"); + JudgeSoundManager.Instance?.PlayJudgeSound("Miss"); teamUIController.Instance?.OnJudgeResult("Miss"); + // Notify SkillBuilder about Miss so OnNoteHit skills configured for Miss can trigger + try { SkillBuilder.Instance?.NotifyNoteHit(TrackIndex, "Miss", SkillDefinition.NoteTypeTrigger.Tap); } catch { } // InputManager.Instance?.ShowJudgeResult(TrackIndex, "Miss"); // HandlePressе for manual presses ReturnToPool(); } @@ -188,6 +188,7 @@ public class Note : BaseNote { // Show Miss and update combo InputManager.Instance?.ShowJudgeResult(TrackIndex, "Miss"); + JudgeSoundManager.Instance?.PlayJudgeSound("Miss"); teamUIController.Instance?.OnJudgeResult("Miss"); JudgeMiss(); } diff --git a/Assets/scripts/gamePlay_gameplay/NoteJudgeConfig.cs b/Assets/scripts/gamePlay_gameplay/NoteJudgeConfig.cs index d24965f9..cd4f62ca 100644 --- a/Assets/scripts/gamePlay_gameplay/NoteJudgeConfig.cs +++ b/Assets/scripts/gamePlay_gameplay/NoteJudgeConfig.cs @@ -7,12 +7,12 @@ using UnityEngine; public class NoteJudgeConfig : ScriptableObject { [Header("ж䣨λ룩")] - [Tooltip("Perfect жʱƫ")] + [Tooltip("Perfect")] public float perfectRange = 0.05f; - [Tooltip("Great жʱƫ")] + [Tooltip("Great")] public float greatRange = 0.1f; - [Tooltip("Good жʱƫ")] + [Tooltip("Good")] public float goodRange = 0.2f; - [Tooltip("Miss жʱƫ")] + [Tooltip("Miss")] public float missRange = 0.3f; } diff --git a/Assets/scripts/gamePlay_gameplay/NoteSpawner.cs b/Assets/scripts/gamePlay_gameplay/NoteSpawner.cs index acbc27c7..699468af 100644 --- a/Assets/scripts/gamePlay_gameplay/NoteSpawner.cs +++ b/Assets/scripts/gamePlay_gameplay/NoteSpawner.cs @@ -18,6 +18,10 @@ public class NoteSpawner : MonoBehaviour public float spawnOffset = 0f; // 生成音符时的时间偏移量 public float bpm; + [Header("Global timing adjustments")] + [Tooltip("Global additional realtime offset (seconds) added to hit times for all notes. Use to test input latency or adjust judgement timing. Default 0. Can be negative to make notes arrive earlier.")] + public float globalHitDelay = 0f; + public NoteJudgeConfig judgeConfig; // 判定区间配置,需在 Inspector 赋值 private Beatmap beatmap; @@ -108,8 +112,9 @@ public class NoteSpawner : MonoBehaviour if (noteScript != null) { float noteSpawnTime = Time.time; - // pass realtime hit time to Note.Setup - float realtimeHit = startTime + noteData.time; + // pass realtime hit time to Note.Setup, include globalHitDelay + float rawHit = startTime + noteData.time + globalHitDelay; + float realtimeHit = Mathf.Max(0f, rawHit); // clamp to non-negative noteScript.Setup(key, noteData.trackIndex, CalculateSpeed(), realtimeHit, noteData.color, judgeConfig); if (GameConfig.verboseLogs) Debug.Log($"到达时间:{noteSpawnTime + (60f / bpm) * 4}"); } @@ -152,7 +157,8 @@ public class NoteSpawner : MonoBehaviour Transform spawnPoint = spawnPoints[noteData.trackIndex]; // scheduledEndTime 使用谱面时间(note.time + length),但转换为实时 - float scheduledEndTime = startTime + (noteData.time + noteData.length); + float rawScheduledEnd = startTime + (noteData.time + noteData.length) + globalHitDelay; + float scheduledEndTime = Mathf.Max(0f, rawScheduledEnd); // clamp to non-negative // 生成唯一 id(改为自增计数器,避免随机冲突) int holdNoteId = ++holdNoteIdCounter; @@ -170,8 +176,10 @@ public class NoteSpawner : MonoBehaviour HoldNote holdNote = startObj.GetComponent(); if (holdNote != null) { - // pass realtime hit time (startTime + note.time) and delay 0 - holdNote.Setup(holdNoteId, noteData.trackIndex, CalculateSpeed(), startTime + noteData.time, 0f, false, scheduledEndTime, noteData.color, key, "start", judgeConfig); + // pass realtime hit time (startTime + note.time) and delay 0, include globalHitDelay + float rawStartHit = startTime + noteData.time + globalHitDelay; + float startHit = Mathf.Max(0f, rawStartHit); + holdNote.Setup(holdNoteId, noteData.trackIndex, CalculateSpeed(), startHit, 0f, false, scheduledEndTime, noteData.color, key, "start", judgeConfig); } else { @@ -198,7 +206,9 @@ public class NoteSpawner : MonoBehaviour if (holdSeg != null) { // 中段都标记为 middle,pass realtime base time and segmentDelay - holdSeg.Setup(holdNoteId, noteData.trackIndex, CalculateSpeed(), startTime + noteData.time, segmentDelay, false, scheduledEndTime, noteData.color, key, "middle", judgeConfig); + float rawBase = startTime + noteData.time + globalHitDelay; + float baseHit = Mathf.Max(0f, rawBase); + holdSeg.Setup(holdNoteId, noteData.trackIndex, CalculateSpeed(), baseHit, segmentDelay, false, scheduledEndTime, noteData.color, key, "middle", judgeConfig); } else { @@ -226,7 +236,9 @@ public class NoteSpawner : MonoBehaviour { // 将 delay 设置为整个 hold 长度 (或 segmentCount * actualSegmentInterval),确保尾部在最后中段之后 float endDelay = segmentCount * actualSegmentInterval; // 通常等于 noteData.length - holdEnd.Setup(holdNoteId, noteData.trackIndex, CalculateSpeed(), startTime + noteData.time, endDelay, true, scheduledEndTime, noteData.color, key, "end", judgeConfig); + float rawBase = startTime + noteData.time + globalHitDelay; + float baseHit = Mathf.Max(0f, rawBase); + holdEnd.Setup(holdNoteId, noteData.trackIndex, CalculateSpeed(), baseHit, endDelay, true, scheduledEndTime, noteData.color, key, "end", judgeConfig); } else { diff --git a/Assets/scripts/gameplay_teamUI/teamUIController.cs b/Assets/scripts/gameplay_teamUI/teamUIController.cs index 079fe4f8..c5c42cae 100644 --- a/Assets/scripts/gameplay_teamUI/teamUIController.cs +++ b/Assets/scripts/gameplay_teamUI/teamUIController.cs @@ -1,6 +1,10 @@ using UnityEngine; using UnityEngine.UI; using TMPro; +using System.Collections.Generic; +#if UNITY_EDITOR +using UnityEditor; +#endif public class teamUIController : MonoBehaviour { @@ -9,6 +13,480 @@ public class teamUIController : MonoBehaviour private set; } + // --- ID бϵ 5 Ѿ --- + [Header("Runtime ally configuration")] + [Tooltip("IDs for the 5 ally slots (top to bottom). These are used by PopulateAllySOsFromIds to resolve SOs into currentAllySOs.")] + public List allySlotIds = new List { 0, 0, 0, 0, 0 }; + + // --- ĵǰ SO ã˳ --- + private TeamCharacterDataInfo[] currentAllySOs = new TeamCharacterDataInfo[5]; + + // previous active flags for detecting external changes + private bool[] prevAllyActive = new bool[5]; + + // ·ֶΣһڱ༭ңд Assets/Resources/so/ally ̾· + // һʱңResources · so/ally + [Header("SO folder paths")] + [Tooltip("Editor-only: project path or absolute disk path to the folder that contains SOs. Example: Assets/Resources/so/ally")] + public string editorSOFolderPath = "Assets/Resources/so/ally"; + + [Tooltip("Runtime: Resources subfolder path (no 'Resources/' prefix). Example: so/ally")] + public string runtimeResourcesFolderPath = "so/ally"; + + // Optional per-ally object to toggle together with isAllyX_active. If null falls back to objectFather_allyXX. + [Header("Ally runtime objects (optional)")] + public GameObject ally01_object; + public GameObject ally02_object; + public GameObject ally03_object; + public GameObject ally04_object; + public GameObject ally05_object; + + // ݾֶΣѡ + [Header("Editor folder load (Editor only)")] + [Tooltip("Deprecated: kept for compatibility. Use editorSOFolderPath or runtimeResourcesFolderPath instead.")] + public string selectedProjectFolderPath = string.Empty; + + /// + /// /༭еã allySlotIds5 intָļӦ TeamCharacterDataInfo ʲ + /// Editor: ʹ editorSOFolderPath / selectedProjectFolderPathRuntime: ʹ runtimeResourcesFolderPath / selectedProjectFolderPath + /// + public void PopulateAllySOsFromIds() + { + if (allySlotIds == null || allySlotIds.Count < 5) + { + Debug.LogWarning("allySlotIds δȷãԶΪ 5 ռλ ID"); + allySlotIds = new List { 0, 0, 0, 0, 0 }; + } + +#if UNITY_EDITOR + // Choose editor folder path preferentially from editorSOFolderPath, fallback to selectedProjectFolderPath + string folderToUse = !string.IsNullOrEmpty(editorSOFolderPath) ? editorSOFolderPath : selectedProjectFolderPath; + + // Ensure folderToUse points inside the project Assets folder when possible + string projectRelative = null; + if (!string.IsNullOrEmpty(folderToUse)) + { + string projectPath = folderToUse.Replace("\\", "/"); + if (projectPath.StartsWith(Application.dataPath)) + { + projectRelative = "Assets" + projectPath.Substring(Application.dataPath.Length); + } + else if (projectPath.StartsWith("Assets/")) + { + projectRelative = projectPath; + } + else + { + Debug.LogWarning("editorSOFolderPath λĿ Assets ļԱвѯд Assets/Resources/so/ally˵ȫбҡ·ҲдΪ̾·"); + } + } + + // Collect TeamCharacterDataInfo and AllyHero_SO assets under the folder (or project-wide) + List discovered = new List(); + if (!string.IsNullOrEmpty(projectRelative)) + { + string[] guids = AssetDatabase.FindAssets("t:TeamCharacterDataInfo", new[] { projectRelative }); + foreach (var g in guids) + { + string assetPath = AssetDatabase.GUIDToAssetPath(g); + var so = AssetDatabase.LoadAssetAtPath(assetPath); + if (so != null) discovered.Add(so); + } + string[] guids2 = AssetDatabase.FindAssets("t:AllyHero_SO", new[] { projectRelative }); + foreach (var g in guids2) + { + string assetPath = AssetDatabase.GUIDToAssetPath(g); + var so = AssetDatabase.LoadAssetAtPath(assetPath); + if (so != null) discovered.Add(so); + } + } + else + { + // no valid folder chosen -> search entire project + string[] guids = AssetDatabase.FindAssets("t:TeamCharacterDataInfo"); + foreach (var g in guids) + { + string assetPath = AssetDatabase.GUIDToAssetPath(g); + var so = AssetDatabase.LoadAssetAtPath(assetPath); + if (so != null) discovered.Add(so); + } + string[] guids2 = AssetDatabase.FindAssets("t:AllyHero_SO"); + foreach (var g in guids2) + { + string assetPath = AssetDatabase.GUIDToAssetPath(g); + var so = AssetDatabase.LoadAssetAtPath(assetPath); + if (so != null) discovered.Add(so); + } + } + + TeamCharacterList globalList = null; + if (teamSettingPanel.Instance != null) + globalList = teamSettingPanel.Instance.teamCharacterList; + + for (int i = 0; i < 5; i++) + { + int id = allySlotIds[i]; + TeamCharacterDataInfo found = null; + + // slot ID Ϊ 0 -> رնӦ ally UI + if (id == 0) + { + currentAllySOs[i] = null; + switch (i) + { + case 0: isAlly01_active = false; break; + case 1: isAlly02_active = false; break; + case 2: isAlly03_active = false; break; + case 3: isAlly04_active = false; break; + case 4: isAlly05_active = false; break; + } + ToggleAllyObject(i, false); + Debug.Log($"[teamUIController] slot {i+1} id=0 -> disabled"); + continue; + } + + // ֻҪ asset ·ư id ãEditor + for (int j = 0; j < discovered.Count; j++) + { + var obj = discovered[j]; + if (obj == null) continue; + string path = AssetDatabase.GetAssetPath(obj); + if (!string.IsNullOrEmpty(path) && path.Contains(id.ToString())) + { + // if it's already TeamCharacterDataInfo, use it + if (obj is TeamCharacterDataInfo tc) + { + found = tc; + Debug.Log($"[teamUIController] (Editor) matched asset by path: {path} for id={id} slot={i+1}"); + break; + } + // if it's AllyHero_SO, map to a runtime TeamCharacterDataInfo instance + if (obj is AllyHero_SO ah) + { + var mapped = ScriptableObject.CreateInstance(); + mapped.CharacterID = ah.ally_heroID; + mapped.CharacterName = ah.ally_heroName; + mapped.CharacterCardSprite = ah.ally_heroImage; + mapped.CharacterTeamSprite = ah.ally_heroProfile; + mapped.name = ah.name; + found = mapped; + Debug.Log($"[teamUIController] (Editor) matched AllyHero_SO by path: {path} for id={id} slot={i+1}"); + break; + } + } + } + + // ˵ȫ teamCharacterList + if (found == null && globalList != null && globalList.characters != null) + { + for (int j = 0; j < globalList.characters.Count; j++) + { + var so = globalList.characters[j]; + if (so == null) continue; + // globalList Ҳ name id Ϊ׼ + if (!string.IsNullOrEmpty(so.name) && so.name.Contains(id.ToString())) + { + found = so; + break; + } + } + } + + currentAllySOs[i] = found; + + if (found == null) + { + Debug.LogWarning($"[teamUIController] δҵ id={id} Ӧ SO (slot {i + 1})"); + // disable UI slot when not found + switch (i) + { + case 0: isAlly01_active = false; break; + case 1: isAlly02_active = false; break; + case 2: isAlly03_active = false; break; + case 3: isAlly04_active = false; break; + case 4: isAlly05_active = false; break; + } + ToggleAllyObject(i, false); + } + else + { + Debug.Log($"[teamUIController] (Editor) slot {i + 1} resolved to SO: {found.name} (id={found.CharacterID})"); + // ȷӦ UI slot + switch (i) + { + case 0: isAlly01_active = true; break; + case 1: isAlly02_active = true; break; + case 2: isAlly03_active = true; break; + case 3: isAlly04_active = true; break; + case 4: isAlly05_active = true; break; + } + ToggleAllyObject(i, true); + DebugCharacterSO(found, i+1, true); + // Also attempt to set the teammate character image from an underlying AllyHero_SO if available + try + { + // first try to find AllyHero_SO by the same id + var ahList = Resources.LoadAll(""); + AllyHero_SO matched = null; + foreach (var a in ahList) if (a != null && a.ally_heroID == id) { matched = a; break; } + if (matched != null) + { + var sprite = matched.ally_heroProfile != null ? matched.ally_heroProfile : matched.ally_heroImage; + SetTeammateCharacterImage(i, sprite); + } + else + { + // fallback: if current TeamCharacterDataInfo has a TeamSprite, use that + var tc = found as TeamCharacterDataInfo; + if (tc != null && tc.CharacterTeamSprite != null) + SetTeammateCharacterImage(i, tc.CharacterTeamSprite); + } + } + catch { } + } + } +#else + // Runtime: prefer runtimeResourcesFolderPath, fallback to selectedProjectFolderPath + string resourcesPath = ResolveResourcesRelativePath(!string.IsNullOrEmpty(runtimeResourcesFolderPath) ? runtimeResourcesFolderPath : selectedProjectFolderPath); + + List runtimeDiscovered = new List(); + if (!string.IsNullOrEmpty(resourcesPath)) + { + resourcesPath = resourcesPath.Trim('/'); + try + { + var arr = Resources.LoadAll(resourcesPath); + if (arr != null && arr.Length > 0) + runtimeDiscovered.AddRange(arr); + + // If nothing loaded from the specific folder, fallback to loading all and filter by name later + if (runtimeDiscovered.Count == 0) + { + var arrAll = Resources.LoadAll(""); + if (arrAll != null && arrAll.Length > 0) + { + runtimeDiscovered.AddRange(arrAll); + Debug.LogWarning($"[teamUIController] (Runtime) Resources.LoadAll returned 0 in '{resourcesPath}', fell back to loading all ScriptableObjects ({arrAll.Length})"); + } + } + + Debug.Log($"[teamUIcontroller] (Runtime) Loaded {runtimeDiscovered.Count} objects from Resources/{resourcesPath}"); + } + catch (System.Exception ex) + { + Debug.LogWarning($"[teamUIController] (Runtime) Resources.LoadAll failed for '{resourcesPath}': {ex.Message}"); + var arrAll = Resources.LoadAll(""); + if (arrAll != null && arrAll.Length > 0) + runtimeDiscovered.AddRange(arrAll); + } + } + else + { + var arr = Resources.LoadAll(""); + if (arr != null && arr.Length > 0) + runtimeDiscovered.AddRange(arr); + Debug.Log($"[teamUIController] (Runtime) Loaded {arr?.Length ?? 0} objects from Resources (project-wide)"); + } + + TeamCharacterList globalList = null; + if (teamSettingPanel.Instance != null) + globalList = teamSettingPanel.Instance.teamCharacterList; + + for (int i = 0; i < 5; i++) + { + int id = allySlotIds[i]; + TeamCharacterDataInfo found = null; + + // slot ID Ϊ 0 -> رնӦ ally UI + if (id == 0) + { + currentAllySOs[i] = null; + switch (i) + { + case 0: isAlly01_active = false; break; + case 1: isAlly02_active = false; break; + case 2: isAlly03_active = false; break; + case 3: isAlly04_active = false; break; + case 4: isAlly05_active = false; break; + } + // also toggle associated object + ToggleAllyObject(i, false); + + Debug.Log($"[teamUIController] (Runtime) slot {i+1} id=0 -> disabled"); + continue; + } + + // ֻҪԴ id ãRuntime֧ TeamCharacterDataInfo AllyHero_SO + string runtimeSourceInfo = string.Empty; + for (int j = 0; j < runtimeDiscovered.Count; j++) + { + var obj = runtimeDiscovered[j]; + if (obj == null) continue; + // name match first + if (!string.IsNullOrEmpty(obj.name) && obj.name.Contains(id.ToString())) + { + if (obj is TeamCharacterDataInfo tc) + { + found = tc; break; + } + if (obj is AllyHero_SO ah) + { + var mapped = ScriptableObject.CreateInstance(); + mapped.CharacterID = ah.ally_heroID; + mapped.CharacterName = ah.ally_heroName; + mapped.CharacterCardSprite = ah.ally_heroImage; + mapped.CharacterTeamSprite = ah.ally_heroProfile; + found = mapped; break; + } + } + + // fallback: if object is TeamCharacterDataInfo, check its CharacterID + if (obj is TeamCharacterDataInfo tco && tco.CharacterID == id) + { + found = tco; break; + } + // fallback: AllyHero_SO CharacterID equivalent + if (obj is AllyHero_SO ah2 && ah2.ally_heroID == id) + { + var mapped2 = ScriptableObject.CreateInstance(); + mapped2.CharacterID = ah2.ally_heroID; + mapped2.CharacterName = ah2.ally_heroName; + mapped2.CharacterCardSprite = ah2.ally_heroImage; + mapped2.CharacterTeamSprite = ah2.ally_heroProfile; + found = mapped2; break; + } + } + + // ˵ȫ teamCharacterList + if (found == null && globalList != null && globalList.characters != null) + { + for (int j = 0; j < globalList.characters.Count; j++) + { + var so = globalList.characters[j]; + if (so == null) continue; + if (!string.IsNullOrEmpty(so.name) && so.name.Contains(id.ToString())) + { + found = so; + break; + } + if (so.CharacterID == id) + { + found = so; + break; + } + } + } + + // final fallback: try loading by resource path/id if resourcesPath provided + if (found == null && !string.IsNullOrEmpty(resourcesPath)) + { + try + { + var byId = Resources.Load($"{resourcesPath}/{id}"); + if (byId != null) found = byId; + if (found != null) runtimeSourceInfo = $"Resources.Load: {resourcesPath}/{id}"; + } + catch { } + } + + currentAllySOs[i] = found; + + if (found == null) + { + Debug.LogWarning($"[teamUIController] (Runtime) δҵ id={id} Ӧ SO (slot {i + 1})"); + switch (i) + { + case 0: isAlly01_active = false; break; + case 1: isAlly02_active = false; break; + case 2: isAlly03_active = false; break; + case 3: isAlly04_active = false; break; + case 4: isAlly05_active = false; break; + } + ToggleAllyObject(i, false); + } + else + { + // try to get a readable source for the matched object + if (string.IsNullOrEmpty(runtimeSourceInfo)) + { + runtimeSourceInfo = found.name + " (mapped)"; + } + Debug.Log($"[teamUIcontroller] (Runtime) slot {i + 1} resolved to SO: {found.name} (id={found.CharacterID}) Source={runtimeSourceInfo}"); + switch (i) + { + case 0: isAlly01_active = true; break; + case 1: isAlly02_active = true; break; + case 2: isAlly03_active = true; break; + case 3: isAlly04_active = true; break; + case 4: isAlly05_active = true; break; + } + ToggleAllyObject(i, true); + DebugCharacterSO(found, i+1, false); + // attempt to set teammate image from underlying AllyHero_SO if possible + try + { + var ahList = Resources.LoadAll(""); + AllyHero_SO matched = null; + foreach (var a in ahList) if (a != null && a.ally_heroID == id) { matched = a; break; } + if (matched != null) + { + var sprite = matched.ally_heroProfile != null ? matched.ally_heroProfile : matched.ally_heroImage; + SetTeammateCharacterImage(i, sprite); + } + else + { + var tc = found as TeamCharacterDataInfo; + if (tc != null && tc.CharacterTeamSprite != null) + SetTeammateCharacterImage(i, tc.CharacterTeamSprite); + } + } + catch { } + } + } +#endif + } + + // Resolve various forms of selectedProjectFolderPath into a Resources.Load relative path (no 'Resources/' prefix, no extension) + private string ResolveResourcesRelativePath(string selectedPath) + { + if (string.IsNullOrEmpty(selectedPath)) return string.Empty; + string p = selectedPath.Replace("\\", "/"); + // If user provided a path starting with "Assets/Resources/", strip to get relative + int idx = p.IndexOf("Assets/Resources/"); + if (idx >= 0) + { + return p.Substring(idx + "Assets/Resources/".Length).Trim('/'); + } + // If user provided an absolute path that contains Application.dataPath and Resources + string appData = Application.dataPath.Replace("\\", "/"); + idx = p.IndexOf(appData + "/Resources/"); + if (idx >= 0) + { + return p.Substring((appData + "/Resources/").Length).Trim('/'); + } + // If user already provided a Resources relative path (like "so/ally"), return it trimmed + if (p.StartsWith("Resources/")) p = p.Substring("Resources/".Length); + return p.Trim('/'); + } + + // Debug helper to print key fields of a TeamCharacterDataInfo + private void DebugCharacterSO(TeamCharacterDataInfo so, int slotIndex, bool isEditor) + { + if (so == null) return; + string mode = isEditor ? "Editor" : "Runtime"; + string spriteCard = so.CharacterCardSprite != null ? so.CharacterCardSprite.name : "(null)"; + string spriteTeam = so.CharacterTeamSprite != null ? so.CharacterTeamSprite.name : "(null)"; + Debug.Log($"[teamUIController] ({mode}) Slot {slotIndex} -> CharacterID={so.CharacterID}, Name={so.CharacterName}, Skill={so.CharacterSkillName}, MaxHealth={so.CharacterMaxHealth}, CardSprite={spriteCard}, TeamSprite={spriteTeam}"); + } + + /// + /// صǰ SO б鸱 + /// + public TeamCharacterDataInfo[] GetCurrentAllySOs() + { + return (TeamCharacterDataInfo[])currentAllySOs.Clone(); + } + [Header("ı")] [Tooltip("title")] public TextMeshProUGUI songNametitle; @@ -22,7 +500,7 @@ public class teamUIController : MonoBehaviour [SerializeField] private int enemyCounterMax; // Ϸ [SerializeField] private int enemyCurrentCount; // ڵĵ˳ [Tooltip("ǰܷ")] - public Text currentTotalScore; + public TextMeshProUGUI currentTotalScore; [Header("ComboжҪ")] public ComboJudgeType comboJudgeType = ComboJudgeType.Perfect; @@ -232,13 +710,32 @@ public class teamUIController : MonoBehaviour // Start is called once before the first execution of Update after the MonoBehaviour is created void Start() { + PopulateAllySOsFromIds(); + // initialize previous flags so Update can detect changes + prevAllyActive[0] = isAlly01_active; + prevAllyActive[1] = isAlly02_active; + prevAllyActive[2] = isAlly03_active; + prevAllyActive[3] = isAlly04_active; + prevAllyActive[4] = isAlly05_active; + + // Ensure score text references are resolved so ScoreManager and AllyCombatant can write to them + ResolveScoreTextReferences(); } // Update is called once per frame void Update() { - + // detect external changes to isAllyX_active and toggle objects accordingly + bool[] current = new bool[] { isAlly01_active, isAlly02_active, isAlly03_active, isAlly04_active, isAlly05_active }; + for (int i = 0; i < 5; i++) + { + if (prevAllyActive[i] != current[i]) + { + ToggleAllyObject(i, current[i]); + prevAllyActive[i] = current[i]; + } + } } private void FixedUpdate() @@ -289,5 +786,108 @@ public class teamUIController : MonoBehaviour } } - + // helper to toggle ally object by slot index + private void ToggleAllyObject(int slotIndex, bool active) + { + GameObject target = null; + switch (slotIndex) + { + case 0: target = ally01_object ?? objectFather_ally01; break; + case 1: target = ally02_object ?? objectFather_ally02; break; + case 2: target = ally03_object ?? objectFather_ally03; break; + case 3: target = ally04_object ?? objectFather_ally04; break; + case 4: target = ally05_object ?? objectFather_ally05; break; + } + if (target != null) + target.SetActive(active); + } + + // Try to ensure the teammateXX_current_scoreText fields are assigned; if null, search the corresponding parent for TMP/Text + private void ResolveScoreTextReferences() + { + void TryResolve(ref TextMeshProUGUI field, GameObject parent, string slotName) + { + if (field != null) return; + if (parent != null) + { + var tmp = parent.GetComponentInChildren(true); + if (tmp != null) + { + field = tmp; + Debug.Log($"[teamUIController] Resolved {slotName} TMP from parent {parent.name} -> {tmp.gameObject.name}"); + return; + } + var legacy = parent.GetComponentInChildren(true); + if (legacy != null) + { + // if only legacy Text exists, try to create a TMP component to avoid type mismatch + var go = legacy.gameObject; + var created = go.GetComponent() ?? go.AddComponent(); + created.text = legacy.text; + field = created; + Debug.LogWarning($"[teamUIController] Found legacy Text for {slotName} under {parent.name}. Added/used TMP component on {go.name} and copied text."); + return; + } + } + Debug.LogWarning($"[teamUIController] Could not resolve {slotName} TMP (parent '{parent?.name}')"); + } + + TryResolve(ref teammate01_current_scoreText, objectFather_ally01, "teammate01_current_scoreText"); + TryResolve(ref teammate02_current_scoreText, objectFather_ally02, "teammate02_current_scoreText"); + TryResolve(ref teammate03_current_scoreText, objectFather_ally03, "teammate03_current_scoreText"); + TryResolve(ref teammate04_current_scoreText, objectFather_ally04, "teammate04_current_scoreText"); + TryResolve(ref teammate05_current_scoreText, objectFather_ally05, "teammate05_current_scoreText"); + + // total score: if assigned field is null, try to find any TMP in scene named "currentTotalScore" or under this object + if (currentTotalScore == null) + { + var tmp = GetComponentInChildren(true); + if (tmp != null) + { + currentTotalScore = tmp; + Debug.Log($"[teamUIController] Resolved currentTotalScore from child {tmp.gameObject.name}"); + } + } + } + + /// + /// ڵѾңֻ߲һ + /// + public int[] GetAdjacentAllyIndices(int slotIndex) + { + var list = new List(); + if (slotIndex - 1 >= 0) list.Add(slotIndex - 1); + if (slotIndex + 1 <= 4) list.Add(slotIndex + 1); + return list.ToArray(); + } + + /// + /// ָλӦѾ GameObjectȷ allyX_object򷵻 objectFather_allyXXΪ null + /// + public GameObject GetAllyObjectBySlot(int slotIndex) + { + switch (slotIndex) + { + case 0: return ally01_object ?? objectFather_ally01; + case 1: return ally02_object ?? objectFather_ally02; + case 2: return ally03_object ?? objectFather_ally03; + case 3: return ally04_object ?? objectFather_ally04; + case 4: return ally05_object ?? objectFather_ally05; + default: return null; + } + } + + // helper to set teammate character image based on slot index + private void SetTeammateCharacterImage(int slotIndex, Sprite sprite) + { + if (sprite == null) return; + switch (slotIndex) + { + case 0: if (teammate01_characterImage != null) teammate01_characterImage.sprite = sprite; break; + case 1: if (teammate02_characterImage != null) teammate02_characterImage.sprite = sprite; break; + case 2: if (teammate03_characterImage != null) teammate03_characterImage.sprite = sprite; break; + case 3: if (teammate04_characterImage != null) teammate04_characterImage.sprite = sprite; break; + case 4: if (teammate05_characterImage != null) teammate05_characterImage.sprite = sprite; break; + } + } } \ No newline at end of file