diff --git a/.codely/clipboard/clipboard-1790668979158.png b/.codely/clipboard/clipboard-1790668979158.png deleted file mode 100644 index be9f621..0000000 Binary files a/.codely/clipboard/clipboard-1790668979158.png and /dev/null differ diff --git a/Assets/Animation/石头人.overrideController b/Assets/Animation/石头人.overrideController index d7f385e..651b377 100644 --- a/Assets/Animation/石头人.overrideController +++ b/Assets/Animation/石头人.overrideController @@ -19,9 +19,9 @@ AnimatorOverrideController: type: 3} - m_OriginalClip: {fileID: -203655887218126122, guid: 5072af719b9b1401787c6c55f048d8ed, type: 3} - m_OverrideClip: {fileID: -203655887218126122, guid: d40daebbc0e47416099e97edbbbeac04, + m_OverrideClip: {fileID: -203655887218126122, guid: 3d031ad534e512e45bb7fe10237e6286, type: 3} - m_OriginalClip: {fileID: -203655887218126122, guid: b315bce378aec4abbac5e4070f47b069, type: 3} - m_OverrideClip: {fileID: -203655887218126122, guid: 43b8e945a41aa4eb7a6ebc2cde2cf887, + m_OverrideClip: {fileID: -203655887218126122, guid: 65518d3e21c8c4243979759cd24108d7, type: 3} diff --git a/Assets/Model/第二章/狼人/狼人攻击.fbx.meta b/Assets/Model/第二章/狼人/狼人攻击.fbx.meta index 8b1b161..43e8476 100644 --- a/Assets/Model/第二章/狼人/狼人攻击.fbx.meta +++ b/Assets/Model/第二章/狼人/狼人攻击.fbx.meta @@ -66,7 +66,7 @@ ModelImporter: bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000 curves: [] events: - - time: 0.54800594 + - time: 0.2774049 functionName: OnAttackEffect data: objectReferenceParameter: {instanceID: 0} @@ -410,128 +410,128 @@ ModelImporter: scale: {x: 1, y: 1, z: 1} - name: mixamorig:Hips parentName: "\u72FC\u4EBA\u653B\u51FB(Clone)" - position: {x: 0.000006190017, y: 0.009258306, z: 0.000010177484} + position: {x: 0.0006190017, y: 0.92583054, z: 0.0010177484} rotation: {x: 1.8189897e-10, y: -8.613506e-20, z: -4.735324e-10, w: 1} scale: {x: 1, y: 1, z: 0.99999994} - name: mixamorig:LeftUpLeg parentName: mixamorig:Hips - position: {x: -0.001580724, y: -0.0006625086, z: 0.00006822136} + position: {x: -0.1580724, y: -0.06625086, z: 0.0068221358} rotation: {x: 0.002323065, y: -0.053081393, z: 0.99763256, w: 0.043660242} scale: {x: 1.0000002, y: 1.0000002, z: 1} - name: mixamorig:LeftLeg parentName: mixamorig:LeftUpLeg - position: {x: -0, y: 0.0042308737, z: 0} + position: {x: -0, y: 0.42308736, z: 0} rotation: {x: -0.029839756, y: 0.0006429597, z: -0.021532256, w: 0.99932253} scale: {x: 1.0000005, y: 1.0000002, z: 1.0000004} - name: mixamorig:LeftFoot parentName: mixamorig:LeftLeg - position: {x: -0, y: 0.0029479251, z: 6.9388944e-20} + position: {x: -0, y: 0.2947925, z: 6.938895e-18} rotation: {x: 0.54529315, y: 0.112672314, z: -0.0742639, w: 0.82731205} scale: {x: 1.000001, y: 1.0000005, z: 1.0000006} - name: mixamorig:LeftToeBase parentName: mixamorig:LeftFoot - position: {x: -2.7755578e-19, y: 0.0025459952, z: -2.7755578e-19} + position: {x: -2.775558e-17, y: 0.2545995, z: -2.775558e-17} rotation: {x: 0.24118778, y: 0.014663992, z: -0.0036448347, w: 0.9703608} scale: {x: 0.9999996, y: 0.99999994, z: 0.9999997} - name: mixamorig:LeftToe_End parentName: mixamorig:LeftToeBase - position: {x: -0, y: 0.0010464414, z: 0} + position: {x: -0, y: 0.104644135, z: 0} rotation: {x: 0, y: -0, z: -0, w: 1} scale: {x: 1, y: 1, z: 1} - name: mixamorig:RightUpLeg parentName: mixamorig:Hips - position: {x: 0.001580724, y: -0.0006625086, z: 0.000045689758} + position: {x: 0.1580724, y: -0.06625086, z: 0.004568976} rotation: {x: -0.002111477, y: -0.048199356, z: 0.9978785, w: -0.043714385} scale: {x: 1.0000002, y: 1.0000002, z: 1.0000002} - name: mixamorig:RightLeg parentName: mixamorig:RightUpLeg - position: {x: -0, y: 0.004226694, z: -1.04083406e-19} + position: {x: -0, y: 0.42266938, z: -1.0408341e-17} rotation: {x: -0.03781653, y: -0.0008132118, z: 0.021484528, w: 0.9990534} scale: {x: 1.0000006, y: 1.0000004, z: 1.0000001} - name: mixamorig:RightFoot parentName: mixamorig:RightLeg - position: {x: -0, y: 0.0029510285, z: 0} + position: {x: -0, y: 0.29510286, z: 0} rotation: {x: 0.55099493, y: -0.10983675, z: 0.073447585, w: 0.8239818} scale: {x: 1, y: 0.99999994, z: 0.99999994} - name: mixamorig:RightToeBase parentName: mixamorig:RightFoot - position: {x: 5.5511155e-19, y: 0.0025750154, z: -1.3877789e-19} + position: {x: 5.551116e-17, y: 0.25750154, z: -1.387779e-17} rotation: {x: 0.23677067, y: -0.026426762, z: 0.0064427033, w: 0.9711848} scale: {x: 0.9999996, y: 0.9999997, z: 0.9999997} - name: mixamorig:RightToe_End parentName: mixamorig:RightToeBase - position: {x: -0, y: 0.0010227846, z: -1.7347236e-20} + position: {x: -0, y: 0.10227846, z: -1.7347237e-18} rotation: {x: 0, y: -0, z: -0, w: 1} scale: {x: 1, y: 1, z: 1} - name: mixamorig:Spine parentName: mixamorig:Hips - position: {x: -0, y: 0.0011931198, z: -0.00016322303} + position: {x: -0, y: 0.11931198, z: -0.016322304} rotation: {x: -0.06792743, y: -7.6570514e-11, z: -2.1428481e-10, w: 0.99769026} scale: {x: 1, y: 1, z: 1.0000001} - name: mixamorig:Spine1 parentName: mixamorig:Spine - position: {x: -0, y: 0.0014049385, z: 0} + position: {x: -0, y: 0.14049385, z: 0} rotation: {x: -0.00000010430813, y: -3.0716246e-10, z: 0.0000000010710126, w: 1} scale: {x: 1, y: 1, z: 1} - name: mixamorig:Spine2 parentName: mixamorig:Spine1 - position: {x: -0, y: 0.0016056426, z: 0} + position: {x: -0, y: 0.16056426, z: 0} rotation: {x: 0.000000022351742, y: 0.0000000011889004, z: 0.000000001206832, w: 1} scale: {x: 0.99999994, y: 1.0000001, z: 1.0000001} - name: mixamorig:Neck parentName: mixamorig:Spine2 - position: {x: -0, y: 0.0018063488, z: 2.63642e-10} + position: {x: -0, y: 0.18063489, z: 0.0000000263642} rotation: {x: 0.06792751, y: -0.0000000017159403, z: -0.0000000015753894, w: 0.99769026} scale: {x: 1, y: 0.9999998, z: 0.9999999} - name: mixamorig:Head parentName: mixamorig:Neck - position: {x: -0, y: 0.001452694, z: 0.00040141007} + position: {x: -0, y: 0.1452694, z: 0.04014101} rotation: {x: -0.000000044703484, y: 0.0000000021827875, z: 7.2759593e-10, w: 1} scale: {x: 1, y: 1.0000001, z: 1} - name: mixamorig:HeadTop_End parentName: mixamorig:Head - position: {x: -0, y: 0.0036708983, z: 0.0010143471} + position: {x: -0, y: 0.36708984, z: 0.10143471} rotation: {x: 0, y: -0, z: -0, w: 1} scale: {x: 1, y: 1, z: 1} - name: mixamorig:LeftShoulder parentName: mixamorig:Spine2 - position: {x: -0.0008593107, y: 0.0015329275, z: -0.000043069263} + position: {x: -0.08593107, y: 0.15329275, z: -0.0043069264} rotation: {x: 0.55490446, y: -0.42961565, z: 0.5831107, w: 0.4092596} scale: {x: 1.0000001, y: 1.0000001, z: 1.0000002} - name: mixamorig:LeftArm parentName: mixamorig:LeftShoulder - position: {x: 2.7755578e-19, y: 0.0017839916, z: -2.2204462e-18} + position: {x: 2.775558e-17, y: 0.17839916, z: -2.2204463e-16} rotation: {x: -0.13368575, y: -0.07338428, z: -0.012510804, w: 0.98822385} scale: {x: 1.0000001, y: 1.0000004, z: 1.0000004} - name: mixamorig:LeftForeArm parentName: mixamorig:LeftArm - position: {x: -0, y: 0.0038187266, z: 0} + position: {x: -0, y: 0.38187265, z: 0} rotation: {x: -0.006329544, y: -0.296342, z: -0.022776976, w: 0.95478934} scale: {x: 0.9999996, y: 1.0000007, z: 1.0000005} - name: mixamorig:LeftHand parentName: mixamorig:LeftForeArm - position: {x: -4.1633362e-19, y: 0.0027106532, z: 0} + position: {x: -4.1633363e-17, y: 0.27106532, z: 0} rotation: {x: -0, y: -0, z: -0.0000000037252899, w: 1} scale: {x: 1, y: 1, z: 1} - name: mixamorig:RightShoulder parentName: mixamorig:Spine2 - position: {x: 0.0008593107, y: 0.001531406, z: -0.00003194854} + position: {x: 0.08593107, y: 0.15314059, z: -0.0031948541} rotation: {x: -0.5590448, y: -0.42640686, z: 0.57987845, w: -0.41156673} scale: {x: 1.0000001, y: 1.0000001, z: 1.0000002} - name: mixamorig:RightArm parentName: mixamorig:RightShoulder - position: {x: -0, y: 0.0017839916, z: 0} + position: {x: -0, y: 0.17839916, z: 0} rotation: {x: 0.13425338, y: -0.09040197, z: -0.0030925567, w: -0.98680997} scale: {x: 1.0000002, y: 1.0000002, z: 1.0000006} - name: mixamorig:RightForeArm parentName: mixamorig:RightArm - position: {x: -0, y: 0.0038192812, z: 1.1102231e-18} + position: {x: -0, y: 0.38192812, z: 1.1102232e-16} rotation: {x: -0.0071950112, y: 0.2715749, z: 0.02268568, w: 0.962123} scale: {x: 0.99999994, y: 0.99999994, z: 0.99999994} - name: mixamorig:RightHand parentName: mixamorig:RightForeArm - position: {x: -0, y: 0.0027215641, z: 1.1102231e-18} + position: {x: -0, y: 0.27215642, z: 1.1102232e-16} rotation: {x: -0, y: -0, z: -0, w: 1} scale: {x: 1, y: 1, z: 1} namedPoseList: @@ -544,7 +544,7 @@ ModelImporter: armStretch: 0.05 legStretch: 0.05 feetSpacing: 0 - globalScale: 2 + globalScale: 200 rootMotionBoneName: defaultPoseIndex: -1 hasTranslationDoF: 0 diff --git a/Assets/Model/第二章/石头人/技能砸地.fbx b/Assets/Model/第二章/石头人/技能砸地.fbx new file mode 100644 index 0000000..2ca2888 Binary files /dev/null and b/Assets/Model/第二章/石头人/技能砸地.fbx differ diff --git a/Assets/Model/第二章/石头人/技能砸地.fbx.meta b/Assets/Model/第二章/石头人/技能砸地.fbx.meta new file mode 100644 index 0000000..e717b13 --- /dev/null +++ b/Assets/Model/第二章/石头人/技能砸地.fbx.meta @@ -0,0 +1,555 @@ +fileFormatVersion: 2 +guid: CX8atCL5UC6HxG8hLlhH1BbomgEeW3V4TtB1E5i8Y4neo5akoj0Ujtg= +ModelImporter: + serializedVersion: 22361 + internalIDToNameTable: [] + externalObjects: {} + materials: + materialImportMode: 2 + materialName: 0 + materialSearch: 1 + materialLocation: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + resampleCurves: 1 + optimizeGameObjects: 0 + removeConstantScaleCurves: 0 + motionNodeName: + rigImportErrors: + rigImportWarnings: + animationImportErrors: + animationImportWarnings: + animationRetargetingWarnings: + animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 + importConstraints: 0 + animationCompression: 3 + aCLCompressionLevel: 3 + aCLCurvePrecision: 0.01 + aCLFastSampleMode: 1 + animationRotationError: 0.5 + animationPositionError: 0.5 + animationScaleError: 0.5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + extraUserProperties: [] + clipAnimations: + - serializedVersion: 18 + name: "\u6280\u80FD\u7838\u5730" + takeName: mixamo.com + internalID: -203655887218126122 + firstFrame: 0 + lastFrame: 68 + wrapMode: 0 + orientationOffsetY: 0 + level: 0 + cycleOffset: 0 + loop: 0 + hasAdditiveReferencePose: 0 + lockToRoot: 0 + loopTime: 0 + loopBlend: 0 + loopBlendOrientation: 0 + loopBlendPositionY: 0 + loopBlendPositionXZ: 0 + keepOriginalOrientation: 0 + keepOriginalPositionY: 1 + keepOriginalPositionXZ: 0 + heightFromFeet: 0 + mirror: 0 + bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000 + curves: [] + events: + - time: 0.63982105 + functionName: OnSkillHit1 + data: + objectReferenceParameter: {instanceID: 0} + floatParameter: 0 + intParameter: 0 + messageOptions: 0 + intervals: [] + transformMask: [] + maskType: 3 + maskSource: {instanceID: 0} + additiveReferencePoseFrame: 0 + additiveType: 0 + basePoseType: 0 + additiveSelectedAnimation: {instanceID: 0} + additiveSelectedAnimationFrameIndex: 0 + isReadable: 0 + tuanjieGIEnable: 0 + tuanjieGIGenSDFFactor: 1 + tuanjieGIGenSDFBias: 0.25 + tuanjieGIDoubleSidedMode: 0 + tuanjieGIGenFacetNums: 12 + meshes: + lODScreenPercentages: [] + globalScale: 1 + meshCompression: 0 + totalVerticesCount: 0 + totalTrianglesCount: 0 + addColliders: 0 + useSRGBMaterialColor: 1 + sortHierarchyByName: 1 + importPhysicalCameras: 1 + importVisibility: 1 + importBlendShapes: 1 + importCameras: 1 + importLights: 1 + nodeNameCollisionStrategy: 1 + fileIdsGeneration: 2 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + keepQuads: 0 + weldVertices: 1 + bakeAxisConversion: 0 + preserveHierarchy: 0 + skinWeightsMode: 0 + maxBonesPerVertex: 4 + minBoneWeight: 0.001 + optimizeBones: 1 + meshOptimizationFlags: -1 + indexFormat: 0 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVMarginMethod: 1 + secondaryUVMinLightmapResolution: 40 + secondaryUVMinObjectScale: 1 + secondaryUVPackMargin: 4 + useFileScale: 1 + strictVertexDataChecks: 0 + virtualGeometry: + virtualGeometry: 0 + useTransparent: 0 + setVGForeachMesh: 0 + isFirstUse: 1 + virtualGeometrySettings: + generateGeometryBuffer: 0 + surfaceCompensation: 0 + allMeshUse: 1 + ignoreSimpleMesh: 0 + transformScaleState: 0 + isPossibleOverflow: 0 + hasBoneData: 0 + isBoneCountOverflow: 0 + virtualGeometryPlatformSettings: + - serializedVersion: 0 + overridden: 0 + ignorePlatformSupport: 0 + buildTarget: DefaultVirtualGeometryPlatform + positionPrecision: -2147483648 + normalPrecision: -2147483648 + tangentPrecision: -2147483648 + boneWeightPrecision: -2147483648 + detailedTriangleCount: 0 + detailedVertexCount: 0 + rootPageSize: 0 + streamablePageSize: 0 + reserveTrianglePercent: 100 + reserveDetailLevel: 0 + - serializedVersion: 0 + overridden: 0 + ignorePlatformSupport: 0 + buildTarget: Standalone + positionPrecision: -2147483648 + normalPrecision: -2147483648 + tangentPrecision: -2147483648 + boneWeightPrecision: -2147483648 + detailedTriangleCount: 0 + detailedVertexCount: 0 + rootPageSize: 0 + streamablePageSize: 0 + reserveTrianglePercent: 100 + reserveDetailLevel: 0 + - serializedVersion: 0 + overridden: 0 + ignorePlatformSupport: 0 + buildTarget: iPhone + positionPrecision: -2147483648 + normalPrecision: -2147483648 + tangentPrecision: -2147483648 + boneWeightPrecision: -2147483648 + detailedTriangleCount: 0 + detailedVertexCount: 0 + rootPageSize: 0 + streamablePageSize: 0 + reserveTrianglePercent: 100 + reserveDetailLevel: 0 + - serializedVersion: 0 + overridden: 0 + ignorePlatformSupport: 0 + buildTarget: Android + positionPrecision: -2147483648 + normalPrecision: -2147483648 + tangentPrecision: -2147483648 + boneWeightPrecision: -2147483648 + detailedTriangleCount: 0 + detailedVertexCount: 0 + rootPageSize: 0 + streamablePageSize: 0 + reserveTrianglePercent: 100 + reserveDetailLevel: 0 + selectedVGMeshes: [] + supportVGMeshes: [] + tangentSpace: + normalSmoothAngle: 60 + normalImportMode: 0 + tangentImportMode: 3 + normalCalculationMode: 4 + legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0 + blendShapeNormalImportMode: 1 + normalSmoothingSource: 0 + referencedClips: [] + importAnimation: 1 + overrideDefaultPose: 0 + humanDescription: + serializedVersion: 3 + human: + - boneName: mixamorig:Hips + humanName: Hips + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: mixamorig:LeftUpLeg + humanName: LeftUpperLeg + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: mixamorig:RightUpLeg + humanName: RightUpperLeg + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: mixamorig:LeftLeg + humanName: LeftLowerLeg + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: mixamorig:RightLeg + humanName: RightLowerLeg + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: mixamorig:LeftFoot + humanName: LeftFoot + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: mixamorig:RightFoot + humanName: RightFoot + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: mixamorig:Spine + humanName: Spine + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: mixamorig:Spine1 + humanName: Chest + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: mixamorig:Neck + humanName: Neck + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: mixamorig:Head + humanName: Head + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: mixamorig:LeftShoulder + humanName: LeftShoulder + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: mixamorig:RightShoulder + humanName: RightShoulder + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: mixamorig:LeftArm + humanName: LeftUpperArm + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: mixamorig:RightArm + humanName: RightUpperArm + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: mixamorig:LeftForeArm + humanName: LeftLowerArm + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: mixamorig:RightForeArm + humanName: RightLowerArm + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: mixamorig:LeftHand + humanName: LeftHand + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: mixamorig:RightHand + humanName: RightHand + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: mixamorig:LeftToeBase + humanName: LeftToes + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: mixamorig:RightToeBase + humanName: RightToes + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + - boneName: mixamorig:Spine2 + humanName: UpperChest + limit: + min: {x: 0, y: 0, z: 0} + max: {x: 0, y: 0, z: 0} + value: {x: 0, y: 0, z: 0} + length: 0 + modified: 0 + skeleton: + - name: "\u77F3\u5DE8\u4EBA\u653B\u51FB(Clone)" + parentName: + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + scale: {x: 1, y: 1, z: 1} + - name: node_0 + parentName: "\u77F3\u5DE8\u4EBA\u653B\u51FB(Clone)" + position: {x: -0, y: 0, z: 0} + rotation: {x: 0, y: -0, z: -0, w: 1} + scale: {x: 1, y: 1, z: 1} + - name: mixamorig:Hips + parentName: "\u77F3\u5DE8\u4EBA\u653B\u51FB(Clone)" + position: {x: 0.000025028497, y: 0.0054313573, z: -0.0000036996557} + rotation: {x: 0.0000000010470055, y: 0.000000016171759, z: 0.0000000073942017, + w: 1} + scale: {x: 0.9999999, y: 1, z: 1} + - name: mixamorig:Spine + parentName: mixamorig:Hips + position: {x: -0, y: 0.0007356823, z: -0.00006496691} + rotation: {x: -0.04402572, y: -0.000000013245289, z: -0.00000001143321, w: 0.9990304} + scale: {x: 0.99999994, y: 1.0000001, z: 0.99999994} + - name: mixamorig:Spine1 + parentName: mixamorig:Spine + position: {x: -0, y: 0.00086163584, z: 0} + rotation: {x: -0.0000000037252903, y: -0.000000005867169, z: 0.0000000012216193, + w: 1} + scale: {x: 0.99999994, y: 1, z: 0.9999998} + - name: mixamorig:Spine2 + parentName: mixamorig:Spine1 + position: {x: -0, y: 0.0009847267, z: 6.9388944e-20} + rotation: {x: 0.000000011175871, y: 0.00000000190893, z: 0.000000012783833, + w: 1} + scale: {x: 1, y: 1, z: 1} + - name: mixamorig:LeftShoulder + parentName: mixamorig:Spine2 + position: {x: -0.00058580056, y: 0.00092829805, z: -0.000014055445} + rotation: {x: 0.56822485, y: -0.4168453, z: 0.5826243, w: 0.40485722} + scale: {x: 1, y: 1, z: 0.9999998} + - name: mixamorig:LeftArm + parentName: mixamorig:LeftShoulder + position: {x: -0, y: 0.0012267674, z: 0} + rotation: {x: -0.1461725, y: -0.06026239, z: -0.004887014, w: 0.98740983} + scale: {x: 1, y: 1.0000005, z: 1.0000006} + - name: mixamorig:LeftForeArm + parentName: mixamorig:LeftArm + position: {x: 1.3877789e-19, y: 0.0020718891, z: -1.1102231e-18} + rotation: {x: -0.0025324821, y: -0.01076787, z: -0.02900415, w: 0.9995181} + scale: {x: 1.0000005, y: 1.0000001, z: 1.0000007} + - name: mixamorig:LeftHand + parentName: mixamorig:LeftForeArm + position: {x: -1.3877789e-19, y: 0.0023369573, z: 0} + rotation: {x: -0, y: -0, z: -0, w: 1} + scale: {x: 1, y: 1, z: 1} + - name: mixamorig:RightShoulder + parentName: mixamorig:Spine2 + position: {x: 0.00058580056, y: 0.000928613, z: -0.00001762298} + rotation: {x: -0.5662846, y: -0.41832346, z: 0.5842823, w: -0.40366006} + scale: {x: 1.0000002, y: 1.0000002, z: 1.0000001} + - name: mixamorig:RightArm + parentName: mixamorig:RightShoulder + position: {x: -1.3877789e-19, y: 0.0012267674, z: 1.1102231e-18} + rotation: {x: -0.14613014, y: 0.04451628, z: 0.0058504045, w: 0.988246} + scale: {x: 1.0000001, y: 1, z: 1} + - name: mixamorig:RightForeArm + parentName: mixamorig:RightArm + position: {x: 6.9388944e-20, y: 0.0020716428, z: 0} + rotation: {x: 0.0006950349, y: -0.010786076, z: -0.028526084, w: -0.9995346} + scale: {x: 1, y: 1.0000002, z: 1} + - name: mixamorig:RightHand + parentName: mixamorig:RightForeArm + position: {x: -0, y: 0.0023326648, z: 0} + rotation: {x: -0.0000000074505797, y: 9.3132246e-10, z: 0.000000007217749, w: 1} + scale: {x: 1.0000004, y: 1.0000002, z: 1.0000001} + - name: mixamorig:Neck + parentName: mixamorig:Spine2 + position: {x: -0, y: 0.0011078174, z: -3.276992e-11} + rotation: {x: -0.01486942, y: 3.426908e-10, z: 0.0000000057881673, w: 0.9998895} + scale: {x: 1, y: 1, z: 1} + - name: mixamorig:Head + parentName: mixamorig:Neck + position: {x: -0, y: 0.0001232034, z: 0.000086430045} + rotation: {x: 0.0000000037252903, y: -0.000000004246088, z: -0.00000001824041, + w: 1} + scale: {x: 1.0000001, y: 1, z: 1} + - name: mixamorig:HeadTop_End + parentName: mixamorig:Head + position: {x: -0, y: 0.0014060154, z: 0.0009863526} + rotation: {x: 0, y: -0, z: -0, w: 1} + scale: {x: 1, y: 1, z: 1} + - name: mixamorig:RightUpLeg + parentName: mixamorig:Hips + position: {x: 0.00093557435, y: -0.0004081661, z: -0.000011268007} + rotation: {x: 0.0051710024, y: 0.055403285, z: 0.99413, w: -0.09278605} + scale: {x: 0.9999997, y: 0.99999976, z: 1} + - name: mixamorig:RightLeg + parentName: mixamorig:RightUpLeg + position: {x: -0, y: 0.0022295937, z: 0} + rotation: {x: -0.19639736, y: 0.010663452, z: -0.05315652, w: 0.9790244} + scale: {x: 1.0000004, y: 1.000001, z: 1.0000004} + - name: mixamorig:RightFoot + parentName: mixamorig:RightLeg + position: {x: -0, y: 0.001674451, z: -1.3877789e-19} + rotation: {x: 0.5388422, y: 0.049867895, z: -0.03197695, w: 0.84032124} + scale: {x: 1.0000004, y: 1.0000005, z: 1.0000002} + - name: mixamorig:RightToeBase + parentName: mixamorig:RightFoot + position: {x: -0, y: 0.0016622617, z: 1.3877789e-19} + rotation: {x: 0.35963094, y: -0.010496464, z: 0.0040457686, w: 0.93302685} + scale: {x: 1.0000002, y: 1.0000001, z: 1.0000002} + - name: mixamorig:RightToe_End + parentName: mixamorig:RightToeBase + position: {x: -0, y: 0.00075564603, z: -4.336809e-21} + rotation: {x: 0, y: -0, z: -0, w: 1} + scale: {x: 1, y: 1, z: 1} + - name: mixamorig:LeftUpLeg + parentName: mixamorig:Hips + position: {x: -0.00093557435, y: -0.0004081661, z: 0.0000016435517} + rotation: {x: -0.00520432, y: 0.0557641, z: 0.9941105, w: 0.09277684} + scale: {x: 1.0000001, y: 0.9999999, z: 0.99999994} + - name: mixamorig:LeftLeg + parentName: mixamorig:LeftUpLeg + position: {x: -2.7755578e-19, y: 0.0022297692, z: 0} + rotation: {x: -0.20584376, y: 0.12434317, z: 0.026378915, w: 0.9702944} + scale: {x: 1, y: 1.0000004, z: 0.9999998} + - name: mixamorig:LeftFoot + parentName: mixamorig:LeftLeg + position: {x: -0, y: 0.001677993, z: 1.7347238e-19} + rotation: {x: 0.52844125, y: -0.16615163, z: 0.10633126, w: 0.8257344} + scale: {x: 1.0000006, y: 1.0000005, z: 0.99999976} + - name: mixamorig:LeftToeBase + parentName: mixamorig:LeftFoot + position: {x: -0, y: 0.0016452173, z: -2.0816683e-19} + rotation: {x: 0.36363024, y: 0.012258099, z: -0.0047854558, w: 0.9314505} + scale: {x: 0.9999995, y: 0.99999976, z: 0.9999999} + - name: mixamorig:LeftToe_End + parentName: mixamorig:LeftToeBase + position: {x: -2.7755578e-19, y: 0.00077092234, z: 8.673618e-21} + rotation: {x: 0, y: -0, z: -0, w: 1} + scale: {x: 1, y: 1, z: 1} + namedPoseList: + - name: Default + skeleton: [] + armTwist: 0.5 + foreArmTwist: 0.5 + upperLegTwist: 0.5 + legTwist: 0.5 + armStretch: 0.05 + legStretch: 0.05 + feetSpacing: 0 + globalScale: 1 + rootMotionBoneName: + defaultPoseIndex: -1 + hasTranslationDoF: 0 + hasExtraRoot: 1 + skeletonHasParents: 1 + lastHumanDescriptionAvatarSource: {fileID: 9000000, guid: d40daebbc0e47416099e97edbbbeac04, + type: 3} + autoGenerateAvatarMappingIfUnspecified: 1 + animationType: 3 + humanoidOversampling: 1 + avatarSetup: 2 + addHumanoidExtraRootOnlyWhenUsingAvatar: 1 + importBlendShapeDeformPercent: 1 + remapMaterialsIfMaterialImportModeIsNone: 0 + additionalBone: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/建筑脚本.meta b/Assets/Picture/UI.meta similarity index 67% rename from Assets/Scripts/建筑脚本.meta rename to Assets/Picture/UI.meta index c19d1e9..280fe0e 100644 --- a/Assets/Scripts/建筑脚本.meta +++ b/Assets/Picture/UI.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: Xn9Nt3upASmCnjf71jScieVdxk5dt59IaBF5ly41RuZmaEtbnQfCoRA= +guid: WyscsSisBiiG1MkL0a/b5vj9hwx7ySdmScsXfqIgXODEW8HYzrEwk7Y= folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/Picture/UI/卡片边框.meta b/Assets/Picture/UI/卡片边框.meta new file mode 100644 index 0000000..acc4564 --- /dev/null +++ b/Assets/Picture/UI/卡片边框.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: WnId4S6oACiY5vmJ2go0hyntRvZgo81zfwCX72sqoNOwt+8Wsvvcl0s= +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Picture/UI/卡片边框/技能圆环.png b/Assets/Picture/UI/卡片边框/技能圆环.png new file mode 100644 index 0000000..334effd Binary files /dev/null and b/Assets/Picture/UI/卡片边框/技能圆环.png differ diff --git a/Assets/Picture/UI/卡片边框/技能圆环.png.meta b/Assets/Picture/UI/卡片边框/技能圆环.png.meta new file mode 100644 index 0000000..501b31b --- /dev/null +++ b/Assets/Picture/UI/卡片边框/技能圆环.png.meta @@ -0,0 +1,163 @@ +fileFormatVersion: 2 +guid: XXMetn77Wi3S8NHBfR0p60o3Ff9IjatUZVxmgVVgoDJnsMw1GWQp0aM= +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 14 + 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 + webStreaming: 0 + priorityLevel: 0 + uploadedMode: 2 + 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: 0 + 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: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 256 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WeixinMiniGame + maxTextureSize: 2048 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: PlayableAds + maxTextureSize: 2048 + maxPlaceholderSize: 32 + 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: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + doOverrideTextureManagerOperations: 0 + platformOperationGroupSettings: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Picture/UI/卡片边框/方框.png b/Assets/Picture/UI/卡片边框/方框.png new file mode 100644 index 0000000..0110de9 Binary files /dev/null and b/Assets/Picture/UI/卡片边框/方框.png differ diff --git a/Assets/Picture/UI/卡片边框/方框.png.meta b/Assets/Picture/UI/卡片边框/方框.png.meta new file mode 100644 index 0000000..5d9621c --- /dev/null +++ b/Assets/Picture/UI/卡片边框/方框.png.meta @@ -0,0 +1,163 @@ +fileFormatVersion: 2 +guid: B3NMvSOoB34OawufXPPYrzVfNzS6hZLFn8owZWIABSJSEv7VNIXw5kQ= +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 14 + 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 + webStreaming: 0 + priorityLevel: 0 + uploadedMode: 2 + 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: 0 + 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: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 256 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WeixinMiniGame + maxTextureSize: 2048 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: PlayableAds + maxTextureSize: 2048 + maxPlaceholderSize: 32 + 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: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + doOverrideTextureManagerOperations: 0 + platformOperationGroupSettings: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Picture/UI/卡片边框/橙.png b/Assets/Picture/UI/卡片边框/橙.png new file mode 100644 index 0000000..68072f4 Binary files /dev/null and b/Assets/Picture/UI/卡片边框/橙.png differ diff --git a/Assets/Picture/UI/卡片边框/橙.png.meta b/Assets/Picture/UI/卡片边框/橙.png.meta new file mode 100644 index 0000000..6b86f1a --- /dev/null +++ b/Assets/Picture/UI/卡片边框/橙.png.meta @@ -0,0 +1,163 @@ +fileFormatVersion: 2 +guid: WylLtCmuAC77eU9cELADoML283FqYfUq/TiO5Aq/UEdyMy9jGLkLSNw= +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 14 + 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 + webStreaming: 0 + priorityLevel: 0 + uploadedMode: 2 + 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: 0 + 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: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 512 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WeixinMiniGame + maxTextureSize: 2048 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: PlayableAds + maxTextureSize: 2048 + maxPlaceholderSize: 32 + 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: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + doOverrideTextureManagerOperations: 0 + platformOperationGroupSettings: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Picture/UI/卡片边框/紫.png b/Assets/Picture/UI/卡片边框/紫.png new file mode 100644 index 0000000..4505364 Binary files /dev/null and b/Assets/Picture/UI/卡片边框/紫.png differ diff --git a/Assets/Picture/UI/卡片边框/紫.png.meta b/Assets/Picture/UI/卡片边框/紫.png.meta new file mode 100644 index 0000000..dd5d707 --- /dev/null +++ b/Assets/Picture/UI/卡片边框/紫.png.meta @@ -0,0 +1,163 @@ +fileFormatVersion: 2 +guid: CnJN5CqqVCriKlCAguU+7Gra9Pc8MZo5d1d6VoeGcOOvmk+pBdCzws4= +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 14 + 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 + webStreaming: 0 + priorityLevel: 0 + uploadedMode: 2 + 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: 0 + 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: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 512 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WeixinMiniGame + maxTextureSize: 2048 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: PlayableAds + maxTextureSize: 2048 + maxPlaceholderSize: 32 + 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: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + doOverrideTextureManagerOperations: 0 + platformOperationGroupSettings: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Picture/UI/卡片边框/红.png b/Assets/Picture/UI/卡片边框/红.png new file mode 100644 index 0000000..f4a69b7 Binary files /dev/null and b/Assets/Picture/UI/卡片边框/红.png differ diff --git a/Assets/Picture/UI/卡片边框/红.png.meta b/Assets/Picture/UI/卡片边框/红.png.meta new file mode 100644 index 0000000..6856cb1 --- /dev/null +++ b/Assets/Picture/UI/卡片边框/红.png.meta @@ -0,0 +1,163 @@ +fileFormatVersion: 2 +guid: DywXvCL4Wy1sPf32jIiKkm6uogJC3L0OHuBksuZy2Kxj158zAXdNxy0= +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 14 + 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 + webStreaming: 0 + priorityLevel: 0 + uploadedMode: 2 + 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: 0 + 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: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 512 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WeixinMiniGame + maxTextureSize: 2048 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: PlayableAds + maxTextureSize: 2048 + maxPlaceholderSize: 32 + 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: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + doOverrideTextureManagerOperations: 0 + platformOperationGroupSettings: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Picture/UI/卡片边框/背景.png b/Assets/Picture/UI/卡片边框/背景.png new file mode 100644 index 0000000..395f67e Binary files /dev/null and b/Assets/Picture/UI/卡片边框/背景.png differ diff --git a/Assets/Picture/UI/卡片边框/背景.png.meta b/Assets/Picture/UI/卡片边框/背景.png.meta new file mode 100644 index 0000000..381cfd5 --- /dev/null +++ b/Assets/Picture/UI/卡片边框/背景.png.meta @@ -0,0 +1,163 @@ +fileFormatVersion: 2 +guid: WygetiilAn8XvWbtGJ4uhaSD/yrXjrxvhT/GXLPKISUkhfxMk/BUFlQ= +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 14 + 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 + webStreaming: 0 + priorityLevel: 0 + uploadedMode: 2 + 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: 0 + 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: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WeixinMiniGame + maxTextureSize: 2048 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: PlayableAds + maxTextureSize: 2048 + maxPlaceholderSize: 32 + 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: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + doOverrideTextureManagerOperations: 0 + platformOperationGroupSettings: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Picture/UI/卡片边框/蓝.png b/Assets/Picture/UI/卡片边框/蓝.png new file mode 100644 index 0000000..96665f9 Binary files /dev/null and b/Assets/Picture/UI/卡片边框/蓝.png differ diff --git a/Assets/Picture/UI/卡片边框/蓝.png.meta b/Assets/Picture/UI/卡片边框/蓝.png.meta new file mode 100644 index 0000000..9a50494 --- /dev/null +++ b/Assets/Picture/UI/卡片边框/蓝.png.meta @@ -0,0 +1,163 @@ +fileFormatVersion: 2 +guid: B3IYtiOsBy30XfzNdvmYCqaBjJr0nLhulXlH/g005xRwcG+3BiMFaeA= +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 14 + 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 + webStreaming: 0 + priorityLevel: 0 + uploadedMode: 2 + 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: 0 + 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: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 512 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WeixinMiniGame + maxTextureSize: 2048 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: PlayableAds + maxTextureSize: 2048 + maxPlaceholderSize: 32 + 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: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + doOverrideTextureManagerOperations: 0 + platformOperationGroupSettings: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Prefabs/特效/扩散光圈/ShockwaveRing.cs b/Assets/Prefabs/特效/扩散光圈/ShockwaveRing.cs index d764e39..4470a77 100644 --- a/Assets/Prefabs/特效/扩散光圈/ShockwaveRing.cs +++ b/Assets/Prefabs/特效/扩散光圈/ShockwaveRing.cs @@ -16,13 +16,27 @@ public class ShockwaveRing : MonoBehaviour private Material mat; private float timer = -1f; + private void Awake() + { + Initialize(); + } + void Start() { + Initialize(); + } + + private void Initialize() + { + if (mat != null) + { + return; + } + // 用 .material 生成独立实例,不影响材质资产 mat = GetComponent().material; mat.SetFloat("_Progress", 0f); transform.localScale = startScale; - gameObject.SetActive(false); } /// @@ -30,6 +44,7 @@ public class ShockwaveRing : MonoBehaviour /// public void Play() { + Initialize(); gameObject.SetActive(true); timer = 0f; mat.SetFloat("_Progress", 0f); diff --git a/Assets/Prefabs/特效/扩散光圈/ShockwaveRing.prefab b/Assets/Prefabs/特效/扩散光圈/ShockwaveRing.prefab index 5236a37..fe4a0b6 100644 --- a/Assets/Prefabs/特效/扩散光圈/ShockwaveRing.prefab +++ b/Assets/Prefabs/特效/扩散光圈/ShockwaveRing.prefab @@ -125,7 +125,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 9faf161c1d2f649baaf36efc3fb301fc, type: 3} m_Name: m_EditorClassIdentifier: - duration: 1 + duration: 0.2 autoDestroy: 1 overrideColor: {r: 0, g: 0, b: 0, a: 0} overrideRadius: 0 diff --git a/Assets/Prefabs/第一章/人类士兵.prefab b/Assets/Prefabs/第一章/人类士兵.prefab index f19cb19..1369048 100644 --- a/Assets/Prefabs/第一章/人类士兵.prefab +++ b/Assets/Prefabs/第一章/人类士兵.prefab @@ -385,7 +385,8 @@ MonoBehaviour: m_EditorClassIdentifier: showStunIndicator: 1 indicatorHeight: 0.35 - stunIndicatorPrefab: {fileID: 0} + stunIndicatorPrefab: {fileID: 2432573200162841629, guid: de288ea16be0c1544a4c6eb71e899570, + type: 3} --- !u!114 &3354386702202317803 MonoBehaviour: m_ObjectHideFlags: 0 @@ -398,8 +399,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: da330bbd52e2a424dbe6231c018a3c60, type: 3} m_Name: m_EditorClassIdentifier: + characterDataName: + level: 1 speed: 5 - detectionRange: 30 + detectionRange: 15 attackRange: 1 modelFacingOffset: 0 attackPower: 10 @@ -414,6 +417,7 @@ MonoBehaviour: summonerMode: 0 returnToAnchorWhenIdle: 0 anchorArrivalDistance: 0.35 + useAnchorLeash: 0 target: {fileID: 0} --- !u!114 &165373885999363036 MonoBehaviour: diff --git a/Assets/Prefabs/第一章/小怪/城堡弓童.prefab b/Assets/Prefabs/第一章/小怪/城堡弓童.prefab index f00ef47..65f013a 100644 --- a/Assets/Prefabs/第一章/小怪/城堡弓童.prefab +++ b/Assets/Prefabs/第一章/小怪/城堡弓童.prefab @@ -504,7 +504,8 @@ MonoBehaviour: m_EditorClassIdentifier: showStunIndicator: 1 indicatorHeight: 0.35 - stunIndicatorPrefab: {fileID: 0} + stunIndicatorPrefab: {fileID: 2432573200162841629, guid: de288ea16be0c1544a4c6eb71e899570, + type: 3} --- !u!114 &3330526767746070308 MonoBehaviour: m_ObjectHideFlags: 0 @@ -522,7 +523,7 @@ MonoBehaviour: speed: 5 detectionRange: 100 attackRange: 6 - modelFacingOffset: 0 + modelFacingOffset: 90 attackPower: 10 attackDuration: 0 attackType: 2 diff --git a/Assets/Prefabs/第一章/小怪/城堡蓝卫.prefab b/Assets/Prefabs/第一章/小怪/城堡蓝卫.prefab index 610115f..09a5976 100644 --- a/Assets/Prefabs/第一章/小怪/城堡蓝卫.prefab +++ b/Assets/Prefabs/第一章/小怪/城堡蓝卫.prefab @@ -416,7 +416,8 @@ MonoBehaviour: m_EditorClassIdentifier: showStunIndicator: 1 indicatorHeight: 0.35 - stunIndicatorPrefab: {fileID: 0} + stunIndicatorPrefab: {fileID: 2432573200162841629, guid: de288ea16be0c1544a4c6eb71e899570, + type: 3} --- !u!114 &166917633014101340 MonoBehaviour: m_ObjectHideFlags: 0 diff --git a/Assets/Prefabs/第一章/小怪/城堡金盾卫.prefab b/Assets/Prefabs/第一章/小怪/城堡金盾卫.prefab index 01656c4..a03e0ae 100644 --- a/Assets/Prefabs/第一章/小怪/城堡金盾卫.prefab +++ b/Assets/Prefabs/第一章/小怪/城堡金盾卫.prefab @@ -420,7 +420,8 @@ MonoBehaviour: m_EditorClassIdentifier: showStunIndicator: 1 indicatorHeight: 0.35 - stunIndicatorPrefab: {fileID: 0} + stunIndicatorPrefab: {fileID: 2432573200162841629, guid: de288ea16be0c1544a4c6eb71e899570, + type: 3} --- !u!114 &7384803545623865944 MonoBehaviour: m_ObjectHideFlags: 0 diff --git a/Assets/Prefabs/第一章/小怪/蓝角蛮卒.prefab b/Assets/Prefabs/第一章/小怪/蓝角蛮卒.prefab index 509ad3e..7378f37 100644 --- a/Assets/Prefabs/第一章/小怪/蓝角蛮卒.prefab +++ b/Assets/Prefabs/第一章/小怪/蓝角蛮卒.prefab @@ -311,7 +311,8 @@ MonoBehaviour: m_EditorClassIdentifier: showStunIndicator: 1 indicatorHeight: 0.35 - stunIndicatorPrefab: {fileID: 0} + stunIndicatorPrefab: {fileID: 2432573200162841629, guid: de288ea16be0c1544a4c6eb71e899570, + type: 3} --- !u!114 &3749684936670238626 MonoBehaviour: m_ObjectHideFlags: 0 diff --git a/Assets/Prefabs/第一章/弓箭手.prefab b/Assets/Prefabs/第一章/弓箭手.prefab index b4149d7..2fc9c4f 100644 --- a/Assets/Prefabs/第一章/弓箭手.prefab +++ b/Assets/Prefabs/第一章/弓箭手.prefab @@ -346,7 +346,8 @@ MonoBehaviour: m_EditorClassIdentifier: showStunIndicator: 1 indicatorHeight: 0.35 - stunIndicatorPrefab: {fileID: 0} + stunIndicatorPrefab: {fileID: 2432573200162841629, guid: de288ea16be0c1544a4c6eb71e899570, + type: 3} --- !u!114 &233433209084818606 MonoBehaviour: m_ObjectHideFlags: 0 @@ -362,7 +363,7 @@ MonoBehaviour: characterDataName: level: 1 speed: 5 - detectionRange: 30 + detectionRange: 20 attackRange: 6 modelFacingOffset: 90 attackPower: 10 @@ -378,6 +379,7 @@ MonoBehaviour: summonerMode: 0 returnToAnchorWhenIdle: 0 anchorArrivalDistance: 0.35 + useAnchorLeash: 0 target: {fileID: 0} --- !u!114 &547187195648260442 MonoBehaviour: diff --git a/Assets/Prefabs/第一章/法师.prefab b/Assets/Prefabs/第一章/法师.prefab index 5c033e6..87c9d39 100644 --- a/Assets/Prefabs/第一章/法师.prefab +++ b/Assets/Prefabs/第一章/法师.prefab @@ -401,7 +401,8 @@ MonoBehaviour: m_EditorClassIdentifier: showStunIndicator: 1 indicatorHeight: 0.35 - stunIndicatorPrefab: {fileID: 0} + stunIndicatorPrefab: {fileID: 2432573200162841629, guid: de288ea16be0c1544a4c6eb71e899570, + type: 3} --- !u!114 &5283395080195203019 MonoBehaviour: m_ObjectHideFlags: 0 @@ -414,8 +415,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: da330bbd52e2a424dbe6231c018a3c60, type: 3} m_Name: m_EditorClassIdentifier: + characterDataName: + level: 1 speed: 5 - detectionRange: 30 + detectionRange: 20 attackRange: 6 modelFacingOffset: 0 attackPower: 10 @@ -431,6 +434,7 @@ MonoBehaviour: summonerMode: 0 returnToAnchorWhenIdle: 0 anchorArrivalDistance: 0.35 + useAnchorLeash: 0 target: {fileID: 0} --- !u!114 &6342080793053654425 MonoBehaviour: diff --git a/Assets/Prefabs/第一章/盾卫.prefab b/Assets/Prefabs/第一章/盾卫.prefab index f2fb785..4432e13 100644 --- a/Assets/Prefabs/第一章/盾卫.prefab +++ b/Assets/Prefabs/第一章/盾卫.prefab @@ -343,7 +343,8 @@ MonoBehaviour: m_EditorClassIdentifier: showStunIndicator: 1 indicatorHeight: 0.35 - stunIndicatorPrefab: {fileID: 0} + stunIndicatorPrefab: {fileID: 2432573200162841629, guid: de288ea16be0c1544a4c6eb71e899570, + type: 3} --- !u!114 &3995251606272715396 MonoBehaviour: m_ObjectHideFlags: 0 @@ -356,10 +357,12 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: da330bbd52e2a424dbe6231c018a3c60, type: 3} m_Name: m_EditorClassIdentifier: + characterDataName: + level: 1 speed: 5 - detectionRange: 30 - attackRange: 1 - modelFacingOffset: 0 + detectionRange: 15 + attackRange: 1.5 + modelFacingOffset: 90 attackPower: 10 attackDuration: 0 attackType: 0 @@ -372,6 +375,7 @@ MonoBehaviour: summonerMode: 0 returnToAnchorWhenIdle: 0 anchorArrivalDistance: 0.35 + useAnchorLeash: 0 target: {fileID: 0} --- !u!114 &7519013316474627281 MonoBehaviour: diff --git a/Assets/Prefabs/第一章/精锐士兵.prefab b/Assets/Prefabs/第一章/精锐士兵.prefab index bf67ada..43e9da2 100644 --- a/Assets/Prefabs/第一章/精锐士兵.prefab +++ b/Assets/Prefabs/第一章/精锐士兵.prefab @@ -329,7 +329,8 @@ MonoBehaviour: m_EditorClassIdentifier: showStunIndicator: 1 indicatorHeight: 0.35 - stunIndicatorPrefab: {fileID: 0} + stunIndicatorPrefab: {fileID: 2432573200162841629, guid: de288ea16be0c1544a4c6eb71e899570, + type: 3} --- !u!114 &7308248179790118654 MonoBehaviour: m_ObjectHideFlags: 0 @@ -342,9 +343,11 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: da330bbd52e2a424dbe6231c018a3c60, type: 3} m_Name: m_EditorClassIdentifier: + characterDataName: + level: 1 speed: 5 - detectionRange: 30 - attackRange: 1 + detectionRange: 15 + attackRange: 1.5 modelFacingOffset: 0 attackPower: 10 attackDuration: 0 @@ -358,6 +361,7 @@ MonoBehaviour: summonerMode: 0 returnToAnchorWhenIdle: 0 anchorArrivalDistance: 0.35 + useAnchorLeash: 0 target: {fileID: 0} --- !u!114 &5519732045501058211 MonoBehaviour: @@ -374,6 +378,10 @@ MonoBehaviour: skillDamage: 125 skillRadius: 2.5 skillAnimationDuration: 2.22 + groundCrackEffectPrefab: {fileID: 1670833528851026573, guid: 066bbd566f6034806a29d1e0a6517df4, + type: 3} + groundCrackForwardDistance: 1.2 + groundCrackHeightOffset: 0.05 --- !u!4 &4457840052845775698 stripped Transform: m_CorrespondingSourceObject: {fileID: -8679921383154817045, guid: 62d9f853c067ff443bd2a3aa382ab563, diff --git a/Assets/Prefabs/第二章/弓箭猎人.prefab b/Assets/Prefabs/第二章/弓箭猎人.prefab index 684470d..0ab3646 100644 --- a/Assets/Prefabs/第二章/弓箭猎人.prefab +++ b/Assets/Prefabs/第二章/弓箭猎人.prefab @@ -431,7 +431,8 @@ MonoBehaviour: m_EditorClassIdentifier: showStunIndicator: 1 indicatorHeight: 0.35 - stunIndicatorPrefab: {fileID: 0} + stunIndicatorPrefab: {fileID: 2432573200162841629, guid: de288ea16be0c1544a4c6eb71e899570, + type: 3} --- !u!114 &2471575427310325278 MonoBehaviour: m_ObjectHideFlags: 0 @@ -444,8 +445,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: da330bbd52e2a424dbe6231c018a3c60, type: 3} m_Name: m_EditorClassIdentifier: + characterDataName: + level: 1 speed: 5 - detectionRange: 30 + detectionRange: 20 attackRange: 6 modelFacingOffset: 0 attackPower: 10 @@ -461,6 +464,7 @@ MonoBehaviour: summonerMode: 0 returnToAnchorWhenIdle: 0 anchorArrivalDistance: 0.35 + useAnchorLeash: 0 target: {fileID: 0} --- !u!114 &3563675809045930453 MonoBehaviour: diff --git a/Assets/Prefabs/第二章/狼人.prefab b/Assets/Prefabs/第二章/狼人.prefab index 2d1744f..7e0b750 100644 --- a/Assets/Prefabs/第二章/狼人.prefab +++ b/Assets/Prefabs/第二章/狼人.prefab @@ -241,7 +241,8 @@ MonoBehaviour: m_EditorClassIdentifier: showStunIndicator: 1 indicatorHeight: 0.35 - stunIndicatorPrefab: {fileID: 0} + stunIndicatorPrefab: {fileID: 2432573200162841629, guid: de288ea16be0c1544a4c6eb71e899570, + type: 3} --- !u!114 &1685608640327596089 MonoBehaviour: m_ObjectHideFlags: 0 @@ -254,8 +255,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: da330bbd52e2a424dbe6231c018a3c60, type: 3} m_Name: m_EditorClassIdentifier: + characterDataName: + level: 1 speed: 5 - detectionRange: 30 + detectionRange: 15 attackRange: 1 modelFacingOffset: 0 attackPower: 10 @@ -270,6 +273,7 @@ MonoBehaviour: summonerMode: 0 returnToAnchorWhenIdle: 0 anchorArrivalDistance: 0.35 + useAnchorLeash: 0 target: {fileID: 0} --- !u!114 &5070228847944057027 MonoBehaviour: diff --git a/Assets/Prefabs/第二章/石巨人.prefab b/Assets/Prefabs/第二章/石巨人.prefab index 57d4b0d..f393cd8 100644 --- a/Assets/Prefabs/第二章/石巨人.prefab +++ b/Assets/Prefabs/第二章/石巨人.prefab @@ -268,7 +268,7 @@ MonoBehaviour: characterDataName: level: 1 speed: 5 - detectionRange: 30 + detectionRange: 15 attackRange: 1.5 modelFacingOffset: 0 attackPower: 10 @@ -283,6 +283,7 @@ MonoBehaviour: summonerMode: 0 returnToAnchorWhenIdle: 0 anchorArrivalDistance: 0.35 + useAnchorLeash: 0 target: {fileID: 0} --- !u!114 &2537748805912434613 MonoBehaviour: @@ -300,7 +301,7 @@ MonoBehaviour: skillRadius: 2 stunDuration: 1 skillAnimationDuration: 0 - shockwaveEffectPrefab: {fileID: 2432573200162841629, guid: de288ea16be0c1544a4c6eb71e899570, + shockwaveEffectPrefab: {fileID: 2197285705285267162, guid: c2264ab9308eec342a9aabba9e806a39, type: 3} --- !u!1001 &5212681125682285543 PrefabInstance: diff --git a/Assets/Prefabs/第二章/蓝色怪物.prefab b/Assets/Prefabs/第二章/蓝色怪物.prefab index 82aacd4..c7c371e 100644 --- a/Assets/Prefabs/第二章/蓝色怪物.prefab +++ b/Assets/Prefabs/第二章/蓝色怪物.prefab @@ -230,7 +230,8 @@ MonoBehaviour: m_EditorClassIdentifier: showStunIndicator: 1 indicatorHeight: 0.35 - stunIndicatorPrefab: {fileID: 0} + stunIndicatorPrefab: {fileID: 2432573200162841629, guid: de288ea16be0c1544a4c6eb71e899570, + type: 3} --- !u!114 &3361318073217798046 MonoBehaviour: m_ObjectHideFlags: 0 @@ -243,8 +244,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: da330bbd52e2a424dbe6231c018a3c60, type: 3} m_Name: m_EditorClassIdentifier: + characterDataName: + level: 1 speed: 5 - detectionRange: 30 + detectionRange: 15 attackRange: 1 modelFacingOffset: 0 attackPower: 10 @@ -259,6 +262,7 @@ MonoBehaviour: summonerMode: 0 returnToAnchorWhenIdle: 0 anchorArrivalDistance: 0.35 + useAnchorLeash: 0 target: {fileID: 0} --- !u!114 &5891340383424048665 MonoBehaviour: diff --git a/Assets/Resources/Data/HeroRoster.asset b/Assets/Resources/Data/HeroRoster.asset index 293b817..2b2691c 100644 --- a/Assets/Resources/Data/HeroRoster.asset +++ b/Assets/Resources/Data/HeroRoster.asset @@ -9,32 +9,32 @@ MonoBehaviour: m_GameObject: {fileID: 0} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: faf0a0507d15947d093eb25117aac735, type: 3} + m_Script: {fileID: 11500000, guid: 6b1505c16dbfd46b0b43df9584c2d033, type: 3} m_Name: HeroRoster m_EditorClassIdentifier: heroes: - - displayName: "\u76FE\u536B" - prefab: {fileID: 1242979668690031507, guid: 5a43e36885a204515891085639dd22c4, - type: 3} - icon: {fileID: 21300000, guid: edea9239670494fc69b62e2fdc8525f5, type: 3} - isMelee: 1 - - displayName: "\u4EBA\u7C7B\u58EB\u5175" - prefab: {fileID: 7945271050725079514, guid: 04ae1b1fe51474dda8ae5daf0b1df7c1, - type: 3} - icon: {fileID: 21300000, guid: 3f35fdb898d8648e0a01f5f7c6e5943c, type: 3} - isMelee: 1 - - displayName: "\u7CBE\u9510\u58EB\u5175" - prefab: {fileID: 3933539425749946856, guid: 6be579752d2424feea054ce267928002, - type: 3} - icon: {fileID: 21300000, guid: b86682305b7af4a5983b9f24110d7055, type: 3} - isMelee: 1 - - displayName: "\u5F13\u7BAD\u624B" - prefab: {fileID: 5200308054099318121, guid: 7d2074c48a1b3544eb534bb509ffc845, - type: 3} - icon: {fileID: 21300000, guid: 4e0429f3f8a3046c590d7fc5ce85c915, type: 3} - isMelee: 0 - displayName: "\u6CD5\u5E08" prefab: {fileID: 7062617501994129594, guid: 6fb249c0311f442ecb190db77248eafc, type: 3} - icon: {fileID: 21300000, guid: d6b94f721183e428f9a7d708ab1c6386, type: 3} + icon: {fileID: 0} isMelee: 0 + - displayName: "\u5F13\u7BAD\u624B" + prefab: {fileID: 5200308054099318121, guid: 7d2074c48a1b3544eb534bb509ffc845, + type: 3} + icon: {fileID: 0} + isMelee: 0 + - displayName: "\u76FE\u536B" + prefab: {fileID: 1242979668690031507, guid: 5a43e36885a204515891085639dd22c4, + type: 3} + icon: {fileID: 0} + isMelee: 1 + - displayName: "\u5F13\u7BAD\u730E\u4EBA" + prefab: {fileID: 4059575966999087028, guid: 4331d3c67d9c243cf8320a3a815cd03c, + type: 3} + icon: {fileID: 0} + isMelee: 0 + - displayName: "\u77F3\u5DE8\u4EBA" + prefab: {fileID: 4471054466352856454, guid: 52e49b3af34914387b829cef0563b36e, + type: 3} + icon: {fileID: 0} + isMelee: 1 diff --git a/Assets/Resources/Data/法师Data.asset b/Assets/Resources/Data/法师Data.asset index 45c26bc..bf9ebab 100644 --- a/Assets/Resources/Data/法师Data.asset +++ b/Assets/Resources/Data/法师Data.asset @@ -14,6 +14,7 @@ MonoBehaviour: m_EditorClassIdentifier: characterId: mage characterName: "\u6CD5\u5E08" + rarity: 2 description: "\u9B54\u6CD5\u653B\u51FB\u5355\u4F4D\uFF0C\u4F24\u5BB3\u6781\u9AD8\uFF0C\u8840\u91CF\u6781\u4F4E" cardIcon: {fileID: 21300000, guid: d6b94f721183e428f9a7d708ab1c6386, type: 3} unitPrefab: {fileID: 7062617501994129594, guid: 6fb249c0311f442ecb190db77248eafc, diff --git a/Assets/Resources/Data/狂暴狼人Data.asset b/Assets/Resources/Data/狂暴狼人Data.asset index 5b8e458..cf5fb09 100644 --- a/Assets/Resources/Data/狂暴狼人Data.asset +++ b/Assets/Resources/Data/狂暴狼人Data.asset @@ -14,6 +14,7 @@ MonoBehaviour: m_EditorClassIdentifier: characterId: "\u72C2\u66B4\u72FC\u4EBA" characterName: "\u72C2\u66B4\u72FC\u4EBA" + rarity: 2 description: cardIcon: {fileID: 21300000, guid: 828dd51ecae0cc3418d2f1f675ffba3e, type: 3} unitPrefab: {fileID: 6708744566382593167, guid: f3b0d9efccd74475dbbbcdc1ddcdf129, diff --git a/Assets/Resources/Data/盾卫Data.asset b/Assets/Resources/Data/盾卫Data.asset index 694907e..b6d3b2c 100644 --- a/Assets/Resources/Data/盾卫Data.asset +++ b/Assets/Resources/Data/盾卫Data.asset @@ -14,6 +14,7 @@ MonoBehaviour: m_EditorClassIdentifier: characterId: shield_guard characterName: "\u76FE\u536B" + rarity: 2 description: "\u91CD\u88C5\u9632\u5FA1\u5355\u4F4D\uFF0C\u8840\u91CF\u6781\u9AD8\uFF0C\u79FB\u52A8\u7F13\u6162" cardIcon: {fileID: 21300000, guid: edea9239670494fc69b62e2fdc8525f5, type: 3} unitPrefab: {fileID: 1242979668690031507, guid: 5a43e36885a204515891085639dd22c4, diff --git a/Assets/Resources/Data/石巨人Data.asset b/Assets/Resources/Data/石巨人Data.asset index 8cbd433..d127168 100644 --- a/Assets/Resources/Data/石巨人Data.asset +++ b/Assets/Resources/Data/石巨人Data.asset @@ -14,6 +14,7 @@ MonoBehaviour: m_EditorClassIdentifier: characterId: "\u77F3\u5DE8\u4EBA" characterName: "\u77F3\u5DE8\u4EBA" + rarity: 2 description: cardIcon: {fileID: 21300000, guid: 7a686535436b593458a50fecbe0315ce, type: 3} unitPrefab: {fileID: 4471054466352856454, guid: 52e49b3af34914387b829cef0563b36e, diff --git a/Assets/Resources/Data/精锐士兵Data.asset b/Assets/Resources/Data/精锐士兵Data.asset index eb2f13c..2c732d7 100644 --- a/Assets/Resources/Data/精锐士兵Data.asset +++ b/Assets/Resources/Data/精锐士兵Data.asset @@ -14,6 +14,7 @@ MonoBehaviour: m_EditorClassIdentifier: characterId: elite_soldier characterName: "\u7CBE\u9510\u58EB\u5175" + rarity: 2 description: "\u9AD8\u7EA7\u8FD1\u6218\u5355\u4F4D\uFF0C\u653B\u9632\u517C\u5907\uFF0C\u6D88\u8017\u8F83\u9AD8" cardIcon: {fileID: 21300000, guid: b86682305b7af4a5983b9f24110d7055, type: 3} unitPrefab: {fileID: 3933539425749946856, guid: 6be579752d2424feea054ce267928002, diff --git a/Assets/Resources/Data/荒野之王Data.asset b/Assets/Resources/Data/荒野之王Data.asset index af3188e..c9922f9 100644 --- a/Assets/Resources/Data/荒野之王Data.asset +++ b/Assets/Resources/Data/荒野之王Data.asset @@ -14,6 +14,7 @@ MonoBehaviour: m_EditorClassIdentifier: characterId: "\u8352\u91CE\u4E4B\u738B" characterName: "\u8352\u91CE\u4E4B\u738B" + rarity: 3 description: cardIcon: {fileID: 0} unitPrefab: {fileID: 0} diff --git a/Assets/Resources/Data/荒野祭司Data.asset b/Assets/Resources/Data/荒野祭司Data.asset index 1cbb564..6298eec 100644 --- a/Assets/Resources/Data/荒野祭司Data.asset +++ b/Assets/Resources/Data/荒野祭司Data.asset @@ -14,6 +14,7 @@ MonoBehaviour: m_EditorClassIdentifier: characterId: "\u8352\u91CE\u796D\u53F8" characterName: "\u8352\u91CE\u796D\u53F8" + rarity: 2 description: cardIcon: {fileID: 0} unitPrefab: {fileID: 0} diff --git a/Assets/Scenes/CharacterTest.scene b/Assets/Scenes/CharacterTest.scene index 612a3f8..acee576 100644 Binary files a/Assets/Scenes/CharacterTest.scene and b/Assets/Scenes/CharacterTest.scene differ diff --git a/Assets/Scenes/DefenseTest.scene b/Assets/Scenes/DefenseTest.scene index 7325da3..bef127c 100644 Binary files a/Assets/Scenes/DefenseTest.scene and b/Assets/Scenes/DefenseTest.scene differ diff --git a/Assets/Scripts/UI脚本/DeployHighlight.cs b/Assets/Scripts/UI脚本/DeployHighlight.cs new file mode 100644 index 0000000..9acbb78 --- /dev/null +++ b/Assets/Scripts/UI脚本/DeployHighlight.cs @@ -0,0 +1,113 @@ +using UnityEngine; + +/// +/// 部署格位高亮:拖动卡牌时在目标格位显示一块发光地板。 +/// 绿色 = 可以放置;红色 = 该格已被占用 / 不可放置。 +/// 全场只需要一个,由 DefenseGameFlowController 在布阵阶段创建。 +/// +public class DeployHighlight : MonoBehaviour +{ + public static DeployHighlight Instance { get; private set; } + + private static readonly Color FreeColor = new Color(0.25f, 1f, 0.45f, 0.55f); + private static readonly Color BlockedColor = new Color(1f, 0.28f, 0.28f, 0.55f); + + private GameObject plate; + private Material plateMaterial; + private int shownCell = -1; + + /// 高亮当前是否可见。 + public bool IsVisible => plate != null && plate.activeSelf; + + /// 当前显示的是否是"不可放置"(红色)。 + public bool IsBlocked { get; private set; } + + /// 当前高亮所在的格位,-1 表示没有。 + public int ShownCell => shownCell; + + public static DeployHighlight Ensure() + { + if (Instance != null) return Instance; + + var go = new GameObject("DeployHighlight"); + Instance = go.AddComponent(); + Instance.Build(); + return Instance; + } + + private void Awake() + { + if (Instance == null) + { + Instance = this; + Build(); + } + } + + private void Build() + { + if (plate != null) return; + + plate = GameObject.CreatePrimitive(PrimitiveType.Cube); + plate.name = "CellPlate"; + plate.transform.SetParent(transform, false); + plate.transform.localRotation = Quaternion.identity; + plate.transform.localScale = new Vector3(DeployGrid.CellWidth * 0.96f, 0.02f, DeployGrid.CellDepth * 0.96f); + + // 高亮只是视觉提示,不需要碰撞 + var collider = plate.GetComponent(); + if (collider != null) + { + Destroy(collider); + } + + var shader = Shader.Find("Sprites/Default") ?? Shader.Find("Unlit/Color"); + plateMaterial = new Material(shader); + plateMaterial.name = "DeployHighlightMat"; + plateMaterial.color = FreeColor; + + var renderer = plate.GetComponent(); + renderer.sharedMaterial = plateMaterial; + renderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; + renderer.receiveShadows = false; + + plate.SetActive(false); + } + + /// 在指定格位显示高亮。blocked = true 显示红色。 + public void Show(int cellIndex, bool blocked) + { + if (plate == null) Build(); + if (!DeployGrid.IsValidIndex(cellIndex)) + { + Hide(); + return; + } + + var pos = DeployGrid.CellPosition(cellIndex); + plate.transform.position = new Vector3(pos.x, DeployGrid.GridY + 0.05f, pos.z); + plateMaterial.color = blocked ? BlockedColor : FreeColor; + IsBlocked = blocked; + + if (shownCell != cellIndex || !plate.activeSelf) + { + plate.SetActive(true); + shownCell = cellIndex; + } + } + + public void Hide() + { + if (plate != null && plate.activeSelf) + { + plate.SetActive(false); + } + shownCell = -1; + IsBlocked = false; + } + + private void OnDestroy() + { + if (Instance == this) Instance = null; + } +} diff --git a/Assets/Scripts/建筑脚本/Barracks.cs.meta b/Assets/Scripts/UI脚本/DeployHighlight.cs.meta similarity index 76% rename from Assets/Scripts/建筑脚本/Barracks.cs.meta rename to Assets/Scripts/UI脚本/DeployHighlight.cs.meta index 7e020c0..fdf50b4 100644 --- a/Assets/Scripts/建筑脚本/Barracks.cs.meta +++ b/Assets/Scripts/UI脚本/DeployHighlight.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: W3JKtSP/Ai5L068yM/KfmfMqMzxNuuwNH7682DCQ2pexDdqL0sqt1zY= +guid: XHkY4HmuWipU3pQUHG3woFO67ulNfp7xd8NigFzHi9m1Ba1ZVxVUNLM= MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/Scripts/UI脚本/HeroCardDrag.cs b/Assets/Scripts/UI脚本/HeroCardDrag.cs new file mode 100644 index 0000000..31f870f --- /dev/null +++ b/Assets/Scripts/UI脚本/HeroCardDrag.cs @@ -0,0 +1,291 @@ +using UnityEngine; +using UnityEngine.UI; +using UnityEngine.EventSystems; + +/// +/// 英雄卡片拖动组件(布阵阶段使用)。 +/// 拖动时在场景里生成一个半透明的英雄"幽灵"跟随指针,并吸附到最近的部署格位; +/// 松手后把该卡对应的英雄登记到格位上,卡片进入"已使用"状态。 +/// +public class HeroCardDrag : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler +{ + [Header("配置(由 DefenseGameFlowController 注入)")] + public int cardIndex; // 卡片序号,0 起 + public GameObject heroPrefab; // 对应英雄 Prefab + public CharacterData characterData; // 角色数据 + + [Header("幽灵外观")] + [Range(0.1f, 1f)] public float ghostAlpha = 0.55f; + + private Canvas canvas; + private CanvasGroup canvasGroup; + private GameObject ghost; + private Material ghostHiddenMaterial; + + private bool dragging; + private int currentCell = -1; + + private const float PlacedCardAlpha = 0.35f; + + private void Awake() + { + canvas = GetComponentInParent(); + canvasGroup = GetComponent(); + if (canvasGroup == null) + { + canvasGroup = gameObject.AddComponent(); + } + } + + /// 由流程控制器注入卡片配置。 + public void Setup(int index, GameObject prefab, CharacterData data) + { + cardIndex = index; + heroPrefab = prefab; + characterData = data; + SetPlaced(false); + } + + /// 标记该卡是否已经放下去了(已放置的卡片变暗且不能再拖)。 + public void SetPlaced(bool placed) + { + if (canvasGroup != null) + { + canvasGroup.alpha = placed ? PlacedCardAlpha : 1f; + } + } + + public void OnBeginDrag(PointerEventData eventData) + { + var flow = DefenseGameFlowController.Instance; + if (flow == null || !flow.IsDeployPhase) return; + if (flow.IsCardPlaced(cardIndex)) return; // 已经放置过了 + if (heroPrefab == null) return; + + dragging = true; + currentCell = -1; + + if (canvasGroup != null) + { + canvasGroup.alpha = 0.5f; + canvasGroup.blocksRaycasts = false; + } + + CreateGhost(); + FollowPointer(eventData.position); + } + + public void OnDrag(PointerEventData eventData) + { + if (!dragging) return; + FollowPointer(eventData.position); + } + + public void OnEndDrag(PointerEventData eventData) + { + if (!dragging) return; + dragging = false; + + if (canvasGroup != null) + { + canvasGroup.alpha = 1f; + canvasGroup.blocksRaycasts = true; + } + + if (DeployHighlight.Instance != null) DeployHighlight.Instance.Hide(); + + int cell = currentCell; + currentCell = -1; + + DestroyGhost(); + + if (cell >= 0) + { + var flow = DefenseGameFlowController.Instance; + if (flow != null && flow.PlaceHeroFromCard(cardIndex, cell)) + { + SetPlaced(true); + } + } + } + + // ── 幽灵 ──────────────────────────────────────────────── + + private void CreateGhost() + { + ghost = Instantiate(heroPrefab); + ghost.name = "Ghost_" + heroPrefab.name; + + // 只保留外观:关掉所有逻辑组件与碰撞体 + foreach (var behaviour in ghost.GetComponentsInChildren(true)) + { + if (behaviour is Animator) continue; // 保留 Animator 让它做待机动作 + behaviour.enabled = false; + } + foreach (var collider in ghost.GetComponentsInChildren(true)) + { + collider.enabled = false; + } + foreach (var rb in ghost.GetComponentsInChildren(true)) + { + rb.isKinematic = true; + rb.detectCollisions = false; + } + + // Animator 不能带动根位移,否则幽灵会自己漂走 + foreach (var animator in ghost.GetComponentsInChildren(true)) + { + animator.applyRootMotion = false; + } + + // 血条 UI 是 WorldHealthBar.Awake 生成的,幽灵不需要 + var healthBar = ghost.transform.Find("WorldHealthBar"); + if (healthBar != null) + { + Destroy(healthBar.gameObject); + } + + BuildGhostMaterials(); + } + + private void BuildGhostMaterials() + { + if (ghostHiddenMaterial == null) + { + var hiddenShader = Shader.Find("Sprites/Default") ?? Shader.Find("Unlit/Color"); + ghostHiddenMaterial = new Material(hiddenShader); + ghostHiddenMaterial.name = "GhostHidden"; + ghostHiddenMaterial.color = new Color(1f, 1f, 1f, 0f); + } + + var bodyShader = Shader.Find("Standard"); + + foreach (var renderer in ghost.GetComponentsInChildren(true)) + { + var source = renderer.sharedMaterials; + var result = new Material[source.Length]; + + for (int i = 0; i < source.Length; i++) + { + // 第 0 个材质是本体,做成半透明;其余(描边等附加材质)隐藏掉 + if (i == 0 && source[i] != null && bodyShader != null) + { + result[i] = MakeTransparent(source[i], ghostAlpha, bodyShader); + } + else + { + result[i] = ghostHiddenMaterial; + } + } + + renderer.sharedMaterials = result; + renderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; + } + } + + private static Material MakeTransparent(Material source, float alpha, Shader standard) + { + var mat = new Material(source); + mat.name = source.name + "_Ghost"; + + // 统一用 Standard 的透明混合模式,保证任何贴图都能变成半透明 + if (mat.shader != standard) + { + var mainTex = mat.HasProperty("_MainTex") ? mat.GetTexture("_MainTex") : null; + var color = mat.HasProperty("_Color") ? mat.GetColor("_Color") : Color.white; + mat.shader = standard; + if (mainTex != null) mat.SetTexture("_MainTex", mainTex); + mat.SetColor("_Color", color); + } + + if (mat.HasProperty("_Mode")) + { + mat.SetFloat("_Mode", 3f); // Transparent + mat.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha); + mat.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); + mat.SetInt("_ZWrite", 0); + mat.DisableKeyword("_ALPHATEST_ON"); + mat.EnableKeyword("_ALPHABLEND_ON"); + mat.DisableKeyword("_ALPHAPREMULTIPLY_ON"); + mat.renderQueue = 3000; + } + + if (mat.HasProperty("_Color")) + { + var c = mat.GetColor("_Color"); + c.a = alpha; + mat.SetColor("_Color", c); + } + + return mat; + } + + private void FollowPointer(Vector2 screenPosition) + { + if (ghost == null) return; + + var cam = Camera.main; + if (cam == null) return; + + var ray = cam.ScreenPointToRay(screenPosition); + var ground = new Plane(Vector3.up, new Vector3(0f, DeployGrid.UnitY, 0f)); + + if (!ground.Raycast(ray, out float distance)) + { + return; + } + + Vector3 world = ray.GetPoint(distance); + int cell = DeployGrid.SnapToCellClamped(world); + + if (cell == currentCell) return; + currentCell = cell; + + var flow = DefenseGameFlowController.Instance; + bool blocked = cell < 0 || (flow != null && flow.IsCellOccupied(cell)); + + if (cell >= 0) + { + ghost.transform.position = DeployGrid.CellPosition(cell); + if (DeployHighlight.Instance != null) DeployHighlight.Instance.Show(cell, blocked); + } + else + { + // 没吸附到格位:幽灵跟着指针但压暗提示不可放置 + ghost.transform.position = new Vector3(world.x, DeployGrid.UnitY, world.z); + if (DeployHighlight.Instance != null) DeployHighlight.Instance.Hide(); + } + } + + private void DestroyGhost() + { + if (ghost == null) return; + + foreach (var renderer in ghost.GetComponentsInChildren(true)) + { + if (renderer.sharedMaterials == null) continue; + foreach (var mat in renderer.sharedMaterials) + { + if (mat != null && mat != ghostHiddenMaterial) Destroy(mat); + } + } + + Destroy(ghost); + ghost = null; + } + + private void OnDisable() + { + if (dragging) + { + dragging = false; + if (canvasGroup != null) + { + canvasGroup.alpha = 1f; + canvasGroup.blocksRaycasts = true; + } + if (DeployHighlight.Instance != null) DeployHighlight.Instance.Hide(); + } + DestroyGhost(); + } +} diff --git a/Assets/Scripts/建筑脚本/BuildingHealth.cs.meta b/Assets/Scripts/UI脚本/HeroCardDrag.cs.meta similarity index 76% rename from Assets/Scripts/建筑脚本/BuildingHealth.cs.meta rename to Assets/Scripts/UI脚本/HeroCardDrag.cs.meta index 8810127..85f2b6c 100644 --- a/Assets/Scripts/建筑脚本/BuildingHealth.cs.meta +++ b/Assets/Scripts/UI脚本/HeroCardDrag.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: BihN5y6lVy1x4afDhOwE5/fM5e8mWQXxroZfuMUij3yrzemt9JIHQDA= +guid: BnlMty2vUiow3BhqaXGezjZxgLO0vMhqB1RBSlrYGt9jhcgal1OINJI= MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/Scripts/UI脚本/HeroCardUI.cs b/Assets/Scripts/UI脚本/HeroCardUI.cs index 1410cbb..2a984ff 100644 --- a/Assets/Scripts/UI脚本/HeroCardUI.cs +++ b/Assets/Scripts/UI脚本/HeroCardUI.cs @@ -9,6 +9,11 @@ public class HeroCardUI : MonoBehaviour { [Header("引用")] public Image iconImage; // 英雄头像 + public Image rarityFrameImage; // 稀有度边框 + public Sprite blueRarityFrame; + public Sprite orangeRarityFrame; + public Sprite purpleRarityFrame; + public Sprite redRarityFrame; public Image hpFillImage; // 血条填充 public GameObject deathPanel; // 死亡遮罩 public Text reviveTimerText; // 复活倒计时文本 @@ -86,21 +91,28 @@ public class HeroCardUI : MonoBehaviour /// 设置英雄单位 /// public void SetHero(UnitBase unit, Sprite icon, Vector3 spawnPos) + { + SetHero(unit, icon, spawnPos, null); + } + + public void SetHero(UnitBase unit, Sprite icon, Vector3 spawnPos, CharacterData characterData) { heroUnit = unit; heroSpawnPosition = spawnPos; - + if (unit != null) { heroHealthBar = unit.GetComponent(); } - // 设置头像 if (iconImage != null && icon != null) { iconImage.sprite = icon; } + UpdateRarityFrame(characterData); + UpdateCharacterName(characterData); + isDead = false; if (deathPanel != null) { @@ -108,6 +120,77 @@ public class HeroCardUI : MonoBehaviour } } + /// + /// 只刷新卡面(头像 / 名字 / 稀有度边框),不绑定单位。 + /// 布阵阶段按玩家出战阵容初始化卡片时用,避免"卡片显示 A、拖出来却是 B"。 + /// + public void SetCharacterInfo(CharacterData characterData) + { + if (characterData == null) return; + + if (iconImage != null && characterData.cardIcon != null) + { + iconImage.sprite = characterData.cardIcon; + } + + UpdateRarityFrame(characterData); + UpdateCharacterName(characterData); + } + + private void UpdateRarityFrame(CharacterData characterData) + { + if (rarityFrameImage == null) + { + Transform frame = transform.Find("RarityFrame") ?? transform.Find("稀有度边框"); + if (frame != null) + { + rarityFrameImage = frame.GetComponent(); + } + } + + if (rarityFrameImage == null || characterData == null) + { + return; + } + + Sprite frameSprite = characterData.rarity switch + { + CharacterRarity.Blue => blueRarityFrame, + CharacterRarity.Orange => orangeRarityFrame, + CharacterRarity.Purple => purpleRarityFrame, + CharacterRarity.Red => redRarityFrame, + _ => blueRarityFrame + }; + + if (frameSprite != null) + { + rarityFrameImage.sprite = frameSprite; + } + } + + private void UpdateCharacterName(CharacterData characterData) + { + if (characterData == null) + { + return; + } + + // 查找 NameLabel/Text + Transform nameLabel = transform.Find("NameLabel"); + if (nameLabel != null) + { + Transform textTransform = nameLabel.Find("Text"); + if (textTransform != null) + { + Text nameText = textTransform.GetComponent(); + if (nameText != null) + { + nameText.text = characterData.characterName; + } + } + } + } + /// /// 更新血条显示 /// diff --git a/Assets/Scripts/关卡脚本/BattleFormationSpawner.cs b/Assets/Scripts/关卡脚本/BattleFormationSpawner.cs index 8e616a9..439e2c1 100644 --- a/Assets/Scripts/关卡脚本/BattleFormationSpawner.cs +++ b/Assets/Scripts/关卡脚本/BattleFormationSpawner.cs @@ -245,7 +245,7 @@ public class BattleFormationSpawner : MonoBehaviour UnityEngine.Sprite icon = characterData != null ? characterData.cardIcon : null; // 绑定英雄到卡片 - heroCardUI.SetHero(unitBase, icon, spawnPos); + heroCardUI.SetHero(unitBase, icon, spawnPos, characterData); spawnedHeroCount++; diff --git a/Assets/Scripts/关卡脚本/ChaosGateSpawner.cs b/Assets/Scripts/关卡脚本/ChaosGateSpawner.cs deleted file mode 100644 index c11bc4b..0000000 --- a/Assets/Scripts/关卡脚本/ChaosGateSpawner.cs +++ /dev/null @@ -1,117 +0,0 @@ -using UnityEngine; - -/// -/// 混沌之门:被占领后按固定间隔从所属阵营卡组随机出兵。 -/// -[RequireComponent(typeof(CrystalMineCapture))] -public class ChaosGateSpawner : MonoBehaviour -{ - [Header("出兵配置")] - [Min(1f)] public float spawnInterval = 12f; - [Min(0f)] public float spawnRadius = 1.5f; - public bool spawnImmediatelyOnCapture = false; - - [Header("蓝方卡组")] - [SerializeField] private string[] blueDeckDataNames = - { - "人类士兵Data", "弓箭手Data", "盾卫Data", "精锐士兵Data", - "法师Data", "狂暴狼人Data", "石巨人Data", "弓箭猎人Data" - }; - - private CrystalMineCapture capture; - private UnitTeam unitTeam; - private float spawnTimer; - private int previousTeamId = 2; - - private void Awake() - { - capture = GetComponent(); - unitTeam = GetComponent(); - spawnTimer = spawnInterval; - } - - private void Update() - { - if (unitTeam == null) - { - unitTeam = GetComponent(); - if (unitTeam == null) return; - } - - int currentTeamId = unitTeam.teamId; - if (currentTeamId != previousTeamId) - { - previousTeamId = currentTeamId; - spawnTimer = spawnImmediatelyOnCapture ? 0f : spawnInterval; - } - - if (currentTeamId != 0 && currentTeamId != 1) - { - spawnTimer = spawnInterval; - return; - } - - spawnTimer -= Time.deltaTime; - if (spawnTimer > 0f) return; - - if (TrySpawn(currentTeamId)) - spawnTimer = spawnInterval; - else - spawnTimer = 1f; - } - - private bool TrySpawn(int teamId) - { - Vector3 position = transform.position; - position.x += Random.Range(-spawnRadius, spawnRadius); - position.z += Random.Range(-spawnRadius, spawnRadius); - - if (teamId == 1) - { - EnemyCastleAI enemyAI = FindObjectOfType(); - return enemyAI != null && enemyAI.TrySpawnFromPortal(position, transform.rotation); - } - - CharacterData card = ChooseBlueCard(); - if (card == null || CastleSpawnManager.Instance == null) - return false; - - return SpawnBlueUnit(card, position, transform.rotation); - } - - private CharacterData ChooseBlueCard() - { - CharacterData[] cards = new CharacterData[blueDeckDataNames.Length]; - int validCount = 0; - foreach (string dataName in blueDeckDataNames) - { - CharacterData data = Resources.Load("Data/" + dataName); - if (data != null && data.unitPrefab != null) - cards[validCount++] = data; - } - - if (validCount == 0) return null; - - return cards[Random.Range(0, validCount)]; - } - - private bool SpawnBlueUnit(CharacterData data, Vector3 position, Quaternion rotation) - { - GameObject unit = Instantiate(data.unitPrefab, position, rotation); - UnitTeam team = unit.GetComponent(); - if (team != null) - { - team.teamId = 0; - unit.tag = "Friend"; - } - - UnitBase unitBase = unit.GetComponent(); - if (unitBase != null) - { - unitBase.InitializeFromPlayerData(data.GetMaxHealth(1), data.GetAttackPower(1), data.GetMoveSpeed(1)); - } - - return true; - } - -} diff --git a/Assets/Scripts/关卡脚本/DefenseGameFlowController.cs b/Assets/Scripts/关卡脚本/DefenseGameFlowController.cs new file mode 100644 index 0000000..178d249 --- /dev/null +++ b/Assets/Scripts/关卡脚本/DefenseGameFlowController.cs @@ -0,0 +1,599 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.UI; + +/// +/// 塔防模式游戏流程控制器 +/// 1. 开局进入布阵阶段:显示部署网格,玩家把底部英雄卡拖到格位上 +/// 2. 点击"开始游戏"后收起布阵 UI、显示血条并按波次出兵 +/// 3. 每波结束后英雄回到自己的格位(锚点) +/// +public class DefenseGameFlowController : MonoBehaviour +{ + public static DefenseGameFlowController Instance { get; private set; } + + [Header("引用")] + public DefenseWaveLevelController waveLevelController; + public Button startBattleButton; + public GameObject deploymentUI; // 布阵 UI(英雄卡片面板) + + [Header("英雄配置")] + public HeroRoster roster; + public Transform heroParent; // 生成英雄的父节点(战场/英雄) + public int playerTeamId = 0; + + [Header("布阵配置")] + public int maxHeroCount = 5; + public string deployGridObjectName = "部署网格"; // 战场 下的可见网格对象名 + + [Header("阵位守护")] + [Tooltip("英雄只在「离自己格位不超过寻敌视野 detectionRange」的范围内接敌,避免一路推出去。")] + public bool heroGuardPost = true; + + // 布阵登记 + private readonly Dictionary cardToCell = new Dictionary(); // 卡片序号 -> 格位 + private readonly Dictionary cellToHero = new Dictionary(); // 格位 -> 英雄 + private readonly Dictionary cardDrags = new Dictionary(); + + // 已生成英雄 + private readonly List spawnedHeroes = new List(); + private readonly Dictionary heroInitialPositions = new Dictionary(); + private readonly List hiddenHeroBars = new List(); // 布阵阶段藏起来的血条 + + private GameObject deployGridRoot; + private bool battleStarted; + + /// true = 还在布阵阶段(可以拖动卡牌)。 + public bool IsDeployPhase => !battleStarted; + + private void Awake() + { + Instance = this; + + // 场上不应该有预先摆好的英雄 + HideExistingHeroes(); + } + + private void Start() + { + if (waveLevelController != null) + { + waveLevelController.autoStart = false; + } + + if (startBattleButton != null) + { + startBattleButton.onClick.AddListener(OnStartBattleClicked); + startBattleButton.interactable = true; + } + + if (deploymentUI != null) + { + deploymentUI.SetActive(true); + } + + SetupDeployGrid(); + DeployHighlight.Ensure(); + InitializeCardDrag(); + + Debug.Log("DefenseGameFlowController: 布阵阶段,把英雄卡拖到网格上。"); + } + + private void Update() + { + if (battleStarted) return; + + // 布阵阶段:点击已经放好的英雄可以把他撤下来 + if (!TryGetTap(out Vector2 screenPosition)) return; + if (IsPointerOverUI()) return; + + var camera = Camera.main; + if (camera == null) return; + + var ray = camera.ScreenPointToRay(screenPosition); + if (!Physics.Raycast(ray, out RaycastHit hit, 300f, ~0, QueryTriggerInteraction.Collide)) return; + + var unit = hit.collider.GetComponentInParent(); + if (unit != null && spawnedHeroes.Contains(unit.gameObject)) + { + RemoveHero(unit.gameObject); + } + } + + private void OnDestroy() + { + if (Instance == this) Instance = null; + } + + // ── 布阵阶段 ──────────────────────────────────────────── + + /// 隐藏场景里预先摆好的英雄。 + private void HideExistingHeroes() + { + foreach (var unit in FindObjectsOfType(true)) + { + unit.gameObject.SetActive(false); + } + } + + /// 找到可见的部署网格,摆正到 DeployGrid 定义的位置并显示。 + private void SetupDeployGrid() + { + var battlefield = GameObject.Find("战场"); + if (battlefield != null) + { + var child = battlefield.transform.Find(deployGridObjectName); + if (child != null) deployGridRoot = child.gameObject; + } + if (deployGridRoot == null) + { + deployGridRoot = GameObject.Find(deployGridObjectName); + } + if (deployGridRoot == null) + { + Debug.LogWarning($"DefenseGameFlowController: 没找到部署网格对象「{deployGridObjectName}」。"); + return; + } + + AlignGridCells(deployGridRoot.transform); + deployGridRoot.SetActive(true); + } + + /// 把网格下的格位按 DeployGrid 的坐标摆好,保证视觉与吸附完全一致。 + private static void AlignGridCells(Transform gridRoot) + { + gridRoot.localPosition = new Vector3(0f, DeployGrid.GridY, 0f); + gridRoot.localRotation = Quaternion.identity; + + int count = gridRoot.childCount; + if (count == 0) return; + + for (int i = 0; i < count; i++) + { + var cell = gridRoot.GetChild(i); + int index = ParseCellIndex(cell.name, i); + if (!DeployGrid.IsValidIndex(index)) continue; + + var pos = DeployGrid.CellPosition(index); + cell.localPosition = new Vector3(pos.x, 0f, pos.z); + } + } + + /// 格位命名形如「格位_3_4」(行_列,从 1 开始);解析失败时退回顺序索引。 + private static int ParseCellIndex(string name, int fallback) + { + var parts = name.Split('_'); + if (parts.Length >= 3 + && int.TryParse(parts[parts.Length - 2], out int row) + && int.TryParse(parts[parts.Length - 1], out int col)) + { + int r = row - 1; + int c = col - 1; + if (r >= 0 && r < DeployGrid.Rows && c >= 0 && c < DeployGrid.Cols) + { + return DeployGrid.ToIndex(r, c); + } + } + return fallback; + } + + /// + /// 按玩家出战阵容(PlayerData)给底部每张英雄卡挂上拖动组件,并刷新卡面。 + /// 站位不再从 PlayerData 读取(改成开局手动布阵),但「用哪几个角色」仍然读 PlayerData。 + /// + private void InitializeCardDrag() + { + var canvasObj = GameObject.Find("TowerDefenseCanvas"); + if (canvasObj == null) + { + Debug.LogWarning("DefenseGameFlowController: 没找到 TowerDefenseCanvas。"); + return; + } + + var heroPanel = canvasObj.transform.Find("BottomUI/HeroCardsPanel"); + if (heroPanel == null) + { + Debug.LogWarning("DefenseGameFlowController: 没找到 BottomUI/HeroCardsPanel。"); + return; + } + + var deck = GetDeckCharacters(); + + for (int i = 0; i < maxHeroCount; i++) + { + var cardObj = heroPanel.Find($"HeroCard{i + 1}"); + if (cardObj == null) continue; + + var drag = cardObj.GetComponent(); + if (drag == null) + { + drag = cardObj.gameObject.AddComponent(); + } + + var data = i < deck.Length ? deck[i] : null; + drag.Setup(i, data != null ? data.unitPrefab : null, data); + cardDrags[i] = drag; + + // 卡面(头像 / 名字 / 稀有度)也和出战阵容保持一致 + var cardUI = cardObj.GetComponent(); + if (cardUI != null && data != null) + { + cardUI.SetCharacterInfo(data); + } + } + + Debug.Log($"DefenseGameFlowController: 已按出战阵容开启 {cardDrags.Count} 张卡片的拖动。"); + } + + /// + /// 读取玩家出战阵容(PlayerData.json 的 currentDeck),按槽位返回角色数据。 + /// PlayerData 不可用时回退到场景里配置的 HeroRoster。 + /// + private CharacterData[] GetDeckCharacters() + { + var deck = new CharacterData[maxHeroCount]; + var allData = Resources.LoadAll("Data"); + + if (PlayerDataManager.Instance != null) + { + for (int i = 0; i < maxHeroCount; i++) + { + var owned = PlayerDataManager.Instance.GetDeckCharacter(i); + if (owned == null || string.IsNullOrEmpty(owned.characterId)) continue; + + foreach (var data in allData) + { + if (data == null || data.characterId != owned.characterId) continue; + if (data.unitPrefab == null) break; // 只有数据的角色(如荒野之王)不能出战 + deck[i] = data; + break; + } + } + } + + // 兜底:PlayerData 没给出阵容时用 HeroRoster + bool anyDeck = false; + foreach (var d in deck) if (d != null) { anyDeck = true; break; } + + if (!anyDeck && roster != null && roster.heroes != null) + { + for (int i = 0; i < roster.heroes.Length && i < maxHeroCount; i++) + { + var entry = roster.heroes[i]; + if (entry == null || entry.prefab == null) continue; + deck[i] = FindCharacterDataForPrefab(entry.prefab); + } + } + + return deck; + } + + /// 把某张卡的英雄放到格位上。成功返回 true。 + public bool PlaceHeroFromCard(int cardIndex, int cellIndex) + { + if (battleStarted) return false; + if (cardIndex < 0 || cardIndex >= maxHeroCount) return false; + if (!DeployGrid.IsValidIndex(cellIndex)) return false; + if (IsCardPlaced(cardIndex)) return false; + if (IsCellOccupied(cellIndex)) return false; + + if (!cardDrags.TryGetValue(cardIndex, out var drag) || drag == null || drag.heroPrefab == null) + { + return false; + } + + var hero = SpawnHero(drag.heroPrefab, cellIndex, cardIndex); + if (hero == null) return false; + + cardToCell[cardIndex] = cellIndex; + cellToHero[cellIndex] = hero; + + Debug.Log($"布阵: 第 {cardIndex + 1} 张卡 → 格位 {cellIndex} ({hero.name})"); + return true; + } + + /// 撤销某个格位上的英雄,并让对应卡片恢复可用。 + public void RemoveHeroAt(int cellIndex) + { + if (cellToHero.TryGetValue(cellIndex, out var hero) && hero != null) + { + RemoveHero(hero); + } + } + + private void RemoveHero(GameObject hero) + { + int cardIndex = -1; + foreach (var kv in cardToCell) + { + if (cellToHero.TryGetValue(kv.Value, out var h) && h == hero) + { + cardIndex = kv.Key; + break; + } + } + + if (cardIndex >= 0) + { + cardToCell.Remove(cardIndex); + if (cardDrags.TryGetValue(cardIndex, out var drag) && drag != null) + { + drag.SetPlaced(false); + } + } + + foreach (var kv in new List>(cellToHero)) + { + if (kv.Value == hero) cellToHero.Remove(kv.Key); + } + + spawnedHeroes.Remove(hero); + heroInitialPositions.Remove(hero); + + Debug.Log($"撤回英雄: {hero.name}"); + Destroy(hero); + } + + public bool IsCellOccupied(int cellIndex) + { + return cellToHero.TryGetValue(cellIndex, out var hero) && hero != null; + } + + public bool IsCardPlaced(int cardIndex) + { + return cardToCell.ContainsKey(cardIndex); + } + + public int GetCellOfCard(int cardIndex) + { + return cardToCell.TryGetValue(cardIndex, out int cell) ? cell : -1; + } + + // ── 开战 ──────────────────────────────────────────────── + + private void OnStartBattleClicked() + { + if (battleStarted) return; + battleStarted = true; + + if (deploymentUI != null) deploymentUI.SetActive(false); + if (startBattleButton != null) startBattleButton.gameObject.SetActive(false); + if (deployGridRoot != null) deployGridRoot.SetActive(false); + if (DeployHighlight.Instance != null) DeployHighlight.Instance.Hide(); + + // 卡片从"待放置"切换成"英雄状态显示":恢复满不透明度 + foreach (var drag in cardDrags.Values) + { + if (drag != null) drag.SetPlaced(false); + } + + // 一个都没布置时用默认阵型兜底 + if (cellToHero.Count == 0) + { + SpawnDefaultFormation(); + } + + // 布阵阶段藏起来的血条,开战后显示 + foreach (var barObject in hiddenHeroBars) + { + if (barObject != null) barObject.SetActive(true); + } + + Debug.Log("DefenseGameFlowController: 开始游戏,出兵!"); + StartCoroutine(StartBattleSequence()); + } + + private IEnumerator StartBattleSequence() + { + yield return new WaitForSeconds(0.5f); + + if (waveLevelController != null) + { + StartCoroutine(waveLevelController.StartLevel()); + } + } + + // ── 生成英雄 ──────────────────────────────────────────── + + private GameObject SpawnHero(GameObject prefab, int cell, int cardIndex) + { + var characterData = FindCharacterDataForPrefab(prefab); + var spawnPos = DeployGrid.CellPosition(cell); + + var unit = Instantiate(prefab, spawnPos, Quaternion.identity); + unit.name = "英雄_" + prefab.name; + + if (heroParent != null) + { + unit.transform.SetParent(heroParent, true); + } + + var team = unit.GetComponent(); + if (team != null) team.teamId = playerTeamId; + + var unitBase = unit.GetComponent(); + if (unitBase != null) + { + unitBase.returnToAnchorWhenIdle = true; + unitBase.anchorArrivalDistance = 0.35f; + // 阵位守护:接敌范围直接用单位自己的寻敌视野 detectionRange + unitBase.useAnchorLeash = heroGuardPost; + unitBase.ResetAnchorPosition(); + } + + if (characterData != null && unitBase != null) + { + var playerData = PlayerDataManager.Instance != null + ? PlayerDataManager.Instance.GetCharacterData(characterData.characterId) + : null; + int level = playerData != null ? playerData.level : 1; + unitBase.InitializeFromPlayerData( + characterData.GetMaxHealth(level), + characterData.GetAttackPower(level), + characterData.GetMoveSpeed(level)); + } + + var healthBar = unit.GetComponent(); + if (healthBar != null) + { + if (playerTeamId == 0) healthBar.canRevive = true; + + // 布阵阶段把血条收起来,开战时再显示(血条是 WorldHealthBar.Awake 生成的子物体) + var barObject = unit.transform.Find("WorldHealthBar"); + if (barObject != null && !battleStarted) + { + barObject.gameObject.SetActive(false); + hiddenHeroBars.Add(barObject.gameObject); + } + } + + spawnedHeroes.Add(unit); + heroInitialPositions[unit] = spawnPos; + + BindHeroToCard(unit, characterData, spawnPos, cardIndex); + + return unit; + } + + /// 一张都没摆时用出战阵容按"近战前排 / 远程后排"兜底。 + private void SpawnDefaultFormation() + { + var deck = GetDeckCharacters(); + + int meleeTotal = 0, rangedTotal = 0; + for (int i = 0; i < deck.Length; i++) + { + if (deck[i] == null) continue; + if (IsMelee(deck[i])) meleeTotal++; else rangedTotal++; + } + + var used = new HashSet(); + int meleeIndex = 0, rangedIndex = 0, spawned = 0; + + for (int i = 0; i < deck.Length && spawned < maxHeroCount; i++) + { + var data = deck[i]; + if (data == null || data.unitPrefab == null) continue; + + int cell = IsMelee(data) + ? DeployGrid.DefaultCell(true, meleeIndex++, meleeTotal) + : DeployGrid.DefaultCell(false, rangedIndex++, rangedTotal); + + if (used.Contains(cell)) cell = NextFreeCell(cell, used); + if (cell < 0) continue; + + used.Add(cell); + if (SpawnHero(data.unitPrefab, cell, i) == null) continue; + + cellToHero[cell] = spawnedHeroes[spawnedHeroes.Count - 1]; + spawned++; + } + } + + /// 判定角色是否近战(远程单位 attackType 为 RangedProjectile)。 + private static bool IsMelee(CharacterData data) + { + // 用"是否配置了投射物"来判定更可靠:RangedProjectile 一定有 projectilePrefab + return data.unitPrefab == null || data.unitPrefab.GetComponent()?.attackType != UnitBase.AttackType.RangedProjectile; + } + + private static int NextFreeCell(int from, HashSet used) + { + for (int i = 0; i < DeployGrid.CellCount; i++) + { + int candidate = (from + i) % DeployGrid.CellCount; + if (!used.Contains(candidate)) return candidate; + } + return -1; + } + + /// 把英雄绑到它来源的那张卡片上(显示名字 / 稀有度 / 血条)。 + private void BindHeroToCard(GameObject heroUnit, CharacterData characterData, Vector3 spawnPos, int cardIndex) + { + if (cardIndex < 0 || cardIndex >= maxHeroCount) return; + if (!cardDrags.TryGetValue(cardIndex, out var drag) || drag == null) return; + + var cardUI = drag.GetComponent(); + var unitBase = heroUnit.GetComponent(); + if (cardUI == null || unitBase == null) return; + + var icon = characterData != null ? characterData.cardIcon : null; + cardUI.SetHero(unitBase, icon, spawnPos, characterData); + } + + /// + /// 一波清完后让英雄回格位。 + /// 正常情况放开目标,让 UnitBase 自己走回格位;只有寻路真的不可用(卡住)时才瞬移兜底。 + /// + public void ResetHeroPositions() + { + foreach (var hero in spawnedHeroes) + { + if (hero == null || !hero.activeSelf) continue; + + var unitBase = hero.GetComponent(); + var navAgent = hero.GetComponent(); + + bool canWalk = UnityEngine.AI.NavMesh.SamplePosition( + hero.transform.position, out _, 2f, UnityEngine.AI.NavMesh.AllAreas); + + if (navAgent != null && navAgent.enabled && canWalk) + { + if (unitBase != null) unitBase.target = null; // 放开目标,进入回位 + navAgent.isStopped = false; + navAgent.ResetPath(); + continue; + } + + // 卡住了(比如被挤出 NavMesh)才直接摆回格位 + if (heroInitialPositions.TryGetValue(hero, out var initialPos)) + { + Debug.LogWarning($"DefenseGameFlowController: {hero.name} 寻路不可用,瞬移回格位"); + hero.transform.position = initialPos; + if (navAgent != null) navAgent.nextPosition = initialPos; + if (unitBase != null) unitBase.ResetAnchorPosition(); + } + } + } + + // ── 工具 ──────────────────────────────────────────────── + + private CharacterData FindCharacterDataForPrefab(GameObject prefab) + { + if (prefab == null) return null; + foreach (var data in Resources.LoadAll("Data")) + { + if (data != null && data.unitPrefab == prefab) return data; + } + return null; + } + + private static bool TryGetTap(out Vector2 screenPosition) + { + if (Input.GetMouseButtonDown(0)) + { + screenPosition = Input.mousePosition; + return true; + } + if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began) + { + screenPosition = Input.GetTouch(0).position; + return true; + } + screenPosition = default; + return false; + } + + private static bool IsPointerOverUI() + { + if (EventSystem.current == null) return false; + + if (Input.touchCount > 0) + { + return EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId); + } + return EventSystem.current.IsPointerOverGameObject(); + } +} diff --git a/Assets/Scripts/关卡脚本/ChaosGateSpawner.cs.meta b/Assets/Scripts/关卡脚本/DefenseGameFlowController.cs.meta similarity index 76% rename from Assets/Scripts/关卡脚本/ChaosGateSpawner.cs.meta rename to Assets/Scripts/关卡脚本/DefenseGameFlowController.cs.meta index 85eb214..8e698e4 100644 --- a/Assets/Scripts/关卡脚本/ChaosGateSpawner.cs.meta +++ b/Assets/Scripts/关卡脚本/DefenseGameFlowController.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: CXkWsyr5V3PqLCVXf9kh9UDgagA4PNu+m8m3e+26o8Vi3MvAgRRmtzA= +guid: B38YtCOpVSouc7G4rbHoBIMoJtLgT79fWI15sJ401Ny0ANjUOgZHriM= MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/Scripts/关卡脚本/DefenseWaveLevelController.cs b/Assets/Scripts/关卡脚本/DefenseWaveLevelController.cs index 94c8ded..75c2030 100644 --- a/Assets/Scripts/关卡脚本/DefenseWaveLevelController.cs +++ b/Assets/Scripts/关卡脚本/DefenseWaveLevelController.cs @@ -59,6 +59,19 @@ public class DefenseWaveLevelController : MonoBehaviour if (autoStart) StartCoroutine(RunLevel()); } + /// + /// 外部调用:开始关卡(用于游戏流程控制) + /// + public IEnumerator StartLevel() + { + if (level == null || level.waves == null || level.waves.Length == 0) + { + Debug.LogError("DefenseWaveLevelController: 无法启动关卡,波次数据未加载"); + yield break; + } + yield return RunLevel(); + } + private bool LoadLevel() { if (levelJson == null) @@ -88,12 +101,29 @@ public class DefenseWaveLevelController : MonoBehaviour yield return new WaitForSeconds(Mathf.Max(0f, wave.restBeforeWave)); yield return SpawnWave(wave); yield return WaitForWaveCleared(); + + // 每波结束后,让英雄回到初始位置 + ResetHeroPositionsAfterWave(); + yield return new WaitForSeconds(Mathf.Max(0f, waveCompleteDelay)); } UpdateProgress(level.waves.Length, level.waves.Length, "通关"); Debug.Log("DefenseWaveLevelController: 第一关波次全部完成。"); } + + /// + /// 每波结束后让英雄回到初始位置 + /// + private void ResetHeroPositionsAfterWave() + { + DefenseGameFlowController flowController = FindObjectOfType(); + if (flowController != null) + { + flowController.ResetHeroPositions(); + Debug.Log($"第 {currentWaveIndex + 1} 波结束,英雄回到初始位置"); + } + } private IEnumerator SpawnWave(WaveEntry wave) { diff --git a/Assets/Scripts/建筑脚本/Barracks.cs b/Assets/Scripts/建筑脚本/Barracks.cs deleted file mode 100644 index 9fba367..0000000 --- a/Assets/Scripts/建筑脚本/Barracks.cs +++ /dev/null @@ -1,127 +0,0 @@ -using UnityEngine; -using UnityEngine.UI; - -public class Barracks : MonoBehaviour -{ - [Header("角色数据")] - public CharacterData characterData; - - [Header("阵营")] - public string unitTag = "Friend"; - - [Header("生产设置")] - public Transform spawnPoint; // 单位生成位置 - - [Header("UI显示")] - public Image progressBar; // 生产进度条 - public Image characterIcon; // 角色头像 - - private float spawnTimer = 0f; - private float spawnInterval = 5f; - private bool isProducing = true; - private BuildingHealth buildingHealth; - - private void Start() - { - buildingHealth = GetComponent(); - - if (characterData != null) - { - spawnInterval = 5f; - - // 设置角色头像 - if (characterIcon != null && characterData.cardIcon != null) - { - characterIcon.sprite = characterData.cardIcon; - } - - Debug.Log($"兵营初始化:{characterData.characterName},生产间隔{spawnInterval}秒"); - } - else - { - Debug.LogError("兵营缺少角色数据!"); - } - - // 如果没有spawnPoint,使用兵营自己的位置 - if (spawnPoint == null) - { - spawnPoint = transform; - } - } - - private void Update() - { - if (!isProducing || characterData == null) return; - - spawnTimer += Time.deltaTime; - - // 更新进度条 - if (buildingHealth != null) - { - buildingHealth.SetProductionProgress(spawnTimer / spawnInterval); - } - else if (progressBar != null) - { - progressBar.fillAmount = spawnTimer / spawnInterval; - } - - // 时间到,生产单位 - if (spawnTimer >= spawnInterval) - { - SpawnUnit(); - spawnTimer = 0f; - } - } - - private void SpawnUnit() - { - if (characterData == null || characterData.unitPrefab == null) - { - Debug.LogError("无法生产单位:缺少unitPrefab"); - return; - } - - // 在spawnPoint位置生成单位 - Vector3 spawnPosition = spawnPoint.position; - - GameObject unit = Instantiate(characterData.unitPrefab, spawnPosition, Quaternion.identity); - unit.name = characterData.characterName; - unit.tag = unitTag; - - // 设置阵营 ID(根据建筑的阵营) - var buildingTeam = GetComponent(); - var unitTeam = unit.GetComponent(); - if (buildingTeam != null && unitTeam != null) - { - unitTeam.teamId = buildingTeam.teamId; - } - else if (unitTeam != null) - { - // 兜底:根据 tag 判断阵营 - unitTeam.teamId = unitTag == "Friend" ? 0 : 1; - } - - // 如果单位有UnitBase组件,使用1级属性初始化 - var unitBase = unit.GetComponent(); - if (unitBase != null) - { - float health = characterData.GetMaxHealth(1); - float attack = characterData.GetAttackPower(1); - float moveSpeed = characterData.GetMoveSpeed(1); - - unitBase.InitializeFromPlayerData(health, attack, moveSpeed); - } - - Debug.Log($"兵营生产了单位:{characterData.characterName}"); - } - - public void StopProduction() - { - isProducing = false; - } - - public void StartProduction() - { - isProducing = true; - } -} diff --git a/Assets/Scripts/建筑脚本/BuildingHealth.cs b/Assets/Scripts/建筑脚本/BuildingHealth.cs deleted file mode 100644 index d25da50..0000000 --- a/Assets/Scripts/建筑脚本/BuildingHealth.cs +++ /dev/null @@ -1,42 +0,0 @@ -using UnityEngine; - -[RequireComponent(typeof(WorldHealthBar))] -public class BuildingHealth : MonoBehaviour -{ - [Header("建筑生命")] - [Min(1f)] public float maxHealth = 500f; - - private WorldHealthBar healthBar; - - public float ProductionProgress => healthBar != null - ? Mathf.Clamp01(healthBar.currentEnergy / healthBar.maxEnergy) - : 0f; - - private void Awake() - { - healthBar = GetComponent(); - healthBar.maxHealth = maxHealth; - healthBar.currentHealth = maxHealth; - healthBar.maxEnergy = 1f; - healthBar.currentEnergy = 0f; - } - - public void SetProductionProgress(float normalizedProgress) - { - if (healthBar != null) - { - healthBar.SetEnergy(Mathf.Clamp01(normalizedProgress) * healthBar.maxEnergy); - } - } - - public bool ReceiveDamage(float damage, GameObject attacker = null) - { - if (damage <= 0f || healthBar == null) - { - return false; - } - - healthBar.TakeDamage(damage); - return true; - } -} diff --git a/Assets/Scripts/建筑脚本/BuildingPlacementManager.cs b/Assets/Scripts/建筑脚本/BuildingPlacementManager.cs deleted file mode 100644 index fd32c9d..0000000 --- a/Assets/Scripts/建筑脚本/BuildingPlacementManager.cs +++ /dev/null @@ -1,242 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; - -public class BuildingPlacementManager : MonoBehaviour -{ - public static BuildingPlacementManager Instance { get; private set; } - - [Header("建筑预制体")] - public GameObject barracksBasePrefab; - public GameObject goldMinePrefab; - - [Header("虚拟网格")] - [Min(0.1f)] public float gridSize = 1f; - [Min(0f)] public float placementHeight; - public Vector2 xLimits = new Vector2(-7f, 7f); - public Vector2 zLimits = new Vector2(-10f, 20f); - - [Header("放置检测")] - public LayerMask groundLayer; - [Min(0.1f)] public float buildingRadius = 1.25f; - public Material previewMaterialValid; - public Material previewMaterialInvalid; - - private readonly List placedBuildings = new List(); - private CharacterData currentCharacterData; - private GameObject currentPrefab; - private GameObject previewObject; - private Camera mainCamera; - private bool isPlacing; - private bool previewPositionValid; - - private void Awake() - { - if (Instance != null && Instance != this) - { - Destroy(gameObject); - return; - } - - Instance = this; - } - - private void Start() - { - mainCamera = Camera.main; - RegisterExistingBuilding(GameObject.Find("主要基地")); - } - - private void Update() - { - if (!isPlacing) - { - return; - } - - UpdatePreview(); - - if (Input.GetMouseButtonDown(0)) - { - TryPlaceBuilding(); - } - else if (Input.GetMouseButtonDown(1) || Input.GetKeyDown(KeyCode.Escape)) - { - CancelPlacement(); - } - } - - public void StartPlacingBuilding(CharacterData data) - { - if (data == null) - { - return; - } - - StartPlacingBarracks(data); - } - - public void StartPlacingBarracks(CharacterData data) - { - if (data == null || barracksBasePrefab == null) - { - Debug.LogError("兵营预制体或角色数据为空"); - return; - } - - BeginPlacement(barracksBasePrefab, data); - } - - public void StartPlacingGoldMine() - { - if (goldMinePrefab == null) - { - Debug.LogError("金矿预制体为空"); - return; - } - - BeginPlacement(goldMinePrefab, null); - } - - private void BeginPlacement(GameObject prefab, CharacterData data) - { - CancelPlacement(); - currentPrefab = prefab; - currentCharacterData = data; - previewObject = Instantiate(prefab); - previewObject.name = "建筑预览"; - SetCollidersEnabled(previewObject, false); - isPlacing = true; - mainCamera = Camera.main; - } - - private void UpdatePreview() - { - if (previewObject == null || mainCamera == null) - { - return; - } - - Ray ray = mainCamera.ScreenPointToRay(Input.mousePosition); - int mask = groundLayer.value == 0 ? Physics.DefaultRaycastLayers : groundLayer.value; - if (!Physics.Raycast(ray, out RaycastHit hit, 1000f, mask)) - { - previewPositionValid = false; - return; - } - - Vector3 position = hit.point; - position.x = Mathf.Round(position.x / gridSize) * gridSize; - position.y = placementHeight; - position.z = Mathf.Round(position.z / gridSize) * gridSize; - previewObject.transform.position = position; - previewPositionValid = IsValidPosition(position); - UpdatePreviewMaterial(previewPositionValid); - } - - private bool IsValidPosition(Vector3 position) - { - if (position.x < xLimits.x || position.x > xLimits.y || - position.z < zLimits.x || position.z > zLimits.y) - { - return false; - } - - foreach (GameObject building in placedBuildings) - { - if (building != null && Vector3.Distance(position, building.transform.position) < buildingRadius * 2f) - { - return false; - } - } - - return true; - } - - private void TryPlaceBuilding() - { - if (!previewPositionValid || previewObject == null || currentPrefab == null) - { - return; - } - - int cost = 100; - if (GoldSystem.Instance == null || !GoldSystem.Instance.TrySpend(cost)) - { - Debug.Log($"金币不足,需要{cost}"); - return; - } - - Vector3 position = previewObject.transform.position; - GameObject building = Instantiate(currentPrefab, position, Quaternion.identity); - building.name = currentCharacterData != null - ? "兵营_" + currentCharacterData.characterName - : "金矿"; - building.tag = "Friend"; - if (building.GetComponent() == null) - { - building.AddComponent(); - } - - if (currentCharacterData != null) - { - Barracks barracks = building.GetComponent(); - if (barracks == null) - { - barracks = building.AddComponent(); - } - - barracks.characterData = currentCharacterData; - } - else if (building.GetComponent() == null) - { - building.AddComponent(); - } - - placedBuildings.Add(building); - CancelPlacement(); - } - - private void UpdatePreviewMaterial(bool valid) - { - Material material = valid ? previewMaterialValid : previewMaterialInvalid; - if (material == null || previewObject == null) - { - return; - } - - foreach (Renderer renderer in previewObject.GetComponentsInChildren()) - { - renderer.sharedMaterial = material; - } - } - - private void SetCollidersEnabled(GameObject target, bool enabled) - { - foreach (Collider collider in target.GetComponentsInChildren()) - { - collider.enabled = enabled; - } - } - - public void RegisterExistingBuilding(GameObject building) - { - if (building != null && !placedBuildings.Contains(building)) - { - placedBuildings.Add(building); - } - } - - public void CancelPlacement() - { - if (previewObject != null) - { - Destroy(previewObject); - } - - previewObject = null; - currentPrefab = null; - currentCharacterData = null; - isPlacing = false; - previewPositionValid = false; - } -} diff --git a/Assets/Scripts/建筑脚本/BuildingPlacementManager.cs.meta b/Assets/Scripts/建筑脚本/BuildingPlacementManager.cs.meta deleted file mode 100644 index 4a8b43d..0000000 --- a/Assets/Scripts/建筑脚本/BuildingPlacementManager.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: C31KvXn8U39bDHLWfJ9jSgBhWvoLhWw7Xvmn2WmpmrFDtWho+cg1kak= -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Scripts/建筑脚本/CastleSpawnManager.cs b/Assets/Scripts/建筑脚本/CastleSpawnManager.cs deleted file mode 100644 index 9a2c455..0000000 --- a/Assets/Scripts/建筑脚本/CastleSpawnManager.cs +++ /dev/null @@ -1,75 +0,0 @@ -using UnityEngine; - -/// -/// 拆家版出兵管理:从城堡前方出兵点生成单位,消耗能量。 -/// 替代旧的召唤师身边召唤逻辑。 -/// -public class CastleSpawnManager : MonoBehaviour -{ - public static CastleSpawnManager Instance { get; private set; } - - [Header("出兵点(城堡前方)")] - public Transform blueSpawnPoint; - public Transform redSpawnPoint; - - private void Awake() - { - if (Instance != null && Instance != this) { Destroy(gameObject); return; } - Instance = this; - } - - /// 从指定阵营城堡出兵,消耗能量。teamId: 0=蓝, 1=红。 - public bool TrySpawn(CharacterData data, int teamId) - { - if (data == null || data.unitPrefab == null) return false; - Transform spawnPoint = teamId == 0 ? blueSpawnPoint : redSpawnPoint; - if (spawnPoint == null) - { - Debug.LogError($"找不到 teamId={teamId} 的出兵点"); - return false; - } - - Vector3 direction = spawnPoint.forward; - direction.y = 0f; - if (direction.sqrMagnitude < 0.001f) direction = Vector3.forward; - direction.Normalize(); - - GameObject unit = Instantiate( - data.unitPrefab, - spawnPoint.position, - Quaternion.LookRotation(direction, Vector3.up)); - - // 设置阵营 - UnitTeam unitTeam = unit.GetComponent(); - if (unitTeam != null) - { - unitTeam.teamId = teamId; - unit.tag = teamId == 0 ? "Friend" : "Enemy"; - } - - // 初始化属性(默认 1 级) - UnitBase unitBase = unit.GetComponent(); - if (unitBase != null) - { - PlayerCharacterData playerData = new PlayerCharacterData("castle_spawn", 1, 0); - float hp = playerData.GetMaxHealth(data); - float atk = playerData.GetAttackPower(data); - float spd = playerData.GetMoveSpeed(data); - unitBase.InitializeFromPlayerData(hp, atk, spd); - - // 如果是敌人(teamId != 0),增大寻敌距离 - if (teamId != 0) - { - unitBase.detectionRange = 100f; // 从默认30增加到100 - } - } - - Debug.Log($"城堡出兵: {data.characterName} teamId={teamId} pos={spawnPoint.position}"); - return true; - } - - public bool CanAfford(CharacterData data) - { - return data != null && data.unitPrefab != null; - } -} diff --git a/Assets/Scripts/建筑脚本/CastleSpawnManager.cs.meta b/Assets/Scripts/建筑脚本/CastleSpawnManager.cs.meta deleted file mode 100644 index 340e7e7..0000000 --- a/Assets/Scripts/建筑脚本/CastleSpawnManager.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: Wysc5i6rUC+IV5FZ0/o3UMuAsbu+kExxLM4sa7XnkVGb+y85mKtxqMU= -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Scripts/建筑脚本/CrystalMineCapture.cs b/Assets/Scripts/建筑脚本/CrystalMineCapture.cs deleted file mode 100644 index 3c6e395..0000000 --- a/Assets/Scripts/建筑脚本/CrystalMineCapture.cs +++ /dev/null @@ -1,277 +0,0 @@ -using UnityEngine; -using UnityEngine.UI; - -public class CrystalMineCapture : MonoBehaviour -{ - [Header("争夺进度")] - [Range(0f, 100f)] public float blueProgress = 50f; - [Min(0f)] public float capturePerDamage = 1f; - - [Tooltip("是否自动添加中立阵营(teamId=2)。拆家版关闭以避免单位自动锁敌水晶矿")] - public bool autoSetNeutralTeam = true; - - [Header("资源产出")] - [Tooltip("占领后是否按固定间隔给所属阵营增加能量")] - public bool producesMana = true; - [Min(1f)] public float manaInterval = 8f; - [Min(1)] public int manaAmount = 1; - - // [SerializeField] private AdjustableGlowOrb glowOrb; // 已删除,视觉效果脚本未使用 - // [Tooltip("混沌裂缝传送门(随机出兵点),随争夺进度同步变色,可留空")] - // [SerializeField] private RiftPortalVisual riftVisual; // 已删除,视觉效果脚本未使用 - [SerializeField] private Color neutralColor = Color.white; - [SerializeField] private Color blueColor = new Color(0.1f, 0.65f, 1f, 1f); - [SerializeField] private Color redColor = new Color(1f, 0.12f, 0.08f, 1f); - - [Header("世界血条")] - [Tooltip("血条相对模型渲染包围盒顶部的额外高度")] - [Min(0f)] public float heightOffset = 1.1f; - [Min(0.1f)] public float barWidth = 5f; - - private float? barHeightCache; - - private Canvas canvas; - private RectTransform barRect; - private Image blueFill; - private Image redFill; - private RectTransform marker; - private UnitTeam unitTeam; - private float manaTimer; - private static Sprite roundedSprite; - private static readonly int BaseColorId = Shader.PropertyToID("_Color"); - - private void Awake() - { - if (autoSetNeutralTeam) - { - unitTeam = GetComponent(); - if (unitTeam == null) - { - unitTeam = gameObject.AddComponent(); - } - unitTeam.teamId = 2; - } - else - { - unitTeam = GetComponent(); - } - - // if (glowOrb == null) - // { - // glowOrb = GetComponentInChildren(true); - // } - - // if (riftVisual == null) - // { - // riftVisual = GetComponentInChildren(true); - // } - - CreateCaptureBar(); - RefreshVisuals(); - } - - private void Start() - { - // 强制重置光球颜色为初始状态 - // if (glowOrb != null) - // { - // glowOrb.SetGlowColor(neutralColor); - // } - RefreshVisuals(); - } - - private void LateUpdate() - { - UpdateManaProduction(); - - if (barRect == null) return; - - barRect.position = transform.position + Vector3.up * GetBarHeight(); - barRect.localScale = Vector3.one * (barWidth / 100f); - - Camera camera = Camera.main; - if (camera != null) - { - barRect.rotation = Quaternion.LookRotation(camera.transform.position - barRect.position, camera.transform.up); - } - } - - // 血条高度 = 所有子 Renderer 包围盒顶部 + heightOffset。 - // 水晶矿模型根节点是 100 倍缩放,高度必须按世界包围盒算,否则血条会埋进模型内部被遮挡。 - private float GetBarHeight() - { - if (barHeightCache.HasValue) return barHeightCache.Value; - - float top = 0f; - Renderer[] renderers = GetComponentsInChildren(); - if (renderers.Length > 0) - { - Bounds bounds = renderers[0].bounds; - for (int i = 1; i < renderers.Length; i++) - { - bounds.Encapsulate(renderers[i].bounds); - } - top = bounds.max.y; - } - barHeightCache = top - transform.position.y + heightOffset; - return barHeightCache.Value; - } - - private void UpdateManaProduction() - { - if (!producesMana || unitTeam == null || (unitTeam.teamId != 0 && unitTeam.teamId != 1)) - { - manaTimer = 0f; - return; - } - - manaTimer += Time.deltaTime; - while (manaTimer >= manaInterval) - { - manaTimer -= manaInterval; - if (unitTeam.teamId == 0) - { - ManaSystem.Instance?.AddMana(manaAmount); - } - else - { - EnemyCastleAI enemyAI = FindObjectOfType(); - enemyAI?.AddMana(manaAmount); - } - } - } - - public bool ReceiveCaptureDamage(float damage, GameObject attacker) - { - if (damage <= 0f || attacker == null) return false; - - UnitTeam attackerTeam = attacker.GetComponentInParent(); - if (attackerTeam == null) return false; - - float direction = attackerTeam.teamId == 0 ? 1f : -1f; - blueProgress = Mathf.Clamp(blueProgress + direction * damage * capturePerDamage, 0f, 100f); - RefreshVisuals(); - return true; - } - - public void SetCaptureProgress(float value) - { - blueProgress = Mathf.Clamp(value, 0f, 100f); - RefreshVisuals(); - } - - private void RefreshVisuals() - { - if (blueFill == null || redFill == null) return; - - float blue = blueProgress / 100f; - blueFill.fillAmount = blue; - redFill.fillAmount = 1f - blue; - marker.anchorMin = new Vector2(blue, 0f); - marker.anchorMax = new Vector2(blue, 1f); - marker.anchoredPosition = Vector2.zero; - marker.gameObject.SetActive(blueProgress > 0f && blueProgress < 100f); - - if (unitTeam != null) - { - unitTeam.teamId = blueProgress >= 100f ? 0 : blueProgress <= 0f ? 1 : 2; - } - - // if (glowOrb != null) - // { - // Color color = blueProgress >= 100f ? blueColor : blueProgress <= 0f ? redColor : neutralColor; - // glowOrb.SetGlowColor(color); - // } - - // if (riftVisual != null) - // { - // Color riftColor = blueProgress >= 100f ? blueColor : blueProgress <= 0f ? redColor : neutralColor; - // riftVisual.SetRiftColor(riftColor); - // } - } - - private void CreateCaptureBar() - { - GameObject root = new GameObject("CrystalCaptureBar", typeof(RectTransform), typeof(Canvas), typeof(CanvasScaler)); - // 血条 Canvas 不要作为水晶矿的子对象,直接放在场景根目录避免被 100 倍缩放影响 - root.transform.parent = null; - canvas = root.GetComponent(); - canvas.renderMode = RenderMode.WorldSpace; - canvas.sortingOrder = 110; - root.GetComponent().dynamicPixelsPerUnit = 10f; - barRect = root.GetComponent(); - barRect.sizeDelta = new Vector2(100f, 16f); - barRect.localScale = Vector3.one * (barWidth / 100f); - - RectTransform row = CreateRow(root.transform, "CaptureBar", 100f, 14f); - Image background = CreateImage(row, "Background", new Color(0.03f, 0.03f, 0.03f, 0.95f)); - SetFullRect(background.rectTransform); - - blueFill = CreateImage(row, "BlueFill", blueColor); - blueFill.type = Image.Type.Filled; - blueFill.fillMethod = Image.FillMethod.Horizontal; - blueFill.fillOrigin = 0; - blueFill.rectTransform.anchorMin = new Vector2(0f, 0f); - blueFill.rectTransform.anchorMax = new Vector2(1f, 1f); - blueFill.rectTransform.offsetMin = new Vector2(2f, 2f); - blueFill.rectTransform.offsetMax = new Vector2(-2f, -2f); - - redFill = CreateImage(row, "RedFill", redColor); - redFill.type = Image.Type.Filled; - redFill.fillMethod = Image.FillMethod.Horizontal; - redFill.fillOrigin = 1; - redFill.rectTransform.anchorMin = new Vector2(0f, 0f); - redFill.rectTransform.anchorMax = new Vector2(1f, 1f); - redFill.rectTransform.offsetMin = new Vector2(2f, 2f); - redFill.rectTransform.offsetMax = new Vector2(-2f, -2f); - - GameObject markerObject = new GameObject("CenterMarker", typeof(RectTransform), typeof(Image)); - markerObject.transform.SetParent(row, false); - marker = markerObject.GetComponent(); - marker.sizeDelta = new Vector2(2f, 14f); - marker.anchorMin = new Vector2(0.5f, 0f); - marker.anchorMax = new Vector2(0.5f, 1f); - marker.GetComponent().color = Color.white; - } - - private RectTransform CreateRow(Transform parent, string name, float width, float height) - { - GameObject rowObject = new GameObject(name, typeof(RectTransform)); - rowObject.transform.SetParent(parent, false); - RectTransform rect = rowObject.GetComponent(); - rect.anchorMin = new Vector2(0.5f, 0.5f); - rect.anchorMax = new Vector2(0.5f, 0.5f); - rect.pivot = new Vector2(0.5f, 0.5f); - rect.sizeDelta = new Vector2(width, height); - return rect; - } - - private Image CreateImage(Transform parent, string name, Color color) - { - GameObject imageObject = new GameObject(name, typeof(RectTransform), typeof(Image)); - imageObject.transform.SetParent(parent, false); - Image image = imageObject.GetComponent(); - image.sprite = RoundedSprite(); - image.color = color; - return image; - } - - private void SetFullRect(RectTransform rect) - { - rect.anchorMin = Vector2.zero; - rect.anchorMax = Vector2.one; - rect.offsetMin = Vector2.zero; - rect.offsetMax = Vector2.zero; - } - - private static Sprite RoundedSprite() - { - if (roundedSprite != null) return roundedSprite; - Texture2D texture = new Texture2D(1, 1, TextureFormat.RGBA32, false); - texture.SetPixel(0, 0, Color.white); - texture.Apply(); - roundedSprite = Sprite.Create(texture, new Rect(0f, 0f, 1f, 1f), new Vector2(0.5f, 0.5f)); - roundedSprite.name = "CrystalCaptureBarSprite"; - return roundedSprite; - } -} diff --git a/Assets/Scripts/建筑脚本/CrystalMineCapture.cs.meta b/Assets/Scripts/建筑脚本/CrystalMineCapture.cs.meta deleted file mode 100644 index f7ca436..0000000 --- a/Assets/Scripts/建筑脚本/CrystalMineCapture.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: Ci8f4Sz/WnrXjU/p2xyMiRtWkh/2zF5+zBmBE7FvT1PHEvOb80JVbxc= -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Scripts/建筑脚本/EnemyCastleAI.cs b/Assets/Scripts/建筑脚本/EnemyCastleAI.cs deleted file mode 100644 index b816722..0000000 --- a/Assets/Scripts/建筑脚本/EnemyCastleAI.cs +++ /dev/null @@ -1,284 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; - -/// -/// 红方城堡自动出兵 AI:独立能量、三路目标评估、低费试探与高费推进。 -/// -public class EnemyCastleAI : MonoBehaviour -{ - [Header("AI 阵营")] - [SerializeField] private int teamId = 1; - [SerializeField] private int maxMana = 10; - [SerializeField] private float manaRegenInterval = 3f; - [SerializeField] private float decisionInterval = 1.2f; - [SerializeField] private float minimumSpawnInterval = 1.4f; - - [Header("三路目标")] - [SerializeField] private float leftLaneX = -10f; - [SerializeField] private float centerLaneX = 0f; - [SerializeField] private float rightLaneX = 10f; - [SerializeField] private float laneHalfWidth = 4f; - [SerializeField] private float resourceThreatWeight = 2.5f; - [SerializeField] private float enemyUnitWeight = 1.5f; - [SerializeField] private float laneRotationWeight = 0.7f; - - [Header("卡组轮转")] - [SerializeField] private int visibleSlotCount = 4; - [SerializeField] private string[] deckDataNames = - { - "人类士兵Data", "弓箭手Data", "盾卫Data", "精锐士兵Data", - "法师Data", "狂暴狼人Data", "石巨人Data", "弓箭猎人Data" - }; - [SerializeField] private CharacterData[] deck; - - private readonly List hand = new List(); - private readonly Queue drawQueue = new Queue(); - private Transform redSpawnPoint; - private AttackTargetController targetController; - private float currentMana; - private float manaTimer; - private float decisionTimer; - private float spawnTimer; - private int lastLane = 1; - private int consecutiveLaneSpawns; - private bool initialized; - - private void Start() - { - redSpawnPoint = FindRedSpawnPoint(); - targetController = AttackTargetController.Instance; - currentMana = maxMana; - BuildDeck(); - BuildHand(); - initialized = redSpawnPoint != null && hand.Count > 0; - if (!initialized) - Debug.LogWarning("EnemyCastleAI 初始化失败:缺少红方出兵点或角色卡组。"); - } - - private void Update() - { - if (!initialized) return; - - manaTimer += Time.deltaTime; - while (manaTimer >= manaRegenInterval) - { - manaTimer -= manaRegenInterval; - currentMana = Mathf.Min(maxMana, currentMana + 1f); - } - - decisionTimer -= Time.deltaTime; - spawnTimer -= Time.deltaTime; - if (decisionTimer > 0f || spawnTimer > 0f) return; - decisionTimer = decisionInterval; - - int lane = ChooseLane(); - CharacterData card = ChooseCard(lane); - if (card == null) return; - if (Spawn(card, lane)) - { - currentMana -= 1f; - RotatePlayedCard(card); - spawnTimer = minimumSpawnInterval; - if (lane == lastLane) consecutiveLaneSpawns++; - else consecutiveLaneSpawns = 1; - lastLane = lane; - } - } - - public void AddMana(int amount) - { - if (amount <= 0) return; - currentMana = Mathf.Min(maxMana, currentMana + amount); - } - - public int CurrentMana => Mathf.FloorToInt(currentMana); - - public bool TrySpawnFromPortal(Vector3 spawnPosition, Quaternion spawnRotation) - { - if (!initialized) return false; - - List affordable = new List(); - foreach (CharacterData card in hand) - { - if (card != null && card.unitPrefab != null) - affordable.Add(card); - } - - if (affordable.Count == 0) return false; - - CharacterData selected = affordable[Random.Range(0, affordable.Count)]; - if (!SpawnAt(selected, spawnPosition, spawnRotation, teamId)) return false; - - currentMana -= 1f; - RotatePlayedCard(selected); - return true; - } - - private CharacterData SelectWeightedCard(List cards) - { - return cards == null || cards.Count == 0 ? null : cards[Random.Range(0, cards.Count)]; - } - - private int ChooseLane() - { - float left = ScoreLane(leftLaneX, 0); - float center = ScoreLane(centerLaneX, 1); - float right = ScoreLane(rightLaneX, 2); - - if (consecutiveLaneSpawns >= 2) - { - if (lastLane == 0) left -= 3f; - if (lastLane == 1) center -= 3f; - if (lastLane == 2) right -= 3f; - } - - float best = Mathf.Max(left, Mathf.Max(center, right)); - if (Mathf.Approximately(best, left)) return 0; - if (Mathf.Approximately(best, right)) return 2; - return 1; - } - - private float ScoreLane(float laneX, int lane) - { - float score = 1f; - score += lane == 1 ? 0.8f : 0f; - score += lane == lastLane ? laneRotationWeight : 0f; - - foreach (var unit in FindObjectsOfType()) - { - if (unit == null || unit.teamId != 0) continue; - Vector3 p = unit.transform.position; - if (Mathf.Abs(p.x - laneX) <= laneHalfWidth) - score += enemyUnitWeight; - } - - foreach (var mine in FindObjectsOfType()) - { - if (mine == null) continue; - Vector3 p = mine.transform.position; - if (Mathf.Abs(p.x - laneX) > laneHalfWidth * 1.8f) continue; - UnitTeam team = mine.GetComponent(); - if (team == null || team.teamId != teamId) - score += resourceThreatWeight; - } - - return score; - } - - private CharacterData ChooseCard(int lane) - { - CharacterData best = null; - float bestScore = float.NegativeInfinity; - foreach (var card in hand) - { - if (card == null || card.unitPrefab == null) continue; - float score = Random.Range(0f, 1f); - if (score > bestScore) - { - bestScore = score; - best = card; - } - } - return best; - } - - private void BuildDeck() - { - if (deck != null && deck.Length > 0) return; - - var loadedDeck = new List(); - foreach (string dataName in deckDataNames) - { - CharacterData data = Resources.Load("Data/" + dataName); - if (data == null) - { - Debug.LogWarning($"敌方卡组缺少角色数据: Resources/Data/{dataName}.asset"); - continue; - } - loadedDeck.Add(data); - } - deck = loadedDeck.ToArray(); - } - - private void BuildHand() - { - hand.Clear(); - drawQueue.Clear(); - if (deck == null) return; - - int handCount = Mathf.Min(visibleSlotCount, deck.Length); - for (int i = 0; i < handCount; i++) - hand.Add(deck[i]); - for (int i = handCount; i < deck.Length; i++) - drawQueue.Enqueue(deck[i]); - } - - private void RotatePlayedCard(CharacterData playedCard) - { - int handIndex = hand.IndexOf(playedCard); - if (handIndex < 0 || drawQueue.Count == 0) return; - - hand[handIndex] = drawQueue.Dequeue(); - drawQueue.Enqueue(playedCard); - } - - private bool SpawnAt(CharacterData data, Vector3 position, Quaternion rotation, int spawnTeamId) - { - GameObject unit = Instantiate(data.unitPrefab, position, rotation); - UnitTeam team = unit.GetComponent(); - if (team != null) - { - team.teamId = spawnTeamId; - unit.tag = spawnTeamId == 0 ? "Friend" : "Enemy"; - } - - UnitBase unitBase = unit.GetComponent(); - if (unitBase != null) - { - unitBase.InitializeFromPlayerData(data.GetMaxHealth(1), data.GetAttackPower(1), data.GetMoveSpeed(1)); - - // 如果是敌人(teamId != 0),增大寻敌距离 - if (spawnTeamId != 0) - { - unitBase.detectionRange = 100f; // 从默认30增加到100 - } - } - - return true; - } - - private bool Spawn(CharacterData data, int lane) - { - if (!SpawnAt(data, redSpawnPoint.position, redSpawnPoint.rotation, teamId)) return false; - - if (targetController != null) - { - targetController.redTarget = FindLaneTarget(lane); - } - return true; - } - - private GameObject FindLaneTarget(int lane) - { - float x = lane == 0 ? leftLaneX : lane == 2 ? rightLaneX : centerLaneX; - GameObject best = null; - float bestDistance = float.PositiveInfinity; - foreach (var mine in FindObjectsOfType()) - { - if (Mathf.Abs(mine.transform.position.x - x) < laneHalfWidth * 2f) - { - float d = Mathf.Abs(mine.transform.position.z - redSpawnPoint.position.z); - if (d < bestDistance) { bestDistance = d; best = mine.gameObject; } - } - } - return best != null ? best : targetController?.GetEnemyCastleOfTeam(teamId); - } - - private Transform FindRedSpawnPoint() - { - var manager = GetComponent(); - if (manager != null && manager.redSpawnPoint != null) return manager.redSpawnPoint; - var castles = GameObject.Find("红色城堡"); - return castles != null ? castles.transform.Find("出兵点") : null; - } -} diff --git a/Assets/Scripts/建筑脚本/EnemyCastleAI.cs.meta b/Assets/Scripts/建筑脚本/EnemyCastleAI.cs.meta deleted file mode 100644 index 6c3abae..0000000 --- a/Assets/Scripts/建筑脚本/EnemyCastleAI.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: Di4e5COsW3MaOIKjAZpkNB3DV96stk4sKbaXXg7lgL4M9IOQyMJld6Y= -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Scripts/建筑脚本/GoldMine.cs b/Assets/Scripts/建筑脚本/GoldMine.cs deleted file mode 100644 index 4aaefbf..0000000 --- a/Assets/Scripts/建筑脚本/GoldMine.cs +++ /dev/null @@ -1,78 +0,0 @@ -using UnityEngine; - -/// -/// 金矿建筑,定时产出金币 -/// -public class GoldMine : MonoBehaviour -{ - [Header("金币产出")] - [Tooltip("每次产出的金币数量")] - [SerializeField] private int goldPerProduction = 50; - - [Tooltip("产出间隔(秒)")] - [SerializeField] private float productionInterval = 5f; - - [Header("可选:血条和进度条")] - [SerializeField] private WorldHealthBar healthBar; - - private float productionTimer = 0f; - - private void Awake() - { - // 如果没有手动指定,尝试自动获取 - if (healthBar == null) - { - healthBar = GetComponent(); - } - } - - private void Start() - { - // 初始化进度条(使用能量条显示产出进度) - if (healthBar != null) - { - healthBar.maxEnergy = 100f; - healthBar.currentEnergy = 0f; - } - } - - private void Update() - { - if (GoldManager.Instance == null) return; - - productionTimer += Time.deltaTime; - - // 更新进度条 - if (healthBar != null) - { - float progress = Mathf.Clamp01(productionTimer / productionInterval); - healthBar.currentEnergy = progress * 100f; - } - - // 达到产出时间 - if (productionTimer >= productionInterval) - { - ProduceGold(); - productionTimer = 0f; - } - } - - private void ProduceGold() - { - if (GoldManager.Instance != null) - { - GoldManager.Instance.AddGold(goldPerProduction); - Debug.Log($"{gameObject.name} 产出金币 +{goldPerProduction}"); - - // 可以在这里播放特效和音效 - // TODO: 添加金币产出特效 - } - } - - // 在编辑器中显示信息 - private void OnDrawGizmosSelected() - { - Gizmos.color = Color.yellow; - Gizmos.DrawWireSphere(transform.position + Vector3.up * 2f, 0.5f); - } -} diff --git a/Assets/Scripts/建筑脚本/GoldMine.cs.meta b/Assets/Scripts/建筑脚本/GoldMine.cs.meta deleted file mode 100644 index 2060a9f..0000000 --- a/Assets/Scripts/建筑脚本/GoldMine.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: DykfvC7+VnysnFVe0RuuhqYblOX8b3TqKpWkys/vBAvo9QxqFltLb0g= -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Scripts/技能脚本/EliteSoldierSkill.cs b/Assets/Scripts/技能脚本/EliteSoldierSkill.cs index 2c05e89..b5c57f1 100644 --- a/Assets/Scripts/技能脚本/EliteSoldierSkill.cs +++ b/Assets/Scripts/技能脚本/EliteSoldierSkill.cs @@ -13,6 +13,13 @@ public class EliteSoldierSkill : UnitSkill [Min(0f)] public float skillAnimationDuration = 2.22f; + [Header("特效")] + public GameObject groundCrackEffectPrefab; + [Min(0f)] + public float groundCrackForwardDistance = 1.2f; + [Min(0f)] + public float groundCrackHeightOffset = 0.05f; + private bool isSkillReady; public override void ReleaseSkill() @@ -35,6 +42,24 @@ public class EliteSoldierSkill : UnitSkill return; } + if (groundCrackEffectPrefab != null) + { + Vector3 effectPosition = unit.transform.position + + unit.transform.forward * groundCrackForwardDistance; + effectPosition.y += groundCrackHeightOffset; + + GameObject effectObject = Instantiate( + groundCrackEffectPrefab, + effectPosition, + groundCrackEffectPrefab.transform.rotation); + + ShockwaveRing shockwave = effectObject.GetComponent(); + if (shockwave != null) + { + shockwave.Play(); + } + } + unit.ApplyAreaSkillDamage(skillRadius, skillDamage, false); isSkillReady = false; } diff --git a/Assets/Scripts/技能脚本/StoneGolemSkill.cs b/Assets/Scripts/技能脚本/StoneGolemSkill.cs index cb02ce5..e8aec1b 100644 --- a/Assets/Scripts/技能脚本/StoneGolemSkill.cs +++ b/Assets/Scripts/技能脚本/StoneGolemSkill.cs @@ -46,14 +46,10 @@ public class StoneGolemSkill : UnitSkill { Vector3 effectPosition = unit.transform.position; var effectObj = Instantiate(shockwaveEffectPrefab, effectPosition, shockwaveEffectPrefab.transform.rotation); - - // 可选:动态配置特效参数(不配置则使用Prefab默认值) - var effect = effectObj.GetComponent(); - if (effect != null) + ShockwaveRing shockwave = effectObj.GetComponent(); + if (shockwave != null) { - // 根据技能范围动态设置扩散半径 - effect.overrideRadius = skillRadius; - // 可以设置颜色,例如:effect.overrideColor = new Color(1f, 0.8f, 0.2f, 1f); + shockwave.Play(); } } diff --git a/Assets/Scripts/投射物和特效/Projectile.cs b/Assets/Scripts/投射物和特效/Projectile.cs index f347c13..b42bd90 100644 --- a/Assets/Scripts/投射物和特效/Projectile.cs +++ b/Assets/Scripts/投射物和特效/Projectile.cs @@ -122,11 +122,9 @@ public class Projectile : MonoBehaviour } UnitBase targetUnit = hitObject.GetComponentInParent(); - CrystalMineCapture crystalMine = hitObject.GetComponentInParent(); - BuildingHealth targetBuilding = hitObject.GetComponentInParent(); WorldHealthBar targetHealthBar = hitObject.GetComponentInParent(); - if (targetUnit == null && crystalMine == null && targetBuilding == null && targetHealthBar == null) + if (targetUnit == null && targetHealthBar == null) { return; } @@ -137,14 +135,6 @@ public class Projectile : MonoBehaviour { targetUnit.ReceiveDamage(damage, owner); } - else if (crystalMine != null) - { - crystalMine.ReceiveCaptureDamage(damage, owner); - } - else if (targetBuilding != null) - { - targetBuilding.ReceiveDamage(damage, owner); - } else if (targetHealthBar != null) { // 召唤师等特殊单位(有 WorldHealthBar 但没有 UnitBase) diff --git a/Assets/Scripts/数据脚本/CharacterData.cs b/Assets/Scripts/数据脚本/CharacterData.cs index 07ebc7e..73e968a 100644 --- a/Assets/Scripts/数据脚本/CharacterData.cs +++ b/Assets/Scripts/数据脚本/CharacterData.cs @@ -1,11 +1,20 @@ using UnityEngine; +public enum CharacterRarity +{ + Blue = 0, + Orange = 1, + Purple = 2, + Red = 3 +} + [CreateAssetMenu(fileName = "NewCharacterData", menuName = "召唤之战/角色数据")] public class CharacterData : ScriptableObject { [Header("基础信息")] public string characterId = "unknown"; public string characterName = "未命名角色"; + public CharacterRarity rarity = CharacterRarity.Blue; [TextArea(2, 4)] public string description = ""; diff --git a/Assets/Scripts/数据脚本/DeployGrid.cs b/Assets/Scripts/数据脚本/DeployGrid.cs index 45556ad..fb696ed 100644 --- a/Assets/Scripts/数据脚本/DeployGrid.cs +++ b/Assets/Scripts/数据脚本/DeployGrid.cs @@ -2,20 +2,22 @@ using UnityEngine; /// /// 部署网格的几何参数与坐标换算。 -/// 阵型编排场景和战斗场景共用同一份参数,保证两边的格位完全对齐。 +/// 网格与场景里用于标记布阵区域的那个 Plane 完全重合: +/// Plane 世界范围 X -5.75..5.75、Z -15.6..-4.4,中心 (0, ?, -10)。 +/// 4 列 × 4 行,正好铺满这块区域;整体位于 NavMesh 覆盖范围内。 /// public static class DeployGrid { - public const int Cols = 6; - public const int Rows = 5; - public const float ColStep = 2.4f; // 列间距改为2.4,让网格更紧凑,避免最边缘格子太靠外 - public const float RowStep = 2.8f; // 行间距保持2.8 - public const float BackZ = -15.0f; // 最靠后一排的中心 Z(调整到靠近摄像机的底部区域) - public const float CellWidth = 2.5f; - public const float CellDepth = 2.5f; // 格子深度改为2.5,与宽度相同,形成正方形 + public const int Cols = 4; + public const int Rows = 4; + public const float ColStep = 2.875f; // 11.5 / 4 + public const float RowStep = 2.8f; // 11.2 / 4 + public const float BackZ = -14.2f; // 第 0 排(最靠近镜头)中心 Z = -10 - 1.5*2.8 + public const float CellWidth = 2.815f; // 比间距略小,留出缝,看得出是格子 + public const float CellDepth = 2.74f; public const float CellHeight = 0.03f; - public const float GridY = 0.12f; // 格位可视块的中心高度 - public const float UnitY = 0.16f; // 单位落点高度(与 NavMesh 高度一致) + public const float GridY = 0.115f; // 格位可视块中心高度(贴在布阵平面之上) + public const float UnitY = 0.10f; // 单位落点高度(与烘焙后的 NavMesh 高度一致) public const int CellCount = Cols * Rows; @@ -34,7 +36,23 @@ public static class DeployGrid return new Vector3(x, UnitY, z); } - /// 把地面上的世界坐标吸附到最近格位;不在网格范围内返回 -1。 + /// 整个网格的中心(可视块高度)。 + public static Vector3 GridCenter + { + get + { + float z = BackZ + (Rows - 1) * RowStep * 0.5f; + return new Vector3(0f, GridY, z); + } + } + + /// 网格在 X 方向的宽度。 + public static float GridWidth => Cols * ColStep; + + /// 网格在 Z 方向的深度。 + public static float GridDepth => Rows * RowStep; + + /// 把地面坐标吸附到最近格位;不在网格范围内返回 -1。 public static int SnapToCell(Vector3 world) { int c = Mathf.RoundToInt(world.x / ColStep + (Cols - 1) * 0.5f); @@ -50,6 +68,29 @@ public static class DeployGrid return ToIndex(r, c); } + /// + /// 宽松吸附:超出网格时夹到最近格位,只要离网格边缘不超过 tolerance 个格子就算命中。 + /// 让玩家在网格边缘附近松手也能放下单位。 + /// + public static int SnapToCellClamped(Vector3 world, float tolerance = 0.9f) + { + int c = Mathf.RoundToInt(world.x / ColStep + (Cols - 1) * 0.5f); + int r = Mathf.RoundToInt((world.z - BackZ) / RowStep); + + int clampedC = Mathf.Clamp(c, 0, Cols - 1); + int clampedR = Mathf.Clamp(r, 0, Rows - 1); + + // 超出网格多少(以格为单位) + int overC = c < 0 ? -c : (c >= Cols ? c - (Cols - 1) : 0); + int overR = r < 0 ? -r : (r >= Rows ? r - (Rows - 1) : 0); + if (overC > tolerance || overR > tolerance) + { + return -1; + } + + return ToIndex(clampedR, clampedC); + } + /// 把一组单位在网格宽度内均匀铺开,返回列号。 public static int SpreadColumn(int indexInGroup, int groupCount) { @@ -60,7 +101,7 @@ public static class DeployGrid return Mathf.RoundToInt(step * (indexInGroup + 1)); } - /// 默认阵型格位:近战在最前排(靠近敌人),远程在最后排。 + /// 默认阵型格位:近战在最靠敌方的一排,远程在最后排。 public static int DefaultCell(bool isMelee, int indexInGroup, int groupCount) { int row = isMelee ? Rows - 1 : 0; diff --git a/Assets/Scripts/系统脚本/StatusEffectController.cs b/Assets/Scripts/系统脚本/StatusEffectController.cs index 89ee05e..ab8f332 100644 --- a/Assets/Scripts/系统脚本/StatusEffectController.cs +++ b/Assets/Scripts/系统脚本/StatusEffectController.cs @@ -81,13 +81,28 @@ public class StatusEffectController : MonoBehaviour Bounds bounds = new Bounds(transform.position, Vector3.zero); Renderer[] renderers = GetComponentsInChildren(true); - if (renderers.Length > 0) + bool hasRenderer = false; + foreach (Renderer renderer in renderers) { - bounds = renderers[0].bounds; - for (int i = 1; i < renderers.Length; i++) + if (stunIndicator != null && renderer.transform.IsChildOf(stunIndicator.transform)) { - bounds.Encapsulate(renderers[i].bounds); + continue; } + + if (!hasRenderer) + { + bounds = renderer.bounds; + hasRenderer = true; + } + else + { + bounds.Encapsulate(renderer.bounds); + } + } + + if (!hasRenderer) + { + bounds = new Bounds(transform.position, Vector3.zero); } indicatorTransform.position = new Vector3( diff --git a/Assets/Scripts/角色脚本/MainCharacterDebugMovement.cs b/Assets/Scripts/角色脚本/MainCharacterDebugMovement.cs index ab64c09..92ce3f9 100644 --- a/Assets/Scripts/角色脚本/MainCharacterDebugMovement.cs +++ b/Assets/Scripts/角色脚本/MainCharacterDebugMovement.cs @@ -126,11 +126,6 @@ public class MainCharacterDebugMovement : MonoBehaviour continue; } - if (candidate.GetComponentInParent() == null) - { - continue; - } - // 主建筑按名称优先匹配;找不到时退回第一个己方建筑 if (candidate.name.Contains("主要") || candidate.name.Contains("基地")) { diff --git a/Assets/Scripts/角色脚本/UnitBase.cs b/Assets/Scripts/角色脚本/UnitBase.cs index 36c0c93..e6cdcbe 100644 --- a/Assets/Scripts/角色脚本/UnitBase.cs +++ b/Assets/Scripts/角色脚本/UnitBase.cs @@ -76,13 +76,17 @@ public class UnitBase : MonoBehaviour private bool summonerAttackEnabled = true; [Header("无目标回位")] - [Tooltip("开启后,当前没有敌方单位时返回生成时的初始格位;不限制正常追击距离。")] + [Tooltip("开启后,当前没有敌方单位时返回生成时的初始格位。")] public bool returnToAnchorWhenIdle = false; [Min(0.1f)] public float anchorArrivalDistance = 0.35f; private Vector3 anchorPosition; private bool anchorInitialized; + [Header("阵位守护")] + [Tooltip("开启后,只打「离自己阵位不超过 寻敌视野 detectionRange」的敌人,避免一路推到很远的地方。")] + public bool useAnchorLeash = false; + //角色状态 private State state = State.Alert; @@ -112,6 +116,8 @@ public class UnitBase : MonoBehaviour private float attackSpeedMultiplier = 1f; private UnitSkill unitSkill; private System.Action skillFinishedCallback; + private float skillElapsedTime; + private float skillTimeout; //状态枚举 @@ -183,7 +189,7 @@ public class UnitBase : MonoBehaviour navAgent.speed = speed; navAgent.angularSpeed = 120f; navAgent.acceleration = 8f; - navAgent.stoppingDistance = attackRange * 0.95f; // 接近攻击范围边缘时停止 + navAgent.stoppingDistance = NormalStoppingDistance; // 接近攻击范围边缘时停止 navAgent.autoBraking = true; // NavMesh 使用烘焙平面的高度,不能根据动画帧中的 Renderer 包围盒推算 baseOffset。 @@ -287,6 +293,13 @@ public class UnitBase : MonoBehaviour // Attack 状态在上方单独处理,因此不会被这里打断或切换目标。 target = FindTarget(); + // 阵位守护:目标离自己阵位超过寻敌视野(detectionRange)就不追了,留在阵位附近 + if (target != null && useAnchorLeash && anchorInitialized + && IsBeyondLeash(target.transform.position, detectionRange)) + { + target = null; + } + if (target != null) { // 召唤师模式:不主动追击,站定且攻击开关开启时才攻击射程内目标。 @@ -374,6 +387,11 @@ public class UnitBase : MonoBehaviour public void ApplyStun(float duration) { + if (duration <= 0f) + { + return; + } + EnsureStatusEffectController().ApplyStun(duration); } @@ -455,6 +473,20 @@ public class UnitBase : MonoBehaviour return Vector3.Distance(current, anchor) <= anchorArrivalDistance; } + /// 某个世界坐标是否离锚点超过了指定距离(只算水平距离)。 + private bool IsBeyondLeash(Vector3 worldPosition, float maxDistance) + { + if (!anchorInitialized) return false; + Vector3 anchor = anchorPosition; + anchor.y = 0f; + Vector3 point = worldPosition; + point.y = 0f; + return Vector3.Distance(anchor, point) > maxDistance; + } + + /// 追击/接敌时用的停靠距离(贴着攻击范围边缘停下)。 + private float NormalStoppingDistance => Mathf.Max(0f, attackRange * 0.95f); + /// /// 重置锚点位置到当前位置(用于复活等场景) /// @@ -468,11 +500,7 @@ public class UnitBase : MonoBehaviour { if (navAgent == null || !anchorInitialized) { - if (!summonerMode) - { - animator.SetInteger("speed", 0); - animator.speed = 1f; // 重置动画播放速度 - } + RestoreIdleSpeed(); return; } @@ -483,11 +511,7 @@ public class UnitBase : MonoBehaviour if (!navAgent.isOnNavMesh) { - if (!summonerMode) - { - animator.SetInteger("speed", 0); - animator.speed = 1f; // 重置动画播放速度 - } + RestoreIdleSpeed(); return; } @@ -497,22 +521,41 @@ public class UnitBase : MonoBehaviour navAgent.ResetPath(); transform.position = new Vector3(anchorPosition.x, transform.position.y, anchorPosition.z); navAgent.nextPosition = transform.position; - if (!summonerMode) - { - animator.SetInteger("speed", 0); - animator.speed = 1f; // 重置动画播放速度 - } + RestoreIdleSpeed(); return; } navAgent.isStopped = false; + // 回位必须贴到锚点:攻击用的停靠距离会把 agent 挡在半路(远程角色尤其明显) + navAgent.stoppingDistance = 0f; if (Time.time >= nextPathUpdateTime) { navAgent.SetDestination(anchorPosition); nextPathUpdateTime = Time.time + PathUpdateInterval; } - animator.SetInteger("speed", navAgent.velocity.sqrMagnitude > 0.01f ? 1 : 0); - animator.speed = 1f; // 确保移动时动画速度正常 + + // 用正常速度走回格位 + navAgent.speed = speed; + if (!summonerMode) + { + animator.SetInteger("speed", navAgent.velocity.sqrMagnitude > 0.01f ? 1 : 0); + animator.speed = 1f; // 确保走路动画速度正常 + } + } + + /// 回位结束或无法寻路时,把速度和动画恢复成正常站定状态。 + private void RestoreIdleSpeed() + { + if (navAgent != null && navAgent.enabled) + { + navAgent.speed = speed; + navAgent.stoppingDistance = NormalStoppingDistance; + } + if (!summonerMode && animator != null) + { + animator.SetInteger("speed", 0); + animator.speed = 1f; + } } //目标决策:只寻找 detectionRange 内的敌方战斗单位;范围内没有敌人时原地待机或回到锚点。 @@ -837,21 +880,6 @@ public class UnitBase : MonoBehaviour return; } - CrystalMineCapture targetCrystalMine = opponent.GetComponentInParent(); - if (targetCrystalMine != null && targetCrystalMine.ReceiveCaptureDamage(attackPower, gameObject)) - { - RegisterAttackHit(); - return; - } - - BuildingHealth targetBuilding = opponent.GetComponentInParent(); - if (targetBuilding != null && targetBuilding.ReceiveDamage(attackPower, gameObject)) - { - RegisterAttackHit(); - return; - } - - // 召唤师等特殊单位(有 WorldHealthBar 但没有 UnitBase) WorldHealthBar targetHealthBar = opponent.GetComponentInParent(); if (targetHealthBar != null) { @@ -871,18 +899,6 @@ public class UnitBase : MonoBehaviour UnitBase targetUnit = target.GetComponentInParent(); bool hit = targetUnit != null && targetUnit.ReceiveDamage(damage, gameObject); - if (!hit) - { - CrystalMineCapture targetCrystalMine = target.GetComponentInParent(); - hit = targetCrystalMine != null && targetCrystalMine.ReceiveCaptureDamage(damage, gameObject); - } - - if (!hit) - { - BuildingHealth targetBuilding = target.GetComponentInParent(); - hit = targetBuilding != null && targetBuilding.ReceiveDamage(damage, gameObject); - } - if (!hit) { return; @@ -937,22 +953,9 @@ public class UnitBase : MonoBehaviour } UnitBase targetUnit = opponent.GetComponentInParent(); - BuildingHealth targetBuilding = opponent.GetComponentInParent(); - WorldHealthBar healthBar = null; - - if (targetUnit != null) - { - healthBar = targetUnit.GetComponent(); - } - else if (targetBuilding != null) - { - healthBar = targetBuilding.GetComponent(); - } - else - { - // 召唤师等特殊单位(有 WorldHealthBar 但没有 UnitBase) - healthBar = opponent.GetComponentInParent(); - } + WorldHealthBar healthBar = targetUnit != null + ? targetUnit.GetComponent() + : opponent.GetComponentInParent(); if (healthBar == null || !hitHealthBars.Add(healthBar)) { @@ -963,13 +966,8 @@ public class UnitBase : MonoBehaviour { targetUnit.ReceiveDamage(damage, gameObject); } - else if (targetBuilding != null) + else { - targetBuilding.ReceiveDamage(damage, gameObject); - } - else if (healthBar != null) - { - // 召唤师等特殊单位 healthBar.TakeDamage(damage, gameObject); } } @@ -999,6 +997,7 @@ public class UnitBase : MonoBehaviour // 查找所有带 UnitTeam 的对象(包括单位和召唤师) UnitTeam[] allTeams = FindObjectsOfType(); HashSet hitUnits = new HashSet(); + HashSet hitStatusEffects = new HashSet(); foreach (UnitTeam targetTeam in allTeams) { @@ -1031,7 +1030,7 @@ public class UnitBase : MonoBehaviour // 召唤师等特殊单位(有 StatusEffectController 但没有 UnitBase) StatusEffectController statusEffect = opponent.GetComponentInParent(); - if (statusEffect != null) + if (statusEffect != null && hitStatusEffects.Add(statusEffect)) { statusEffect.ApplyStun(duration); } @@ -1129,6 +1128,11 @@ public class UnitBase : MonoBehaviour skillFinishedCallback = onFinished; isPlayingSkill = true; + skillElapsedTime = 0f; + float animationDuration = GetSkillAnimationDuration(); + skillTimeout = targetDuration > 0f + ? targetDuration + 0.5f + : Mathf.Max(animationDuration + 0.5f, 2f); state = State.Skill; animator.speed = GetSkillAnimationSpeed(targetDuration); animator.SetInteger("speed", 0); @@ -1145,13 +1149,23 @@ public class UnitBase : MonoBehaviour private void CheckSkillAnimationFinished() { + if (!isPlayingSkill) + { + return; + } + + skillElapsedTime += Time.deltaTime; AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0); - if (!stateInfo.IsName("skill") || stateInfo.normalizedTime < 1f) + bool animationFinished = stateInfo.IsName("skill") && stateInfo.normalizedTime >= 1f; + bool timedOut = skillElapsedTime >= skillTimeout; + if (!animationFinished && !timedOut) { return; } isPlayingSkill = false; + skillElapsedTime = 0f; + skillTimeout = 0f; state = State.Alert; animator.speed = attackSpeedMultiplier; skillFinishedCallback?.Invoke(); @@ -1232,6 +1246,10 @@ public class UnitBase : MonoBehaviour if (!navAgent.isOnNavMesh) return; + // 追击时用正常速度和正常停靠距离(可能刚从回位状态切回来) + navAgent.speed = speed; + navAgent.stoppingDistance = NormalStoppingDistance; + // 确保没有被停止 if (navAgent.isStopped) { diff --git a/Assets/UI/Sprites.meta b/Assets/UI/Sprites.meta new file mode 100644 index 0000000..5c19ca2 --- /dev/null +++ b/Assets/UI/Sprites.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: XX4b4Sj+VXxuxB9gb8yVHKpQYSGcJVjr5mzI4RA3uPKfov4bDCvQsZE= +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UI/Sprites/RoundedBar.png b/Assets/UI/Sprites/RoundedBar.png new file mode 100644 index 0000000..5fbde89 Binary files /dev/null and b/Assets/UI/Sprites/RoundedBar.png differ diff --git a/Assets/UI/Sprites/RoundedBar.png.meta b/Assets/UI/Sprites/RoundedBar.png.meta new file mode 100644 index 0000000..27fe30e --- /dev/null +++ b/Assets/UI/Sprites/RoundedBar.png.meta @@ -0,0 +1,163 @@ +fileFormatVersion: 2 +guid: CyxKsCn+AClYPC7V7ifHiA+4oCDYo5bwTLVEuiEPllLn+zIihQs8LIs= +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 14 + 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 + webStreaming: 0 + priorityLevel: 0 + uploadedMode: 2 + 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: 20, y: 20, z: 20, w: 20} + 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: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WeixinMiniGame + maxTextureSize: 2048 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: PlayableAds + maxTextureSize: 2048 + maxPlaceholderSize: 32 + 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: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + doOverrideTextureManagerOperations: 0 + platformOperationGroupSettings: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UI/Sprites/RoundedLabel.png b/Assets/UI/Sprites/RoundedLabel.png new file mode 100644 index 0000000..5af5d03 Binary files /dev/null and b/Assets/UI/Sprites/RoundedLabel.png differ diff --git a/Assets/UI/Sprites/RoundedLabel.png.meta b/Assets/UI/Sprites/RoundedLabel.png.meta new file mode 100644 index 0000000..f4656e6 --- /dev/null +++ b/Assets/UI/Sprites/RoundedLabel.png.meta @@ -0,0 +1,163 @@ +fileFormatVersion: 2 +guid: DisYsXz5AX2mNjLLKaPRDwUt6XTTaQB0eNQaPyYL9K5dwtl6j6Mi/u0= +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 14 + 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 + webStreaming: 0 + priorityLevel: 0 + uploadedMode: 2 + 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: 15, y: 15, z: 15, w: 15} + 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: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: WeixinMiniGame + maxTextureSize: 2048 + maxPlaceholderSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: PlayableAds + maxTextureSize: 2048 + maxPlaceholderSize: 32 + 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: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: 5e97eb03825dee720800000000000000 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + doOverrideTextureManagerOperations: 0 + platformOperationGroupSettings: + userData: + assetBundleName: + assetBundleVariant: diff --git a/CODELY.md b/CODELY.md index a230af6..4465f72 100644 --- a/CODELY.md +++ b/CODELY.md @@ -28,7 +28,8 @@ - [2026-09-29 22:28:50] 英雄复活后不寻敌问题:需要在ReviveHero()中调用unitBase.ResetAnchorPosition()重置锚点位置,否则returnToAnchorWhenIdle=true的英雄会尝试返回旧锚点位置导致卡住 - [2026-10-01 15:45:16] UnitBase动画速度问题:攻击时会设置animator.speed来调整攻击动画速度,但攻击结束后必须在Alert状态和ReturnToAnchor中重置为1.0,否则会导致后续移动动画变慢 - [2026-10-01 15:45:27] 投射物方向问题:使用transform.Translate(Vector3.forward)的投射物必须在Instantiate时计算正确的旋转Quaternion.LookRotation(direction),否则会朝默认方向飞行。已在UnitBase.FireProjectile和FireSkillProjectile中修复 -- [2026-10-02 00:03:51] Do NOT manually instantiate stun VFX in skill scripts like StoneGolemSkill.cs — UnitBase.ApplyAreaStun() handles it internally when the prefab reference is set in Inspector. Keep skill scripts minimal: just call ApplyAreaSkillDamage and ApplyAreaStun +- [2026-10-02 10:27:11] 石巨人地裂技能职责:命中帧实例化并调用 `ShockwaveRing.Play()` 播放地面扩散光圈;范围伤害与眩晕分开处理,`UnitBase.ApplyAreaStun()` 只给范围内每个敌方角色调用其自身 `StatusEffectController.ApplyStun()`,星星特效由角色状态组件生成、跟随和清理。石巨人不应直接实例化眩晕星星特效。 + - [2026-10-02 00:03:51] UnitBase fields: use unit.Camp (property), unit.IsAlive (property), NOT unit.camp or unit.isAlive (do not exist). StatusEffectController is private — access stun logic through public UnitBase methods only ### Project @@ -122,6 +123,14 @@ - [2026-10-01 22:57:06] UnitBase.IsWithinAttackReach 攻击缓冲:基础 buffer=0.2,攻击状态下再 +0.5 防状态抖动(UnitBase.cs 约530行)。buffer 过大会造成"隔空对打"——1.5 时近战实际在2.5米外就开打。 - [2026-10-01 22:57:19] DefenseWaveLevelController 生成小怪时必须显式设置 UnitTeam.teamId=1(仅设 tag="Enemy" 不够),否则 Prefab 上默认 teamId=0 会让小怪被当成友军,双方都不交战。场景中该组件的 enemyPrefabs 列表需配 4 项:castle_blue_guard_q/castle_archer/castle_gold_guard/蓝角蛮卒。 - [2026-10-02 00:03:51] Stone Golem stun VFX prefab path: Assets/Prefabs/特效/眩晕头顶星星/眩晕星星粒子.prefab — already exists, should be referenced in Stone Golem prefab Inspector for ApplyAreaStun to work +- [2026-10-02 15:21:34] 2026-10-02 DefenseTest 人类士兵不移动的根因是 UnitBase 技能状态可能因 Animator 状态名不匹配而永久停在 State.Skill,导致 target=null、NavMeshAgent 无路径。UnitBase.PlaySkillAnimation/CheckSkillAnimationFinished 已加入技能超时兜底:动画正常结束或超过技能时长+缓冲都会恢复 Alert、清理回调并恢复 Animator 速度。 +- [2026-10-03 12:29:08] 2026-10-03 卡牌稀有度系统:CharacterData 有 CharacterRarity(Blue/Orange/Purple/Red),HeroCardUI 通过 BattleFormationSpawner 绑定 CharacterData 后选择对应边框;DefenseTest 五张卡片各有 RarityFrame Image,四种边框 Sprite 已绑定到 HeroCardUI 字段,RectTransform 保持卡片尺寸、可由用户自行调整。初始资源设定:荒野之王 Red;法师、狂暴狼人、盾卫、石巨人、精锐士兵、荒野祭司 Purple;其余现有角色 Blue;Orange 暂未分配。 +- [2026-10-03 23:38:14] DefenseTest场景已改造为开局布阵模式:玩家开局拖动英雄卡到3行6列后三排网格(BackZ=-15),点击开始战斗按钮后开始波次,每波结束英雄回到初始位置。不再预先配置阵容到JSON。已创建DefenseGameFlowController和GridLineVisualizer(红线可视化网格,Y=0.5)。StartBattleButton在BottomUI下。 +- [2026-10-04 09:28:04] 2026-10-04 DefenseTest 开局卡牌拖动修复完成:根本原因是 BattleFormationSpawner 在 Start() 时自动生成英雄(法师/弓箭手),DefenseGameFlowController.InitializeCardDrag() 需要的 HeroRoster.asset 因损坏无法加载。修复方案:1) 重新创建 HeroRoster.asset 包含5个英雄并正确设置 unitPrefab 引用;2) 在场景中禁用 BattleFormationSpawner 组件,塔防版不需要自动生成初始英雄;3) DefenseGameFlowController.roster 字段在场景中配置 HeroRoster 引用。现在开局场上无单位,5张卡片均可拖动,HeroCardDrag 组件和 CanvasGroup 已自动配置。 +- [2026-10-04 10:15:39] 2026-10-04 DefenseTest 布阵拖拽系统重做完成。DeployGrid 常量改为 6列×5行、ColStep=2.8、RowStep=3.0、BackZ=-9(旧值 -15 落在 NavMesh 之外,单位会卡住)。战场/部署网格 的30个格位由 DefenseGameFlowController.AlignGridCells 按命名「格位_行_列」自动摆到 DeployGrid 坐标,布阵阶段显示、开战隐藏。新增 DeployHighlight(绿=可放/红=已占用,公开 IsVisible/IsBlocked/ShownCell),HeroCardDrag 重写为「生成半透明英雄幽灵跟随指针 + 平面射线吸附格位」,DefenseGameFlowController 增加 Instance/IsDeployPhase/PlaceHeroFromCard/IsCellOccupied/IsCardPlaced/RemoveHeroAt,点击已放置英雄可撤回(Update 里 Physics.Raycast 命中 UnitBase)。场景新增 StartBattleButton(Canvas 根、bottom-center、y=360、圆角绿底),deploymentUI 必须保持 null——英雄卡面板战斗中要一直显示血量/复活。血条隐藏要操作 WorldHealthBar.Awake 生成的子物体 "WorldHealthBar",不是组件所在的对象。 +- [2026-10-04 11:15:47] 2026-10-04 DefenseTest 布阵区域改为 4×4 并与用户新建的 Plane 完全重合。DeployGrid 常量:Cols=4、Rows=4、ColStep=2.875、RowStep=2.8、BackZ=-14.2、CellWidth=2.815、CellDepth=2.74、GridY=0.115、UnitY=0.10(对齐重烘后的 NavMesh)。Plane 原在 y=0.5 会挡住单位,已降到 y=0.09 并放入 Buildings 层(layer 8)排除烘焙;NavMeshSurface 体积改为 center=(0,1,12) size=(28,12,62) 重烘,NavMesh 高度由 0.16 变 0.095,DefenseWaveLevelController.spawnY 同步改为 0.1。开始游戏按钮改为顶部居中(anchor 上中、anchoredPosition y=-170、420×120)。注意:BattlePlatform 实际只覆盖 Z -22.8..17.2,所以 NavMesh 远端也就到 ~16.9,敌人 spawnZ=20 本身在地面之外(靠 NavMeshAgent 自动吸附),这是既有行为。 +- [2026-10-04 13:12:11] 2026-10-04 英雄打完归位改为"走回去"(正常速度),去掉瞬移。关键坑:UnitBase.Start 里 `navAgent.stoppingDistance = attackRange*0.95` 会让 agent 在到达锚点前就认为"已到达"而停住(法师 5.7 米、盾卫 0.95 米都远大于 anchorArrivalDistance 0.35),所以"走回锚点"以前根本走不到——这正是当初只能瞬移的原因。修法:ReturnToAnchor 里把 stoppingDistance 设 0,RestoreIdleSpeed/move() 里恢复 NormalStoppingDistance。另新增 useAnchorLeash/anchorLeashDistance(英雄设为 10 米,DefenseGameFlowController.heroLeashDistance 控制),目标距锚点超过上限就不追,避免一路推到 Z≈16。DefenseGameFlowController.ResetHeroPositions 现在只清 target 让 UnitBase 自己走回,仅当 NavMesh.SamplePosition 找不到落脚点(真卡住)才瞬移兜底。 +- [2026-10-04 14:12:16] 2026-10-04 DefenseTest 两处修正:1) 阵位守护距离不再单开字段,直接用 UnitBase.detectionRange(已删除 anchorLeashDistance / heroLeashDistance;DefenseGameFlowController 只留开关 heroGuardPost=true,新 bool 字段在旧场景里会反序列化成 false,必须显式写进场景)。出战 5 个英雄 Prefab 的 detectionRange 已从 30/50 调到 10(弓箭手 12)。2) 底部英雄卡的角色改回从 PlayerData.json 的 currentDeck 读(站位不再读),卡面(头像/名字/稀有度)用同一份 CharacterData 刷新(新增 HeroCardUI.SetCharacterInfo,区别于绑定单位的 SetHero),否则会出现「卡面显示人类士兵、拖出来却是法师」的不一致;PlayerData 读不到时兜底用 HeroRoster。注意 CharacterData 里有些角色(荒野之王/荒野流寇等)unitPrefab 为空,不能出战,取阵容时要跳过。 ### Reference - [2026-09-09 12:23:17] 飞行物脚本 Projectile.cs 负责锁敌追踪、碰撞检测和伤害结算。箭矢预制体 ArrowProjectile_White.prefab 已配置 Projectile 组件和 CapsuleCollider(Is Trigger)。远程单位需在攻击动画松弦帧添加 OnAttackEffect Event,并在 UnitBase 中设置 attackType=RangedProjectile、projectilePrefab、projectileSpawnPoint。 diff --git a/ProjectSettings/TagManager.asset b/ProjectSettings/TagManager.asset index b03ad79..363ebb4 100644 --- a/ProjectSettings/TagManager.asset +++ b/ProjectSettings/TagManager.asset @@ -4,6 +4,7 @@ TagManager: serializedVersion: 2 tags: + - DeployGrid - Enemy - Friend - Building