feat(gameplay): 添加建筑系统和改进摄像机控制

- 移除人类士兵数据资产文件,重构为建筑放置系统
- 在CharacterData中添加productionInterval和buildingCost字段用于建筑生产
- 实现CameraFollow脚本的完整重写,支持键盘WASD拖动、鼠标拖动、触摸拖动
- 添加摄像机缩放功能,支持上下键和触摸双指缩放
- 更新Projecttile.cs以同时处理单位和建筑目标的伤害检测
- 修改SummonCardButton从法力值召唤改为金币建筑放置模式
- 在UnitBase.cs中更新攻击逻辑以支持对建筑造成伤害
- 升级WorldHealthBar以显示建筑生产进度和更好的缩放补偿
- 修复MainCharacterDebugMovement移除键盘移动输入冲突
- 更新包管理器中的codely.bridge版本从1.0.80到1.0.81
```
This commit is contained in:
huadexuan committed 2026-09-13 23:35:59 +08:00
1 parent fb56cd7ede
commit 769aea30f3
55 files changed
+9328 -90

No files matched your search

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 MiB

+83
View File
@@ -0,0 +1,83 @@
%YAML 1.1
%TAG !u! tag:yousandi.cn,2023:
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: CoreBattleGround
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords: []
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap: {}
disabledShaderPasses: []
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _BumpScale: 1
- _Cutoff: 0.5
- _DetailNormalMapScale: 1
- _DstBlend: 0
- _GlossMapScale: 1
- _Glossiness: 0.5
- _GlossyReflections: 1
- _Metallic: 0
- _Mode: 0
- _OcclusionStrength: 1
- _Parallax: 0.02
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _UVSec: 0
- _ZWrite: 1
m_Colors:
- _Color: {r: 0.32, g: 0.42, b: 0.38, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
m_BuildTextureStacks: []
@@ -1,8 +1,8 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: DnxLvHioWy/Y8BQTJXvfgy4EY9ORY5NTkgRou5DX6985cCP+TJ5xtIQ= guid: WnpLsS2vAShzdOXoP7o5YodfqCDYBbHYuAbS47NODRFpDWZun6kLBjo=
NativeFormatImporter: NativeFormatImporter:
externalObjects: {} externalObjects: {}
mainObjectFileID: 11400000 mainObjectFileID: 2100000
userData: userData:
assetBundleName: assetBundleName:
assetBundleVariant: assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: Bn0e4yKuAXMPZXm/HEj0nVNsJiBMw44/AkfSRi+g0hcYXta3rtuq9SI=
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: Dywe5iylAH6XEIGdwvfCJxIgXDK5UiS8rO/DVcwIVUAVcSk3UpVKc4k=
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+83
View File
@@ -0,0 +1,83 @@
%YAML 1.1
%TAG !u! tag:yousandi.cn,2023:
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: "\u4E3B\u8981"
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords: []
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap: {}
disabledShaderPasses: []
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 2800000, guid: c9f53eb7b7f154ae7a8c882db66a6e18, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _BumpScale: 1
- _Cutoff: 0.5
- _DetailNormalMapScale: 1
- _DstBlend: 0
- _GlossMapScale: 1
- _Glossiness: 0.5
- _GlossyReflections: 1
- _Metallic: 0
- _Mode: 0
- _OcclusionStrength: 1
- _Parallax: 0.02
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _UVSec: 0
- _ZWrite: 1
m_Colors:
- _Color: {r: 1, g: 1, b: 1, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
m_BuildTextureStacks: []
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: D3tNsCqsVX5SNSCJc7MiOuD/cTLJhSI3NaXZJ2yLx8z4C7InMlVlMtE=
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:
+163
View File
@@ -0,0 +1,163 @@
fileFormatVersion: 2
guid: XHNJsCn4AXyoYvN8Fsi3OMhMP2GvbCPUFnVrNUIUrDy5C/K/hdovc8c=
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 14
mipmaps:
mipMapMode: 0
enableMipMap: 1
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: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
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: 0
spriteTessellationDetail: -1
textureType: 0
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:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0
doOverrideTextureManagerOperations: 0
platformOperationGroupSettings:
userData:
assetBundleName:
assetBundleVariant:
Binary file not shown.
@@ -0,0 +1,210 @@
fileFormatVersion: 2
guid: Bnwesnv7V3KdvMCJ5yCtZreTTprGblFQaxyj6gqcucZU/ThfbCzquRQ=
ModelImporter:
serializedVersion: 22361
internalIDToNameTable: []
externalObjects:
- first:
type: UnityEngine:Material
assembly: UnityEngine.CoreModule
name: Material.001
second: {fileID: 2100000, guid: 01b50165eeecb42dd8995b91984d4cdb, type: 2}
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: 1
aCLCompressionLevel: 3
aCLCurvePrecision: 0.01
aCLFastSampleMode: 1
animationRotationError: 0.5
animationPositionError: 0.5
animationScaleError: 0.5
animationWrapMode: 0
extraExposedTransformPaths: []
extraUserProperties: []
clipAnimations: []
isReadable: 0
tuanjieGIEnable: 0
tuanjieGIGenSDFFactor: 1
tuanjieGIGenSDFBias: 0.25
tuanjieGIDoubleSidedMode: 0
tuanjieGIGenFacetNums: 12
meshes:
lODScreenPercentages: []
globalScale: 3
meshCompression: 0
totalVerticesCount: 8635
totalTrianglesCount: 4998
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:
- index: 0
meshName: node_0
lodLevel: 0
meshGeometryBuffer: 0
supportVGMeshes:
- index: 0
meshName: node_0
lodLevel: 0
meshGeometryBuffer: 0
tangentSpace:
normalSmoothAngle: 60
normalImportMode: 0
tangentImportMode: 3
normalCalculationMode: 4
legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0
blendShapeNormalImportMode: 1
normalSmoothingSource: 0
referencedClips: []
importAnimation: 1
overrideDefaultPose: 0
humanDescription:
serializedVersion: 3
human: []
skeleton: []
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: 0.03
rootMotionBoneName:
defaultPoseIndex: -1
hasTranslationDoF: 0
hasExtraRoot: 0
skeletonHasParents: 1
lastHumanDescriptionAvatarSource: {instanceID: 0}
autoGenerateAvatarMappingIfUnspecified: 1
animationType: 2
humanoidOversampling: 1
avatarSetup: 0
addHumanoidExtraRootOnlyWhenUsingAvatar: 1
importBlendShapeDeformPercent: 1
remapMaterialsIfMaterialImportModeIsNone: 0
additionalBone: 0
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: XitOvCmuVXhPm4JTxqm2zu0uEn85J2Ft0HxxaKHsDzL8ypO2tfocVHU=
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
Binary file not shown.
+210
View File
@@ -0,0 +1,210 @@
fileFormatVersion: 2
guid: C3scsn6tVynfgQkR+aT/N6/sDZmhJuIs7IXeUysy/YRWtlKUwtdiOi8=
ModelImporter:
serializedVersion: 22361
internalIDToNameTable: []
externalObjects:
- first:
type: UnityEngine:Material
assembly: UnityEngine.CoreModule
name: Material.003
second: {fileID: 2100000, guid: 4c0f909e51cc44d19a8ba9c9cc6a4020, type: 2}
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: 1
aCLCompressionLevel: 3
aCLCurvePrecision: 0.01
aCLFastSampleMode: 1
animationRotationError: 0.5
animationPositionError: 0.5
animationScaleError: 0.5
animationWrapMode: 0
extraExposedTransformPaths: []
extraUserProperties: []
clipAnimations: []
isReadable: 0
tuanjieGIEnable: 0
tuanjieGIGenSDFFactor: 1
tuanjieGIGenSDFBias: 0.25
tuanjieGIDoubleSidedMode: 0
tuanjieGIGenFacetNums: 12
meshes:
lODScreenPercentages: []
globalScale: 2.5
meshCompression: 0
totalVerticesCount: 4461
totalTrianglesCount: 2500
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:
- index: 0
meshName: node_0
lodLevel: 0
meshGeometryBuffer: 0
supportVGMeshes:
- index: 0
meshName: node_0
lodLevel: 0
meshGeometryBuffer: 0
tangentSpace:
normalSmoothAngle: 60
normalImportMode: 0
tangentImportMode: 3
normalCalculationMode: 4
legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0
blendShapeNormalImportMode: 1
normalSmoothingSource: 0
referencedClips: []
importAnimation: 1
overrideDefaultPose: 0
humanDescription:
serializedVersion: 3
human: []
skeleton: []
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: 0.024999999
rootMotionBoneName:
defaultPoseIndex: -1
hasTranslationDoF: 0
hasExtraRoot: 0
skeletonHasParents: 1
lastHumanDescriptionAvatarSource: {instanceID: 0}
autoGenerateAvatarMappingIfUnspecified: 1
animationType: 2
humanoidOversampling: 1
avatarSetup: 0
addHumanoidExtraRootOnlyWhenUsingAvatar: 1
importBlendShapeDeformPercent: 1
remapMaterialsIfMaterialImportModeIsNone: 0
additionalBone: 0
userData:
assetBundleName:
assetBundleVariant:
+83
View File
@@ -0,0 +1,83 @@
%YAML 1.1
%TAG !u! tag:yousandi.cn,2023:
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: "\u5175\u8425"
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords: []
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap: {}
disabledShaderPasses: []
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 2800000, guid: 893f1add8bde64ec78423ac9afe16558, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _BumpScale: 1
- _Cutoff: 0.5
- _DetailNormalMapScale: 1
- _DstBlend: 0
- _GlossMapScale: 1
- _Glossiness: 0.5
- _GlossyReflections: 1
- _Metallic: 0
- _Mode: 0
- _OcclusionStrength: 1
- _Parallax: 0.02
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _UVSec: 0
- _ZWrite: 1
m_Colors:
- _Color: {r: 1, g: 1, b: 1, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
m_BuildTextureStacks: []
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: Cykf4yOtWi4ANiIMofDOj5EaGS6UTiupwWsEgXOajmv3Wf9oVoAlkXI=
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:
+163
View File
@@ -0,0 +1,163 @@
fileFormatVersion: 2
guid: B3Mc4yv8By+bp/XTV8UzPbCc9AQscRj/dHLur+fYRqN1YX51kyw31Rs=
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 14
mipmaps:
mipMapMode: 0
enableMipMap: 1
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: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
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: 0
spriteTessellationDetail: -1
textureType: 0
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:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0
doOverrideTextureManagerOperations: 0
platformOperationGroupSettings:
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: W3JJsC6sW3jUx3T13N7U3O900QyO3xZuiYnnFrPA/S100XMKQH/5Hs4=
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
Binary file not shown.
+210
View File
@@ -0,0 +1,210 @@
fileFormatVersion: 2
guid: DH9NvH/4Vn3QQ1137Ubsh80XrP34q8/hmcKBXfpfXohjkkO190osopk=
ModelImporter:
serializedVersion: 22361
internalIDToNameTable: []
externalObjects:
- first:
type: UnityEngine:Material
assembly: UnityEngine.CoreModule
name: Material.002
second: {fileID: 2100000, guid: 7058189db7c2b4e4b8942326a3034a21, type: 2}
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: 1
aCLCompressionLevel: 3
aCLCurvePrecision: 0.01
aCLFastSampleMode: 1
animationRotationError: 0.5
animationPositionError: 0.5
animationScaleError: 0.5
animationWrapMode: 0
extraExposedTransformPaths: []
extraUserProperties: []
clipAnimations: []
isReadable: 0
tuanjieGIEnable: 0
tuanjieGIGenSDFFactor: 1
tuanjieGIGenSDFBias: 0.25
tuanjieGIDoubleSidedMode: 0
tuanjieGIGenFacetNums: 12
meshes:
lODScreenPercentages: []
globalScale: 3
meshCompression: 0
totalVerticesCount: 10051
totalTrianglesCount: 4996
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:
- index: 0
meshName: node_0
lodLevel: 0
meshGeometryBuffer: 0
supportVGMeshes:
- index: 0
meshName: node_0
lodLevel: 0
meshGeometryBuffer: 0
tangentSpace:
normalSmoothAngle: 60
normalImportMode: 0
tangentImportMode: 3
normalCalculationMode: 4
legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0
blendShapeNormalImportMode: 1
normalSmoothingSource: 0
referencedClips: []
importAnimation: 1
overrideDefaultPose: 0
humanDescription:
serializedVersion: 3
human: []
skeleton: []
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: 0.03
rootMotionBoneName:
defaultPoseIndex: -1
hasTranslationDoF: 0
hasExtraRoot: 0
skeletonHasParents: 1
lastHumanDescriptionAvatarSource: {instanceID: 0}
autoGenerateAvatarMappingIfUnspecified: 1
animationType: 2
humanoidOversampling: 1
avatarSetup: 0
addHumanoidExtraRootOnlyWhenUsingAvatar: 1
importBlendShapeDeformPercent: 1
remapMaterialsIfMaterialImportModeIsNone: 0
additionalBone: 0
userData:
assetBundleName:
assetBundleVariant:
+83
View File
@@ -0,0 +1,83 @@
%YAML 1.1
%TAG !u! tag:yousandi.cn,2023:
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: "\u91D1\u77FF"
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords: []
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap: {}
disabledShaderPasses: []
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 2800000, guid: 0f1f0b0e471e4475d976627795f53005, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _BumpScale: 1
- _Cutoff: 0.5
- _DetailNormalMapScale: 1
- _DstBlend: 0
- _GlossMapScale: 1
- _Glossiness: 0.5
- _GlossyReflections: 1
- _Metallic: 0
- _Mode: 0
- _OcclusionStrength: 1
- _Parallax: 0.02
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _UVSec: 0
- _ZWrite: 1
m_Colors:
- _Color: {r: 1, g: 1, b: 1, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
m_BuildTextureStacks: []
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: CHoavSulWi+EWE32SfEyqUBbWQpfjWvpoOK7UERa9+gKez4samGwvVM=
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:
+163
View File
@@ -0,0 +1,163 @@
fileFormatVersion: 2
guid: Dywe4yr/Uy6ZwPMFoZ96bnQl7umQlbWBGIXpcoubbzK1foPvAGg2baE=
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 14
mipmaps:
mipMapMode: 0
enableMipMap: 1
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: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
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: 0
spriteTessellationDetail: -1
textureType: 0
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:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0
doOverrideTextureManagerOperations: 0
platformOperationGroupSettings:
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: W39MsSv+V3y/gDNpKx3/9Y26UZXsxmdQeLuWqOvNqAM1nMybqnfP/q8=
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+139
View File
@@ -0,0 +1,139 @@
%YAML 1.1
%TAG !u! tag:yousandi.cn,2023:
--- !u!1001 &1576419828942378800
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: -8679921383154817045, guid: 4137d04b576874ad5bfa5caa05c5d75f,
type: 3}
propertyPath: m_LocalPosition.x
value: -0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 4137d04b576874ad5bfa5caa05c5d75f,
type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 4137d04b576874ad5bfa5caa05c5d75f,
type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 4137d04b576874ad5bfa5caa05c5d75f,
type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 4137d04b576874ad5bfa5caa05c5d75f,
type: 3}
propertyPath: m_LocalRotation.x
value: -0.00000003774895
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 4137d04b576874ad5bfa5caa05c5d75f,
type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 4137d04b576874ad5bfa5caa05c5d75f,
type: 3}
propertyPath: m_LocalRotation.z
value: -0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 4137d04b576874ad5bfa5caa05c5d75f,
type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 4137d04b576874ad5bfa5caa05c5d75f,
type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 4137d04b576874ad5bfa5caa05c5d75f,
type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 919132149155446097, guid: 4137d04b576874ad5bfa5caa05c5d75f,
type: 3}
propertyPath: m_Name
value: "\u5175\u8425"
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents:
- targetCorrespondingSourceObject: {fileID: 919132149155446097, guid: 4137d04b576874ad5bfa5caa05c5d75f,
type: 3}
insertIndex: -1
addedObject: {fileID: 7297444463306436437}
- targetCorrespondingSourceObject: {fileID: 919132149155446097, guid: 4137d04b576874ad5bfa5caa05c5d75f,
type: 3}
insertIndex: -1
addedObject: {fileID: 7049005926872886096}
- targetCorrespondingSourceObject: {fileID: 919132149155446097, guid: 4137d04b576874ad5bfa5caa05c5d75f,
type: 3}
insertIndex: -1
addedObject: {fileID: 6535874508271334648}
m_SourcePrefab: {fileID: 100100000, guid: 4137d04b576874ad5bfa5caa05c5d75f, type: 3}
--- !u!1 &1811001936706742881 stripped
GameObject:
m_CorrespondingSourceObject: {fileID: 919132149155446097, guid: 4137d04b576874ad5bfa5caa05c5d75f,
type: 3}
m_PrefabInstance: {fileID: 1576419828942378800}
m_PrefabAsset: {fileID: 0}
--- !u!114 &7297444463306436437
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1811001936706742881}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 9355c53f591d4459ea620fc8191efa17, type: 3}
m_Name:
m_EditorClassIdentifier:
maxHealth: 100
currentHealth: 100
maxEnergy: 100
currentEnergy: 0
heightOffset: 0.25
barWidth: 1.2
borderColor: {r: 0.03, g: 0.03, b: 0.03, a: 0.95}
deathEffectDuration: 1.1
deathEffectColor: {r: 0.55, g: 0.9, b: 1, a: 1}
--- !u!114 &7049005926872886096
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1811001936706742881}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 0664b986337964243879f685b5c49aba, type: 3}
m_Name:
m_EditorClassIdentifier:
maxHealth: 500
--- !u!114 &6535874508271334648
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1811001936706742881}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 282625ec862664fd9851af4713c22826, type: 3}
m_Name:
m_EditorClassIdentifier:
characterData: {fileID: 0}
unitTag: Friend
spawnPoint: {fileID: 0}
progressBar: {fileID: 0}
characterIcon: {fileID: 0}
+7
View File
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: Bi5Ks3+rV3zdTjjilQTecvr28Cabbw8GH/mcf2SvOthx3sMZhCVLlp8=
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+70
View File
@@ -0,0 +1,70 @@
%YAML 1.1
%TAG !u! tag:yousandi.cn,2023:
--- !u!1001 &4897434639390281154
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: -8679921383154817045, guid: 35b9ee56f1163491d957e1903bfedf03,
type: 3}
propertyPath: m_LocalPosition.x
value: -0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 35b9ee56f1163491d957e1903bfedf03,
type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 35b9ee56f1163491d957e1903bfedf03,
type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 35b9ee56f1163491d957e1903bfedf03,
type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 35b9ee56f1163491d957e1903bfedf03,
type: 3}
propertyPath: m_LocalRotation.x
value: -0.00000003774895
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 35b9ee56f1163491d957e1903bfedf03,
type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 35b9ee56f1163491d957e1903bfedf03,
type: 3}
propertyPath: m_LocalRotation.z
value: -0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 35b9ee56f1163491d957e1903bfedf03,
type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 35b9ee56f1163491d957e1903bfedf03,
type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 35b9ee56f1163491d957e1903bfedf03,
type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 919132149155446097, guid: 35b9ee56f1163491d957e1903bfedf03,
type: 3}
propertyPath: m_Name
value: "\u91D1\u77FF"
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 35b9ee56f1163491d957e1903bfedf03, type: 3}
+7
View File
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: CX8Y4yirW3kgVNwkfakwJbSuM99wajh48nJl2yWAukMMZ9t+XgcerEs=
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -1,28 +0,0 @@
%YAML 1.1
%TAG !u! tag:yousandi.cn,2023:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 6769361b152df4efb933934b84a6e673, type: 3}
m_Name: HumanSoldierData
m_EditorClassIdentifier:
characterId: human_soldier
characterName: "\u4EBA\u7C7B\u58EB\u5175"
description: "\u57FA\u7840\u8FD1\u6218\u5355\u4F4D\uFF0C\u653B\u51FB\u529B\u9002\u4E2D\uFF0C\u9002\u5408\u524D\u6392\u4F5C\u6218"
cardIcon: {fileID: 21300000, guid: ac0c2d42f9a144e5b9e9b0d16590d58b, type: 3}
unitPrefab: {fileID: 7945271050725079514, guid: 04ae1b1fe51474dda8ae5daf0b1df7c1,
type: 3}
manaCost: 2
cooldownTime: 1
baseMaxHealth: 100
baseAttackPower: 50
baseMoveSpeed: 3
healthPerLevel: 10
attackPerLevel: 5
moveSpeedPerLevel: 0
@@ -20,6 +20,8 @@ MonoBehaviour:
type: 3} type: 3}
manaCost: 2 manaCost: 2
cooldownTime: 1 cooldownTime: 1
productionInterval: 8
buildingCost: 100
baseMaxHealth: 100 baseMaxHealth: 100
baseAttackPower: 50 baseAttackPower: 50
baseMoveSpeed: 3 baseMoveSpeed: 3
@@ -20,6 +20,8 @@ MonoBehaviour:
type: 3} type: 3}
manaCost: 3 manaCost: 3
cooldownTime: 1 cooldownTime: 1
productionInterval: 10
buildingCost: 100
baseMaxHealth: 80 baseMaxHealth: 80
baseAttackPower: 60 baseAttackPower: 60
baseMoveSpeed: 3.5 baseMoveSpeed: 3.5
+2
View File
@@ -20,6 +20,8 @@ MonoBehaviour:
type: 3} type: 3}
manaCost: 6 manaCost: 6
cooldownTime: 1 cooldownTime: 1
productionInterval: 12
buildingCost: 100
baseMaxHealth: 70 baseMaxHealth: 70
baseAttackPower: 100 baseAttackPower: 100
baseMoveSpeed: 3 baseMoveSpeed: 3
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: DX9OsC6lVyqkk3ryvPTWPBTG/Su65dAaznAkwlk3L9HAZlFZvyPuXCg=
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+114
View File
@@ -0,0 +1,114 @@
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<BuildingHealth>();
if (characterData != null)
{
spawnInterval = Mathf.Max(0.1f, characterData.productionInterval);
// 设置角色头像
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;
// 如果单位有UnitBase组件,使用1级属性初始化
var unitBase = unit.GetComponent<UnitBase>();
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;
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: DXIdsyioBigBGeEulZR6ss5x+lvhWguS629tEmVGciD4+vPwhCsbs3I=
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+42
View File
@@ -0,0 +1,42 @@
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<WorldHealthBar>();
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;
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: D3wZsXikW33LIZvtpWVBFbW5HacE/bCypHDY2MmwlMdqllT4Bj7rSz8=
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+242
View File
@@ -0,0 +1,242 @@
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<GameObject> placedBuildings = new List<GameObject>();
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 = currentCharacterData != null ? currentCharacterData.buildingCost : 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<BuildingHealth>() == null)
{
building.AddComponent<BuildingHealth>();
}
if (currentCharacterData != null)
{
Barracks barracks = building.GetComponent<Barracks>();
if (barracks == null)
{
barracks = building.AddComponent<Barracks>();
}
barracks.characterData = currentCharacterData;
}
else if (building.GetComponent<GoldMine>() == null)
{
building.AddComponent<GoldMine>();
}
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>())
{
renderer.sharedMaterial = material;
}
}
private void SetCollidersEnabled(GameObject target, bool enabled)
{
foreach (Collider collider in target.GetComponentsInChildren<Collider>())
{
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;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: Cy5NsnukUC5AkjhzooAm9meZl92B+OUU/7BkXaSTEi6zwYIGOiVmF7o=
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+128 -20
View File
@@ -2,36 +2,144 @@ using UnityEngine;
public class CameraFollow : MonoBehaviour public class CameraFollow : MonoBehaviour
{ {
public Transform target; // 角色的Transform组件 [Header("拖动控制")]
public Vector3 offset; // 摄像机相对于角色的偏移量 public float keyboardDragSpeed = 10f; // WASD拖动速度(模拟手指拖动屏幕)
public float smoothSpeed = 0.125f; // 摄像机移动的平滑速度 public float mouseDragSpeed = 0.5f; // 鼠标拖动速度
public float touchDragSpeed = 0.5f; // 触摸拖动速度
[Header("缩放控制(正交相机用orthographicSize,透视相机用fieldOfView)")]
public float zoomSpeed = 5f; // 缩放速度
public float minOrthographicSize = 5f; // 正交相机最小size
public float maxOrthographicSize = 20f; // 正交相机最大size
public float minFieldOfView = 30f; // 透视相机最小FOV
public float maxFieldOfView = 90f; // 透视相机最大FOV
[Header("边界限制")] [Header("边界限制")]
public bool enableBounds = true; // 是否启用边界限制 public bool enableBounds = true;
public float minX = -6f; // X轴最小边界 public float minX = -6f;
public float maxX = 6f; // X轴最大边界 public float maxX = 6f;
public float minZ = -30f; // Z轴最小边界(摄像机位置,不是主角位置) public float minZ = -30f;
public float maxZ = 91f; // Z轴最大边界(摄像机位置,不是主角位置) public float maxZ = 91f;
private void LateUpdate() private Vector3 lastMousePosition;
private bool isDragging = false;
private Camera cam;
private void Start()
{ {
if (target == null) cam = GetComponent<Camera>();
if (cam == null)
{ {
return; Debug.LogError("CameraFollow需要挂载在Camera组件上");
}
}
private void Update()
{
HandleKeyboardDrag();
HandleMouseDrag();
HandleKeyboardZoom();
}
private void HandleKeyboardDrag()
{
float horizontal = 0f;
float vertical = 0f;
if (Input.GetKey(KeyCode.W)) vertical = 1f;
if (Input.GetKey(KeyCode.S)) vertical = -1f;
if (Input.GetKey(KeyCode.A)) horizontal = -1f;
if (Input.GetKey(KeyCode.D)) horizontal = 1f;
if (horizontal != 0f || vertical != 0f)
{
Vector3 movement = new Vector3(horizontal, 0, vertical) * keyboardDragSpeed * Time.deltaTime;
MoveCameraWithBounds(movement);
}
}
private void HandleMouseDrag()
{
// 鼠标拖动
if (Input.GetMouseButtonDown(0))
{
lastMousePosition = Input.mousePosition;
isDragging = true;
}
else if (Input.GetMouseButton(0) && isDragging)
{
Vector3 delta = Input.mousePosition - lastMousePosition;
Vector3 movement = new Vector3(-delta.x, 0, -delta.y) * mouseDragSpeed * Time.deltaTime;
MoveCameraWithBounds(movement);
lastMousePosition = Input.mousePosition;
}
else if (Input.GetMouseButtonUp(0))
{
isDragging = false;
} }
Vector3 desiredPosition = target.position + offset; // 触摸拖动(移动设备)
if (Input.touchCount == 1 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
Vector2 touchDelta = Input.GetTouch(0).deltaPosition;
Vector3 movement = new Vector3(-touchDelta.x, 0, -touchDelta.y) * touchDragSpeed * Time.deltaTime;
MoveCameraWithBounds(movement);
}
}
private void HandleKeyboardZoom()
{
if (cam == null) return;
float zoomDelta = 0f;
// 上下键控制缩放
if (Input.GetKey(KeyCode.UpArrow)) zoomDelta = -1f; // 缩小(拉近)
if (Input.GetKey(KeyCode.DownArrow)) zoomDelta = 1f; // 放大(拉远)
// 触摸双指缩放
if (Input.touchCount == 2)
{
Touch touch0 = Input.GetTouch(0);
Touch touch1 = Input.GetTouch(1);
Vector2 touch0PrevPos = touch0.position - touch0.deltaPosition;
Vector2 touch1PrevPos = touch1.position - touch1.deltaPosition;
float prevMagnitude = (touch0PrevPos - touch1PrevPos).magnitude;
float currentMagnitude = (touch0.position - touch1.position).magnitude;
float difference = currentMagnitude - prevMagnitude;
zoomDelta = -difference * 0.01f; // 负号:手指分开=拉近,手指合拢=拉远
}
if (zoomDelta != 0f)
{
if (cam.orthographic)
{
// 正交相机:调整 orthographicSize
float newSize = cam.orthographicSize + zoomDelta * zoomSpeed * Time.deltaTime;
cam.orthographicSize = Mathf.Clamp(newSize, minOrthographicSize, maxOrthographicSize);
}
else
{
// 透视相机:调整 fieldOfView
float newFov = cam.fieldOfView + zoomDelta * zoomSpeed * Time.deltaTime;
cam.fieldOfView = Mathf.Clamp(newFov, minFieldOfView, maxFieldOfView);
}
}
}
private void MoveCameraWithBounds(Vector3 movement)
{
Vector3 newPosition = transform.position + movement;
// 边界限制:摄像机停在边界处,主角可以继续移动
if (enableBounds) if (enableBounds)
{ {
desiredPosition.x = Mathf.Clamp(desiredPosition.x, minX, maxX); newPosition.x = Mathf.Clamp(newPosition.x, minX, maxX);
desiredPosition.z = Mathf.Clamp(desiredPosition.z, minZ, maxZ); newPosition.z = Mathf.Clamp(newPosition.z, minZ, maxZ);
} }
transform.position = Vector3.Lerp( transform.position = newPosition;
transform.position,
desiredPosition,
smoothSpeed);
} }
} }
+7
View File
@@ -22,6 +22,13 @@ public class CharacterData : ScriptableObject
[Min(0f)] [Min(0f)]
public float cooldownTime = 1f; public float cooldownTime = 1f;
[Header("兵营生产")]
[Min(0.1f)]
public float productionInterval = 5f;
[Min(0)]
public int buildingCost = 100;
[Header("基础属性(1级)")] [Header("基础属性(1级)")]
[Min(0f)] [Min(0f)]
public float baseMaxHealth = 100f; public float baseMaxHealth = 100f;
+36
View File
@@ -0,0 +1,36 @@
using UnityEngine;
public class GoldMine : MonoBehaviour
{
[Header("产出配置")]
[Min(0)] public int goldPerTick = 5;
[Min(0.1f)] public float productionInterval = 3f;
private float timer;
private BuildingHealth buildingHealth;
private void Awake()
{
buildingHealth = GetComponent<BuildingHealth>();
}
private void Update()
{
if (GoldSystem.Instance == null)
{
return;
}
timer += Time.deltaTime;
if (buildingHealth != null)
{
buildingHealth.SetProductionProgress(timer / productionInterval);
}
while (timer >= productionInterval)
{
timer -= productionInterval;
GoldSystem.Instance.AddGold(goldPerTick);
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: XisXvCP7W3ud7In4Aw0vAdASTrL7i67o+okMla+dirFaiiA027bCSYk=
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+60
View File
@@ -0,0 +1,60 @@
using UnityEngine;
using UnityEngine.UI;
public class GoldSystem : MonoBehaviour
{
public static GoldSystem Instance { get; private set; }
[Header("金币配置")]
[Min(0)] public int startingGold = 200;
[Min(0)] public int maxGold = 9999;
[Header("UI(可选)")]
public Text goldText;
public int CurrentGold { get; private set; }
private void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this;
CurrentGold = startingGold;
UpdateUI();
}
public bool TrySpend(int amount)
{
if (amount < 0 || CurrentGold < amount)
{
return false;
}
CurrentGold -= amount;
UpdateUI();
return true;
}
public void AddGold(int amount)
{
if (amount <= 0)
{
return;
}
CurrentGold = Mathf.Min(CurrentGold + amount, maxGold);
UpdateUI();
}
private void UpdateUI()
{
if (goldText != null)
{
goldText.text = CurrentGold.ToString();
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: WnkatS//B38zOhf5GkU6P+3LfnaKjNkhHT8apytdd5KyzfqefjIzQJE=
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+1 -15
View File
@@ -19,9 +19,7 @@ public class MainCharacterDebugMovement : MonoBehaviour
private Vector3 clickTarget; private Vector3 clickTarget;
private bool hasClickTarget; private bool hasClickTarget;
public bool IsMoving => public bool IsMoving => hasClickTarget;
hasClickTarget ||
new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical")).sqrMagnitude > 0.001f;
private void Start() private void Start()
{ {
@@ -34,18 +32,6 @@ public class MainCharacterDebugMovement : MonoBehaviour
{ {
HandleClickTarget(); HandleClickTarget();
Vector3 keyboardInput = new Vector3(
Input.GetAxisRaw("Horizontal"),
0f,
Input.GetAxisRaw("Vertical"));
if (keyboardInput.sqrMagnitude > 0.001f)
{
hasClickTarget = false;
Move(keyboardInput.normalized);
return;
}
if (!hasClickTarget) if (!hasClickTarget)
{ {
SetWalking(false); SetWalking(false);
+10 -2
View File
@@ -115,13 +115,21 @@ public class Projectile : MonoBehaviour
} }
UnitBase targetUnit = hitObject.GetComponentInParent<UnitBase>(); UnitBase targetUnit = hitObject.GetComponentInParent<UnitBase>();
if (targetUnit == null) BuildingHealth targetBuilding = hitObject.GetComponentInParent<BuildingHealth>();
if (targetUnit == null && targetBuilding == null)
{ {
return; return;
} }
hasHit = true; hasHit = true;
targetUnit.ReceiveDamage(damage, owner); if (targetUnit != null)
{
targetUnit.ReceiveDamage(damage, owner);
}
else
{
targetBuilding.ReceiveDamage(damage, owner);
}
if (registerEnergyOnHit && owner != null) if (registerEnergyOnHit && owner != null)
{ {
UnitBase unit = owner.GetComponent<UnitBase>(); UnitBase unit = owner.GetComponent<UnitBase>();
+14 -7
View File
@@ -67,19 +67,26 @@ public class SummonCardButton : MonoBehaviour
public void OnClick() public void OnClick()
{ {
if (isOnCooldown || characterData == null) if (characterData == null)
{ {
return; return;
} }
if (combat == null) // 检查建筑费用是否足够
if (GoldSystem.Instance == null || GoldSystem.Instance.CurrentGold < characterData.buildingCost)
{ {
combat = FindObjectOfType<MainCharacterCombat>(); Debug.Log($"金币不足,需要{characterData.buildingCost}");
return;
} }
if (combat != null && combat.RequestSummon(summonSlot)) // 触发建筑放置模式
if (BuildingPlacementManager.Instance != null)
{ {
StartCooldown(); BuildingPlacementManager.Instance.StartPlacingBuilding(characterData);
}
else
{
Debug.LogError("找不到 BuildingPlacementManager");
} }
} }
@@ -138,12 +145,12 @@ public class SummonCardButton : MonoBehaviour
private bool CanAfford() private bool CanAfford()
{ {
if (ManaSystem.Instance == null || characterData == null) if (GoldSystem.Instance == null || characterData == null)
{ {
return false; return false;
} }
return ManaSystem.Instance.CurrentManaInt >= characterData.manaCost; return GoldSystem.Instance.CurrentGold >= characterData.buildingCost;
} }
private float GetCooldownTime() private float GetCooldownTime()
+29 -9
View File
@@ -561,12 +561,17 @@ public class UnitBase : MonoBehaviour
private void ApplyDirectDamage(GameObject opponent) private void ApplyDirectDamage(GameObject opponent)
{ {
UnitBase targetUnit = opponent.GetComponentInParent<UnitBase>(); UnitBase targetUnit = opponent.GetComponentInParent<UnitBase>();
if (targetUnit == null || !targetUnit.ReceiveDamage(attackPower, gameObject)) if (targetUnit != null && targetUnit.ReceiveDamage(attackPower, gameObject))
{ {
RegisterAttackHit();
return; return;
} }
RegisterAttackHit(); BuildingHealth targetBuilding = opponent.GetComponentInParent<BuildingHealth>();
if (targetBuilding != null && targetBuilding.ReceiveDamage(attackPower, gameObject))
{
RegisterAttackHit();
}
} }
public void ApplySkillHit(float damageMultiplier, bool registerEnergy) public void ApplySkillHit(float damageMultiplier, bool registerEnergy)
@@ -576,8 +581,17 @@ public class UnitBase : MonoBehaviour
return; return;
} }
float damage = attackPower * Mathf.Max(0f, damageMultiplier);
UnitBase targetUnit = target.GetComponentInParent<UnitBase>(); UnitBase targetUnit = target.GetComponentInParent<UnitBase>();
if (targetUnit == null || !targetUnit.ReceiveDamage(attackPower * Mathf.Max(0f, damageMultiplier), gameObject)) bool hit = targetUnit != null && targetUnit.ReceiveDamage(damage, gameObject);
if (!hit)
{
BuildingHealth targetBuilding = target.GetComponentInParent<BuildingHealth>();
hit = targetBuilding != null && targetBuilding.ReceiveDamage(damage, gameObject);
}
if (!hit)
{ {
return; return;
} }
@@ -621,18 +635,24 @@ public class UnitBase : MonoBehaviour
} }
UnitBase targetUnit = opponent.GetComponentInParent<UnitBase>(); UnitBase targetUnit = opponent.GetComponentInParent<UnitBase>();
if (targetUnit == null) BuildingHealth targetBuilding = opponent.GetComponentInParent<BuildingHealth>();
{ WorldHealthBar healthBar = targetUnit != null
continue; ? targetUnit.GetComponent<WorldHealthBar>()
} : targetBuilding != null ? targetBuilding.GetComponent<WorldHealthBar>() : null;
WorldHealthBar healthBar = targetUnit.GetComponent<WorldHealthBar>();
if (healthBar == null || !hitHealthBars.Add(healthBar)) if (healthBar == null || !hitHealthBars.Add(healthBar))
{ {
continue; continue;
} }
targetUnit.ReceiveDamage(damage, gameObject); if (targetUnit != null)
{
targetUnit.ReceiveDamage(damage, gameObject);
}
else
{
targetBuilding.ReceiveDamage(damage, gameObject);
}
} }
if (registerEnergy) if (registerEnergy)
+28 -4
View File
@@ -94,6 +94,7 @@ public class WorldHealthBar : MonoBehaviour
{ {
if (barRect == null) return; if (barRect == null) return;
barRect.localPosition = GetBarRootPosition(); barRect.localPosition = GetBarRootPosition();
ApplyScaleCompensation();
// 优先使用场景中名称完全为 Main Camera 的摄像机。 // 优先使用场景中名称完全为 Main Camera 的摄像机。
Camera camera = FindMainCamera(); Camera camera = FindMainCamera();
@@ -167,13 +168,19 @@ public class WorldHealthBar : MonoBehaviour
// 清空技能能量并刷新能量条。 // 清空技能能量并刷新能量条。
public void ResetEnergy() public void ResetEnergy()
{
SetEnergy(0f);
}
// 设置下方条的当前填充值;单位用于技能能量,建筑用于生产进度。
public void SetEnergy(float value)
{ {
if (isDead) if (isDead)
{ {
return; return;
} }
currentEnergy = 0f; currentEnergy = Mathf.Clamp(value, 0f, maxEnergy);
UpdateEnergyFill(); UpdateEnergyFill();
} }
@@ -327,7 +334,10 @@ public class WorldHealthBar : MonoBehaviour
worldWidth = barWidth; worldWidth = barWidth;
// 水平方向固定对齐单位根节点,只使用模型顶部计算血条高度。 // 水平方向固定对齐单位根节点,只使用模型顶部计算血条高度。
Vector3 top = transform.InverseTransformPoint(new Vector3(transform.position.x, bounds.max.y, transform.position.z)); Vector3 top = transform.InverseTransformPoint(new Vector3(transform.position.x, bounds.max.y, transform.position.z));
localBarPosition = new Vector3(0f, top.y + heightOffset, 0f); float localHeightOffset = transform.lossyScale.y != 0f
? heightOffset / transform.lossyScale.y
: heightOffset;
localBarPosition = new Vector3(0f, top.y + localHeightOffset, 0f);
} }
// 创建世界空间 Canvas、边框和绿色血量填充。 // 创建世界空间 Canvas、边框和绿色血量填充。
private void CreateBar() private void CreateBar()
@@ -343,6 +353,7 @@ public class WorldHealthBar : MonoBehaviour
barRect.sizeDelta = new Vector2(PixelWidth, TotalPixelHeight); barRect.sizeDelta = new Vector2(PixelWidth, TotalPixelHeight);
barRect.localScale = Vector3.one * (worldWidth / PixelWidth); barRect.localScale = Vector3.one * (worldWidth / PixelWidth);
barRect.localPosition = GetBarRootPosition(); barRect.localPosition = GetBarRootPosition();
ApplyScaleCompensation();
RectTransform healthRow = CreateRow(barObject.transform, "HealthBar", PixelWidth, PixelHeight, 0); RectTransform healthRow = CreateRow(barObject.transform, "HealthBar", PixelWidth, PixelHeight, 0);
Image background = CreateImage("Border", healthRow, RoundedSprite(), borderColor); Image background = CreateImage("Border", healthRow, RoundedSprite(), borderColor);
@@ -383,12 +394,25 @@ public class WorldHealthBar : MonoBehaviour
energyFillImage = energyInner; energyFillImage = energyInner;
} }
private void ApplyScaleCompensation()
{
Vector3 parentScale = transform.lossyScale;
float targetScale = worldWidth / PixelWidth;
barRect.localScale = new Vector3(
parentScale.x != 0f ? targetScale / parentScale.x : targetScale,
parentScale.y != 0f ? targetScale / parentScale.y : targetScale,
parentScale.z != 0f ? targetScale / parentScale.z : targetScale);
}
// 返回整体 Canvas 的位置,使血条中心保持原来的高度。 // 返回整体 Canvas 的位置,使血条中心保持原来的高度。
private Vector3 GetBarRootPosition() private Vector3 GetBarRootPosition()
{ {
float pixelToWorld = worldWidth / PixelWidth; float pixelToWorld = worldWidth / PixelWidth;
float energyOffset = (TotalPixelHeight - PixelHeight) * 0.5f * pixelToWorld; float worldEnergyOffset = (TotalPixelHeight - PixelHeight) * 0.5f * pixelToWorld;
return localBarPosition - Vector3.up * energyOffset; float localEnergyOffset = transform.lossyScale.y != 0f
? worldEnergyOffset / transform.lossyScale.y
: worldEnergyOffset;
return localBarPosition - Vector3.up * localEnergyOffset;
} }
// 创建一行固定像素高度的世界空间 UI。 // 创建一行固定像素高度的世界空间 UI。
+2 -2
View File
@@ -44,7 +44,7 @@
"com.unity.modules.vr": "1.0.0", "com.unity.modules.vr": "1.0.0",
"com.unity.modules.wind": "1.0.0", "com.unity.modules.wind": "1.0.0",
"com.unity.modules.xr": "1.0.0", "com.unity.modules.xr": "1.0.0",
"cn.tuanjie.codely.bridge": "1.0.80", "cn.tuanjie.ai.generators": "file:../.codely-cli/extensions/TJGenerators/Packages/cn.tuanjie.ai.generators",
"cn.tuanjie.ai.generators": "file:../.codely-cli/extensions/TJGenerators/Packages/cn.tuanjie.ai.generators" "cn.tuanjie.codely.bridge": "1.0.81"
} }
} }
+1 -1
View File
@@ -31,7 +31,7 @@
"url": "https://packages.tuanjie.cn" "url": "https://packages.tuanjie.cn"
}, },
"cn.tuanjie.codely.bridge": { "cn.tuanjie.codely.bridge": {
"version": "1.0.80", "version": "1.0.81",
"depth": 0, "depth": 0,
"source": "registry", "source": "registry",
"dependencies": { "dependencies": {
+258
View File
@@ -0,0 +1,258 @@
# 召唤之战-核心玩法
> 当前版本:核心玩法草案
>
> 目标:围绕“建筑生产 + 自动作战 + 主角辅助”的对攻玩法,先确定单局战斗的基本规则,再逐步扩展角色、装备、养成和对战模式。
## 一、核心定位
《召唤之战》是一款以**召唤和建筑生产**为核心的实时策略战斗游戏。
玩家通过金币建造金矿和兵营,兵营持续生产角色单位。己方单位自动寻找目标并向敌方推进,玩家主要通过经济投入、建筑选择、兵种组合和主角技能影响战局。
核心决策是:
- 先建造金矿,发展经济;
- 还是先建造兵营,尽快形成战斗压力;
- 选择哪种角色建筑;
- 建筑放在哪里,如何避免堵塞和被快速摧毁;
- 什么时候操作主角移动或释放技能。
## 二、单局战斗结构
### 2.1 地图
- 地图长度比当前第一版长地图明显缩短,避免玩家长时间赶路。
- 每个小关使用一个独立场景,同时复用通用建筑、角色、UI 和特效资源。
- 地图保留主题变化,例如城堡、荒野、沼泽、矿坑、雪山等。
- 地图中间设置少量障碍物,用来分割进攻路径。
- 进攻路线根据关卡设计分为 1 路、2 路或 3 路。
- 单位从己方区域向敌方区域推进,并在路线上寻找最近的有效目标。
### 2.2 寻路
当前单位主要沿直线移动,后续需要加入自动寻路能力。
目标规则:
- 单位自动寻找距离最近的敌方单位或建筑;
- 遇到障碍物时能够绕行;
- 多路线地图中,单位可以选择可到达的进攻路径;
- 单位不能因为建筑或己方单位摆放而永久卡死;
- 寻路系统应优先服务于短地图和少量障碍物,不追求复杂 RTS 级别的路径编辑。
具体采用 Unity NavMesh 还是轻量级多路线方案,待实现阶段确认。
## 三、主角定位
主角保留,并作为己方单位加入战场,而不是单纯的 UI 指挥官。
### 3.1 主角职责
- 主角可以普通攻击;
- 主角可以由玩家手动移动;
- 玩家没有主动操作时,主角自动巡逻并攻击附近敌人;
- 主角可以手动释放技能;
- 主角技能冷却较长,主要用于辅助、补刀和改变局部战况;
- 主角不是主要战斗力,不能替代建筑生产的军队;
- 主角的价值是提升玩家参与感,并在关键时刻提供战术干预。
### 3.2 主角装备
主角可以装备不同武器或装备。装备可改变主角的普通攻击方式和技能效果。
初步装备方向:
| 装备 | 普攻方向 | 技能方向 | 定位 |
|---|---|---|---|
| 法杖/魔杖 | 远程魔法攻击 | 范围伤害、控制或增益 | 远程辅助 |
| 弓箭 | 远程物理攻击 | 多重射击、点杀或穿透 | 远程输出辅助 |
| 大剑 | 近战攻击 | 范围斩击、击退或短时强化 | 近战辅助 |
装备技能冷却较长,主要是锦上添花,不应让主角单独决定整场胜负。
装备获取、稀有度和具体数值暂不实现,后续可与抽卡系统关联。
## 四、建筑系统
### 4.1 建筑类型
首版至少包含以下建筑:
| 建筑 | 主要作用 |
|---|---|
| 主建筑 | 己方核心建筑,负责承受攻击并作为重要胜负目标 |
| 金矿 | 持续产生金币,支持后续建造 |
| 兵营 | 按固定间隔持续生产指定角色单位 |
除了主建筑外,金矿和兵营都需要消耗金币建造。
后续可以增加防御塔、特殊功能建筑或不同生产类型的建筑,但不作为首版核心要求。
### 4.2 建筑摆放
采用“隐藏粗网格 + 视觉上不显示网格线 + 建筑自动吸附”的方案。玩家看到的是自然地面,不需要操作可见的密集网格;只有建筑放置位置受到隐藏网格约束。
首版不制作复杂的六边形网格编辑器,也不要求玩家精确调整每个建筑的连续坐标。建筑放置系统负责将建筑吸附到最近的合法位置,同时保留一定的布局自由度。
#### 基本规则
- 建筑只能放置在允许的己方区域内;
- 建筑移动预览时自动吸附到最近的粗网格位置;
- 建筑之间不能重叠;
- 建筑之间需要保持最小安全间距;
- 建筑不能超出地图边界;
- 建筑不能堵住主建筑、主角或己方单位的主要出口;
- 建筑不能完全封死己方主要进攻路线;
- 非法位置不能确认建造。
#### 建筑占格建议
- 金矿:暂定占用 2×2 格;
- 兵营:暂定占用 2×2 格;
- 主建筑:暂定占用 3×3 或 4×4 格;
- 建筑之间至少保留一格缓冲距离,避免建筑虽然没有重叠,但互相贴近导致单位无法通过。
具体网格尺寸和建筑占格数量以实际地图比例和单位体型测试结果为准。
#### 放置预览
玩家选择金矿或兵营后,进入建筑放置状态:
1. 显示半透明的建筑预览;
2. 预览自动吸附到最近的粗网格位置;
3. 建筑底部显示放置边框;
4. 合法位置显示绿色边框,并允许确认建造;
5. 非法位置显示红色边框,并禁止确认建造;
6. 点击确认后扣除金币并生成正式建筑;
7. 点击取消或右键退出放置状态。
绿色/红色边框需要让玩家明确知道当前位置是否能够放置,而不显示完整网格线。
#### 合法性检查
建筑位置校验至少需要考虑:
1. 建筑自身占用范围;
2. 与其他建筑的安全间距;
3. 建筑与地图边界的距离;
4. 主角和生产单位的出生点;
5. 己方主要进攻通道是否仍然可通行;
6. 建筑被摧毁后是否仍会留下阻挡;
7. 建筑是否处于可建造地面。
实现上可以组合使用隐藏网格占用判断、碰撞范围检测和进攻路线通行检查,而不只依赖单个 Collider。
#### 视觉与资源复用
- 兵营和金矿使用统一的正方形底座规格;
- 兵营通过顶部站立的对应角色模型表现生产兵种;
- 金矿通过明显的金色矿脉、矿井入口和采矿收集装置表现功能;
- 主建筑使用更大的独立底座和召唤核心突出重要性;
- 运行时角色展示、生产进度条和放置边框不烘焙进建筑贴图。
如果隐藏粗网格仍无法稳定解决卡位问题,再考虑使用预设建筑槽位。主角和战斗单位仍使用真实世界坐标移动,只有建筑放置使用隐藏网格。
## 五、兵营生产
### 5.1 基本规则
- 角色对应的兵营建造完成后,开始生产该角色;
- 兵营每隔若干秒自动产出一个单位;
- 生产出的单位从兵营附近的出生位置出现;
- 单位出现后自动寻找目标并参与战斗;
- 兵营被摧毁后停止生产;
- 生产间隔、建筑血量和角色费用由角色与建筑配置决定。
### 5.2 建筑表现
首版尽量复用同一个兵营模型:
- 所有角色兵营使用统一的兵营建筑模型;
- 兵营顶部或正面显示对应角色的小头像;
- 头像外显示绿色生产进度条;
- 进度条从空逐渐增长,完成后生产一个单位并重新开始;
- 金矿可以暂时复用统一的建筑表现;
- 建筑外观差异主要通过头像、颜色和 UI 标识体现。
这样可以先验证玩法,不把开发成本集中在大量建筑模型上。后续玩家数量和内容规模确定后,再增加建筑皮肤或主题外观。
## 六、经济系统
- 金币是建造金矿和兵营的主要资源;
- 金矿持续产生金币;
- 兵营和其他功能建筑消耗金币;
- 玩家需要在经济发展和即时战力之间做选择;
- 高稀有度或高强度角色可以设置更高的建筑/生产成本,但不能只依靠数值碾压普通角色;
- 金币初始值、金矿产出速度、建筑费用和单位生产间隔需要通过单局测试平衡。
## 七、自动战斗规则
- 己方和敌方单位均由 AI 控制;
- 单位优先寻找距离最近的有效目标;
- 有效目标包括敌方单位和敌方建筑;
- 单位进入攻击范围后停止移动并进行普通攻击;
- 角色技能按各自规则自动释放;
- 主角与普通单位一样属于战场单位,但拥有玩家手动移动和手动技能操作;
- 主角没有主动指令时,按照自动巡逻和自动攻击规则行动。
## 八、胜负规则
### 8.1 当前确定规则
- 摧毁对方主建筑作为主要胜利目标;
- 己方主建筑被摧毁时,立即失败;
- 对方主建筑被摧毁时,立即胜利;
- 摧毁金矿和兵营可以削弱对方经济与持续生产能力,但暂不直接作为立即胜负条件。
### 8.2 限时结束
如果时间结束时双方主建筑都没有被摧毁,具体判定方式暂未最终确定。
待评估方案:
1. 比较双方主建筑剩余生命值百分比;
2. 比较双方被摧毁建筑价值或建筑得分;
3. 比较双方场上剩余战力;
4. 平局后进入短时间加时,先摧毁建筑的一方获胜。
当前倾向优先测试“建筑摧毁得分”或“主建筑剩余生命值”方案,最终以实际对战体验为准。
## 九、角色与养成方向
角色是玩家收集和配置的战斗单位。每个角色可以对应一种兵营生产方案。
后续养成方向:
- 角色通过抽卡或其他收集方式获得;
- 每次对战后获得抽奖券,作为免费获取渠道;
- 角色卡片可以升级;
- 普通等级提升基础属性;
- 在关键等级节点改变或强化技能;
- 角色具有稀有度;
- 稀有角色可以拥有更强或更特殊的能力,同时承担更高的金币消耗或生产成本;
- 需要避免稀有度直接造成无法通过策略弥补的数值碾压。
抽卡概率、碎片来源、金币消耗、升级节点和付费方案属于长期系统,暂不影响首版核心战斗验证。
## 十、首版验证优先级
1. 缩短地图并制作 1~2 条进攻路线;
2. 实现少量障碍物和基本自动寻路;
3. 保留主角的普通攻击、手动移动和一个手动技能;
4. 实现金矿产出金币;
5. 实现统一兵营模型和角色头像;
6. 实现兵营生产单位和绿色生产进度条;
7. 实现建筑不能重叠、不能过近和不能堵住出生点的摆放校验;
8. 实现攻击建筑和摧毁主建筑的胜负逻辑;
9. 通过单机对战或简单 AI 验证“发展经济还是快速建兵”的选择是否有趣;
10. 核心战斗成立后,再加入更多角色、装备、养成和对战模式。
## 十一、当前明确不做的内容
- 首版不制作复杂的完整 RTS 网格编辑系统;
- 首版不制作大量不同兵营模型;
- 首版不让主角成为主要输出核心;
- 首版不先实现完整抽卡、充值和联网对战;
- 首版不先扩展大量角色和装备;
- 首版不在限时胜负规则未验证前绑定复杂的排名和奖励系统。