地图初步

This commit is contained in:
SoulliesOfficial
2026-04-30 07:06:38 -04:00
parent 8ad26129b2
commit 47125f95f4
98 changed files with 2237 additions and 20524 deletions

View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="UserContentModel">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>

View File

@@ -1,6 +1,114 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!74 &7400000
--- !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: 1aad7ba1072fa344088a099ea9469a38, type: 3}
m_Name: HeavyEnforcer_GetHitHeavyFront
m_EditorClassIdentifier: Assembly-CSharp::SLSUtilities.FunctionalAnimation.FuncAnimData
serializationData:
SerializedFormat: 2
SerializedBytes:
ReferencedUnityObjects: []
SerializedBytesString:
Prefab: {fileID: 0}
PrefabModificationsReferencedUnityObjects: []
PrefabModifications: []
SerializationNodes:
- Name: interactions
Entry: 7
Data: 0|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.Collections.Generic.List`1[[System.String,
mscorlib]], mscorlib]], mscorlib
- Name: comparer
Entry: 7
Data: 1|System.Collections.Generic.GenericEqualityComparer`1[[System.String,
mscorlib]], mscorlib
- Name:
Entry: 8
Data:
- Name:
Entry: 12
Data: 0
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:
- Name: variableCollection
Entry: 7
Data: 2|SLSUtilities.FunctionalAnimation.VariableCollection, SLSUtilities
- Name: variables
Entry: 7
Data: 3|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.String,
mscorlib]], mscorlib
- Name: comparer
Entry: 7
Data: 4|System.Collections.Generic.GenericEqualityComparer`1[[System.String,
mscorlib]], mscorlib
- Name:
Entry: 8
Data:
- Name:
Entry: 12
Data: 0
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
parentCollection: {fileID: 11400000, guid: 3eca36b3803e5cb4dbaf7663b08e27f7, type: 2}
timeMode: 1
animationClip: {fileID: 6033113146954903928}
animInfo:
animationName: GetHitHeavyFront
stateName: GetHitHeavyFront
useRootMotion: 0
tags: []
disruptionType: 1000
overridePlaySpeed: 1
overrideStartFrame: 0
isAffectedBySpeedMultiplier: 1
description:
intervals:
- intervalType: 10
intervalName:
timeRange: {x: 0, y: 0}
- intervalType: 11
intervalName:
timeRange: {x: 0.33333334, y: 1}
- intervalType: 20
intervalName:
timeRange: {x: 0, y: 0}
- intervalType: 30
intervalName:
timeRange: {x: 0.73333335, y: 1}
- intervalType: 31
intervalName:
timeRange: {x: 0.9, y: 1}
- intervalType: 40
intervalName:
timeRange: {x: 0, y: 0}
eventCollection:
animEvents: []
startEvents: []
disruptionEvents: []
updateEvents: []
updateUntilEvents: []
references:
version: 2
RefIds: []
--- !u!74 &6033113146954903928
AnimationClip:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: c5df4eb83565f304aaa8074869fa2239
guid: 18b1b9346fba76d42a853b13f3638380
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000

View File

@@ -1,6 +1,6 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!74 &7400000
--- !u!74 &-1375646522349566030
AnimationClip:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
@@ -14409,3 +14409,111 @@ AnimationClip:
m_HasGenericRootTransform: 0
m_HasMotionFloatCurves: 0
m_Events: []
--- !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: 1aad7ba1072fa344088a099ea9469a38, type: 3}
m_Name: HeavyEnforcer_GetHitMediumFront
m_EditorClassIdentifier: Assembly-CSharp::SLSUtilities.FunctionalAnimation.FuncAnimData
serializationData:
SerializedFormat: 2
SerializedBytes:
ReferencedUnityObjects: []
SerializedBytesString:
Prefab: {fileID: 0}
PrefabModificationsReferencedUnityObjects: []
PrefabModifications: []
SerializationNodes:
- Name: interactions
Entry: 7
Data: 0|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.Collections.Generic.List`1[[System.String,
mscorlib]], mscorlib]], mscorlib
- Name: comparer
Entry: 7
Data: 1|System.Collections.Generic.GenericEqualityComparer`1[[System.String,
mscorlib]], mscorlib
- Name:
Entry: 8
Data:
- Name:
Entry: 12
Data: 0
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:
- Name: variableCollection
Entry: 7
Data: 2|SLSUtilities.FunctionalAnimation.VariableCollection, SLSUtilities
- Name: variables
Entry: 7
Data: 3|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.String,
mscorlib]], mscorlib
- Name: comparer
Entry: 7
Data: 4|System.Collections.Generic.GenericEqualityComparer`1[[System.String,
mscorlib]], mscorlib
- Name:
Entry: 8
Data:
- Name:
Entry: 12
Data: 0
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
parentCollection: {fileID: 11400000, guid: 3eca36b3803e5cb4dbaf7663b08e27f7, type: 2}
timeMode: 1
animationClip: {fileID: -1375646522349566030}
animInfo:
animationName: GetHitMediumFront
stateName: GetHitMediumFront
useRootMotion: 0
tags: []
disruptionType: 1000
overridePlaySpeed: 1
overrideStartFrame: 0
isAffectedBySpeedMultiplier: 1
description:
intervals:
- intervalType: 10
intervalName:
timeRange: {x: 0, y: 0}
- intervalType: 11
intervalName:
timeRange: {x: 0.13333334, y: 0.56666666}
- intervalType: 20
intervalName:
timeRange: {x: 0, y: 0}
- intervalType: 30
intervalName:
timeRange: {x: 0.5, y: 0.56666666}
- intervalType: 31
intervalName:
timeRange: {x: 0.53333336, y: 0.56666666}
- intervalType: 40
intervalName:
timeRange: {x: 0, y: 0}
eventCollection:
animEvents: []
startEvents: []
disruptionEvents: []
updateEvents: []
updateUntilEvents: []
references:
version: 2
RefIds: []

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: f9d08dd5a5ec51f4cb5b60bacf0484d6
guid: b7d79a1e6f8daf44b825845d8c1218e5
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000

View File

@@ -1054,7 +1054,7 @@ AnimatorState:
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: 7400000, guid: d5679acf57148904796b9b930181ab5d, type: 2}
m_Motion: {fileID: -1375646522349566030, guid: b7d79a1e6f8daf44b825845d8c1218e5, type: 2}
m_Tag:
m_SpeedParameter: MoveSpeedX
m_MirrorParameter:
@@ -1267,7 +1267,7 @@ AnimatorState:
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: 7400000, guid: 18cfbdc87454ce345a403f5701b05a87, type: 2}
m_Motion: {fileID: 6033113146954903928, guid: 18b1b9346fba76d42a853b13f3638380, type: 2}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:

View File

@@ -1,110 +0,0 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 1aad7ba1072fa344088a099ea9469a38, type: 3}
m_Name: HeavyEnforcer_Rise
m_EditorClassIdentifier: Assembly-CSharp::SLSUtilities.FunctionalAnimation.FuncAnimData
serializationData:
SerializedFormat: 2
SerializedBytes:
ReferencedUnityObjects: []
SerializedBytesString:
Prefab: {fileID: 0}
PrefabModificationsReferencedUnityObjects: []
PrefabModifications: []
SerializationNodes:
- Name: interactions
Entry: 7
Data: 0|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.Collections.Generic.List`1[[System.String,
mscorlib]], mscorlib]], mscorlib
- Name: comparer
Entry: 7
Data: 1|System.Collections.Generic.GenericEqualityComparer`1[[System.String,
mscorlib]], mscorlib
- Name:
Entry: 8
Data:
- Name:
Entry: 12
Data: 0
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:
- Name: variableCollection
Entry: 6
Data:
parentCollection: {fileID: 11400000, guid: 3eca36b3803e5cb4dbaf7663b08e27f7, type: 2}
timeMode: 1
animationClip: {fileID: 7400000, guid: d39d3ab6258c405418470f9cf78ed7a6, type: 2}
animInfo:
animationName: Rise
stateName: Rise
useRootMotion: 0
tags: []
disruptionType: 10000
overridePlaySpeed: 1
overrideStartFrame: 0
isAffectedBySpeedMultiplier: 0
description:
intervals:
- intervalType: 0
intervalName:
timeRange: {x: 0, y: 0}
- intervalType: 10
intervalName:
timeRange: {x: 0, y: 0}
- intervalType: 20
intervalName:
timeRange: {x: 0, y: 0}
- intervalType: 21
intervalName:
timeRange: {x: 0, y: 0}
- intervalType: 22
intervalName:
timeRange: {x: 0, y: 0}
- intervalType: 30
intervalName:
timeRange: {x: 0, y: 0}
- intervalType: 31
intervalName:
timeRange: {x: 0, y: 0}
- intervalType: 40
intervalName:
timeRange: {x: 0, y: 0}
eventCollection:
animEvents:
- triggerTime: 1
isEnd: 1
payload:
rid: 563130414968078473
startEvents:
- rid: 563130414968078472
disruptionEvents: []
updateEvents: []
updateUntilEvents: []
references:
version: 2
RefIds:
- rid: 563130414968078472
type: {class: SetStatus, ns: Cielonos.MainGame.FunctionalAnimation, asm: Assembly-CSharp}
data:
eventName: StartSetStatus0
statusToSet: d0070000
isAdd: 1
- rid: 563130414968078473
type: {class: SetStatus, ns: Cielonos.MainGame.FunctionalAnimation, asm: Assembly-CSharp}
data:
eventName: AnimSetStatus0
statusToSet: d0070000
isAdd: 0

View File

@@ -105,3 +105,5 @@ MonoBehaviour:
- {fileID: 11400000, guid: 625840d1f4d3e504c9c9d7a143a9412c, type: 2}
- {fileID: 11400000, guid: bed905359cbe44a4293a5ec068d6f491, type: 2}
- {fileID: 11400000, guid: 378607732fa361b4897853229bbfcf76, type: 2}
- {fileID: 11400000, guid: b7d79a1e6f8daf44b825845d8c1218e5, type: 2}
- {fileID: 11400000, guid: 18b1b9346fba76d42a853b13f3638380, type: 2}

View File

@@ -0,0 +1,178 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 87e69f21423d3c746ae55ea47c545ba6, type: 3}
m_Name: Player_Feedback_GetHitHeavy
m_EditorClassIdentifier: SLSUtilities::SLSUtilities.Feedback.FeedbackData
serializationData:
SerializedFormat: 2
SerializedBytes:
ReferencedUnityObjects: []
SerializedBytesString:
Prefab: {fileID: 0}
PrefabModificationsReferencedUnityObjects: []
PrefabModifications: []
SerializationNodes: []
parentCollection: {fileID: 11400000, guid: 97907d6e971a2dd41b795615cb499f34, type: 2}
feedbackName: GetHitHeavy
defaultTimeSettings:
timeScaleType: 1
applyDynamicTimeScale: 1
tracks:
- trackName: Camera
mute: 0
solo: 0
clips:
- clipName:
startTime: 0
duration: 0.3
overrideTimeSettings: 0
timeSettings:
timeScaleType: 1
applyDynamicTimeScale: 1
action:
rid: 1359146347520065664
references:
version: 2
RefIds:
- rid: 1359146347520065664
type: {class: CameraPositionShakeAction, ns: Cielonos.MainGame.Effects.Feedback, asm: Assembly-CSharp}
data:
intensityCurve:
curve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 20
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 0.05
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 0.13
value: -0.72
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 0.21
value: 0.52
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 0.29
value: -0.36
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 0.38
value: 0.24
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 0.48
value: -0.15
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 0.6
value: 0.08
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 0.75
value: -0.03
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 1
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
remapMin: 0
remapMax: 1
relativeToInitial: 1
amplitude: {x: 0, y: 0.4, z: 0}
directionSettings:
affectedByCameraDirection: 0
affectedByCharacterDirection: 0
useAttenuation: 0
attenuationRange: 50
attenuationCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 1
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4

View File

@@ -1,8 +1,8 @@
fileFormatVersion: 2
guid: d39d3ab6258c405418470f9cf78ed7a6
guid: 41c1d8c7cca2d7243ae7ab60b3998a51
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 7400000
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -27,7 +27,7 @@ MonoBehaviour:
timeScaleType: 1
applyDynamicTimeScale: 1
tracks:
- trackName: New Track
- trackName: Camera
mute: 0
solo: 0
clips:
@@ -54,13 +54,13 @@ MonoBehaviour:
time: 0
value: 0
inSlope: 0
outSlope: 20
outSlope: 12
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 0.05
time: 0.08
value: 1
inSlope: 0
outSlope: 0
@@ -69,8 +69,8 @@ MonoBehaviour:
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 0.13
value: -0.72
time: 0.24
value: -0.55
inSlope: 0
outSlope: 0
tangentMode: 0
@@ -78,8 +78,8 @@ MonoBehaviour:
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 0.21
value: 0.52
time: 0.42
value: 0.3
inSlope: 0
outSlope: 0
tangentMode: 0
@@ -87,44 +87,8 @@ MonoBehaviour:
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 0.29
value: -0.36
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 0.38
value: 0.24
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 0.48
value: -0.15
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 0.6
value: 0.08
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 0.75
value: -0.03
time: 0.62
value: -0.12
inSlope: 0
outSlope: 0
tangentMode: 0
@@ -146,7 +110,7 @@ MonoBehaviour:
remapMin: 0
remapMax: 1
relativeToInitial: 1
amplitude: {x: 0.5, y: 0.5, z: 0}
amplitude: {x: 0, y: 0.2, z: 0}
directionSettings:
affectedByCameraDirection: 0
affectedByCharacterDirection: 0

View File

@@ -0,0 +1,133 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 87e69f21423d3c746ae55ea47c545ba6, type: 3}
m_Name: Player_Feedback_TakeDamage
m_EditorClassIdentifier: SLSUtilities::SLSUtilities.Feedback.FeedbackData
serializationData:
SerializedFormat: 2
SerializedBytes:
ReferencedUnityObjects: []
SerializedBytesString:
Prefab: {fileID: 0}
PrefabModificationsReferencedUnityObjects: []
PrefabModifications: []
SerializationNodes: []
parentCollection: {fileID: 11400000, guid: 97907d6e971a2dd41b795615cb499f34, type: 2}
feedbackName: TakeDamage
defaultTimeSettings:
timeScaleType: 1
applyDynamicTimeScale: 1
tracks:
- trackName: Postprocessing
mute: 0
solo: 0
clips:
- clipName:
startTime: 0
duration: 0.2
overrideTimeSettings: 0
timeSettings:
timeScaleType: 1
applyDynamicTimeScale: 1
action:
rid: 1359146577946214797
references:
version: 2
RefIds:
- rid: 1359146577946214797
type: {class: RGBSplitGlitchAction, ns: Cielonos.MainGame.Effects.Feedback, asm: Assembly-CSharp}
data:
intensityCurve:
curve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 136
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
- serializedVersion: 3
time: 1
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
remapMin: 0
remapMax: 1
relativeToInitial: 1
modifySpeed: 0
speedCurve:
curve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 8
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 0.12
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 0.32
value: 0.1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 0.52
value: 0.7
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 1
value: 0
inSlope: -0.6
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
remapMin: 0
remapMax: 50
relativeToInitial: 1
speed: 10

View File

@@ -1,8 +1,8 @@
fileFormatVersion: 2
guid: d5679acf57148904796b9b930181ab5d
guid: 0dc6f91602157d341b311a680009e309
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 7400000
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -28,3 +28,6 @@ MonoBehaviour:
- {fileID: 11400000, guid: 8e5f98cbcfebbe94ab42a318488f19c9, type: 2}
- {fileID: 11400000, guid: ed0fa067d61c36c46b4daf3e726ff241, type: 2}
- {fileID: 11400000, guid: 9548a16e378165340823512202cfd978, type: 2}
- {fileID: 11400000, guid: 41c1d8c7cca2d7243ae7ab60b3998a51, type: 2}
- {fileID: 11400000, guid: a0cb75b536ebea6489c731b3d2775109, type: 2}
- {fileID: 11400000, guid: 0dc6f91602157d341b311a680009e309, type: 2}

View File

@@ -1,279 +1,5 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &1096462161717453291
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 4144713736332461459}
- component: {fileID: 5264817877047676679}
m_Layer: 6
m_Name: Swing
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &4144713736332461459
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1096462161717453291}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 4528112382595921377}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &5264817877047676679
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1096462161717453291}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 6da43522623d4704e979466dc7650b65, type: 3}
m_Name:
m_EditorClassIdentifier: MoreMountains.Tools::MoreMountains.Feedbacks.MMF_Player
Feedbacks: []
InitializationMode: 2
AutoInitialization: 1
SafeMode: 3
Direction: 0
AutoChangeDirectionOnEnd: 0
AutoPlayOnStart: 0
AutoPlayOnEnable: 0
ForceTimescaleMode: 0
ForcedTimescaleMode: 1
DurationMultiplier: 1
TimescaleMultiplier: 1
ApplyExternalTimeScale: 1
ExternalTimeScale: 1
RandomizeDuration: 0
RandomDurationMultiplier: {x: 0.5, y: 1.5}
DisplayFullDurationDetails: 0
PlayerTimescaleMode: 0
OnlyPlayIfWithinRange: 0
RangeCenter: {fileID: 0}
RangeDistance: 5
UseRangeFalloff: 0
RangeFalloff:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 1
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
RemapRangeFalloff: {x: 0, y: 1}
IgnoreRangeEvents: 0
CooldownDuration: 0
InitialDelay: 0
CanPlay: 1
CanPlayWhileAlreadyPlaying: 1
ChanceToPlay: 100
FeedbacksIntensity: 1
Events:
TriggerMMFeedbacksEvents: 0
TriggerUnityEvents: 1
OnPlay:
m_PersistentCalls:
m_Calls: []
OnPause:
m_PersistentCalls:
m_Calls: []
OnStop:
m_PersistentCalls:
m_Calls: []
OnResume:
m_PersistentCalls:
m_Calls: []
OnChangeDirection:
m_PersistentCalls:
m_Calls: []
OnComplete:
m_PersistentCalls:
m_Calls: []
OnRestoreInitialValues:
m_PersistentCalls:
m_Calls: []
OnSkipToTheEnd:
m_PersistentCalls:
m_Calls: []
OnInitializationComplete:
m_PersistentCalls:
m_Calls: []
OnEnable:
m_PersistentCalls:
m_Calls: []
OnDisable:
m_PersistentCalls:
m_Calls: []
DebugActive: 0
InScriptDrivenPause: 0
FeedbacksList:
- rid: 563130844529033324
KeepPlayModeChanges: 0
PerformanceMode: 0
RestoreInitialValuesOnDisable: 0
StopFeedbacksOnDisable: 0
PlayCount: 0
references:
version: 2
RefIds:
- rid: 563130844529033324
type: {class: MMF_CinemachineRotation, ns: MoreMountains.FeedbacksForThirdParty, asm: MoreMountains.Tools}
data:
Active: 1
UniqueID: -1235249708
Label: Cinemachine Rotation Shake
OriginalLabel: Cinemachine Rotation Shake
ChannelMode: 0
Channel: 0
MMChannelDefinition: {fileID: 0}
Chance: 100
Timing:
TimescaleMode: 0
applyOwnerExternalTimescale: 0
ExcludeFromHoldingPauses: 0
ContributeToTotalDuration: 1
InitialDelay: 0
CooldownDuration: 0
InterruptsOnStop: 1
NumberOfRepeats: 0
RepeatForever: 0
DelayBetweenRepeats: 1
PlayCount: 0
LimitPlayCount: 0
MaxPlayCount: 3
SetPlayCountToZeroOnReset: 0
MMFeedbacksDirectionCondition: 0
PlayDirection: 0
ConstantIntensity: 0
UseIntensityInterval: 0
IntensityIntervalMin: 0
IntensityIntervalMax: 0
Sequence: {fileID: 0}
TrackID: 0
Quantized: 0
TargetBPM: 120
AutomatedTargetAcquisition:
Mode: 0
ChildIndex: 0
RandomizeOutput: 0
RandomMultiplier: {x: 0.8, y: 1}
RandomizeDuration: 0
RandomDurationMultiplier: {x: 0.5, y: 2}
UseRange: 0
RangeDistance: 5
UseRangeFalloff: 0
RangeFalloff:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 1
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
RemapRangeFalloff: {x: 0, y: 1}
AutomaticShakerSetupButton:
ButtonText:
Owner: {fileID: 5264817877047676679}
DebugActive: 0
Duration: 0.2
RotationAmplitude: {x: 0, y: 0, z: 0}
ShakeCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: -3.1114726
outSlope: -3.1114726
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.0352
- serializedVersion: 3
time: 1
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
UseAttenuation: 0
AttenuationRange: 50
AttenuationCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 1
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
DrawGizmos: 1
--- !u!1 &1531999231273389742
GameObject:
m_ObjectHideFlags: 0
@@ -305,9 +31,7 @@ Transform:
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 4144713736332461459}
- {fileID: 1992739708638524400}
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &1181514316549350430
@@ -331,6 +55,9 @@ MonoBehaviour:
PrefabModificationsReferencedUnityObjects: []
PrefabModifications: []
SerializationNodes:
- Name: passiveAttributeSm
Entry: 6
Data:
- Name: comboSm
Entry: 6
Data:
@@ -340,9 +67,12 @@ MonoBehaviour:
- Name: ammoSm
Entry: 6
Data:
- Name: overloadSm
Entry: 6
Data:
- Name: viewObjects
Entry: 7
Data: 0|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[Cielonos.MainGame.Inventory.ItemViewObject,
Data: 0|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[Cielonos.MainGame.Characters.Inventory.ItemViewObject,
Assembly-CSharp]], mscorlib
- Name: comparer
Entry: 7
@@ -360,28 +90,32 @@ MonoBehaviour:
- Name:
Entry: 8
Data:
fullBodyFuncAnims:
- {fileID: 11400000, guid: 5ae4e6fb437c04a49b116a062daf9892, type: 2}
- {fileID: 11400000, guid: 03ddb2652d7010b47bb65f6eaa27091c, type: 2}
- {fileID: 11400000, guid: cc7be8e826d20cc41a72c20f55350257, type: 2}
- {fileID: 11400000, guid: 5dae8552f60f2c04b8ec6bd5c070772e, type: 2}
- {fileID: 11400000, guid: a31727863ab7d8b46964840f10d6688e, type: 2}
- {fileID: 11400000, guid: 2ade289f2956acc4aa42ef79025ef2b4, type: 2}
- Name: activeAttributeSm
Entry: 6
Data:
fullBodyFuncAnims: {fileID: 0}
upperBodyFuncAnims: {fileID: 0}
contentData: {fileID: 11400000, guid: 377ae7a88c5cd4549b8ba90d9dff4b15, type: 2}
viewObjectData: {fileID: 11400000, guid: 0418af7cddfaad149a449c950a9d6e4c, type: 2}
vfxData: {fileID: 11400000, guid: 5d145d0d0b68e6b499526e1a13f066a8, type: 2}
passiveAttributeData: {fileID: 0}
upgradeData: {fileID: 0}
comboData: {fileID: 11400000, guid: ea9965ca658cdcc45b128a62a54945bd, type: 2}
attackData: {fileID: 11400000, guid: c11b8c31bce99984da5171686377ac8d, type: 2}
functionData: {fileID: 11400000, guid: f94aa6d20a42c4f4bb97cbd0034f144c, type: 2}
ammoData: {fileID: 11400000, guid: 8b49a05c6fe71934ba549cc036b8720f, type: 2}
blockData: {fileID: 0}
overloadData: {fileID: 0}
audioContainer: {fileID: 5194564820638940080}
feedbackSc: {fileID: 873105875386414627}
baseAnimationGroup: {fileID: 11400000, guid: f0d2f7c9e0f2e1f42961b393c736f3fe, type: 2}
activeAttributeData: {fileID: 0}
extraUIContainerPrefab: {fileID: 0}
disablePrimaryPreinput: 0
disableSecondaryPreinput: 0
disableSpecialAPreinput: 0
disableSpecialBPreinput: 0
disableSpecialCPreinput: 0
currentTarget: {fileID: 0}
--- !u!114 &5194564820638940080
MonoBehaviour:
@@ -656,303 +390,11 @@ MonoBehaviour:
serializationData:
SerializedFormat: 2
SerializedBytes:
ReferencedUnityObjects:
- {fileID: 5264817877047676679}
- {fileID: 1970790365688036326}
ReferencedUnityObjects: []
SerializedBytesString:
Prefab: {fileID: 0}
PrefabModificationsReferencedUnityObjects: []
PrefabModifications: []
SerializationNodes:
- Name: feedbacks
Entry: 7
Data: 0|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[SLSFramework.FeelAssistance.FeedbackUnit,
Assembly-CSharp]], mscorlib
- Name: comparer
Entry: 7
Data: 1|System.Collections.Generic.GenericEqualityComparer`1[[System.String,
mscorlib]], mscorlib
- Name:
Entry: 8
Data:
- Name:
Entry: 12
Data: 2
- Name:
Entry: 7
Data:
- Name: $k
Entry: 1
Data: Swing
- Name: $v
Entry: 7
Data: 2|SLSFramework.FeelAssistance.FeedbackUnit, Assembly-CSharp
- Name: feedback
Entry: 10
Data: 0
- Name: action
Entry: 6
Data:
- Name: canPlay
Entry: 5
Data: false
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 7
Data:
- Name: $k
Entry: 1
Data: Hit
- Name: $v
Entry: 7
Data: 3|SLSFramework.FeelAssistance.FeedbackUnit, Assembly-CSharp
- Name: feedback
Entry: 10
Data: 1
- Name: action
Entry: 6
Data:
- Name: canPlay
Entry: 5
Data: false
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:
SerializationNodes: []
owner: {fileID: 1181514316549350430}
--- !u!1 &1607319644205644852
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1992739708638524400}
- component: {fileID: 1970790365688036326}
m_Layer: 6
m_Name: Hit
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1992739708638524400
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1607319644205644852}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 4528112382595921377}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &1970790365688036326
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1607319644205644852}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 6da43522623d4704e979466dc7650b65, type: 3}
m_Name:
m_EditorClassIdentifier: MoreMountains.Tools::MoreMountains.Feedbacks.MMF_Player
Feedbacks: []
InitializationMode: 2
AutoInitialization: 1
SafeMode: 3
Direction: 0
AutoChangeDirectionOnEnd: 0
AutoPlayOnStart: 0
AutoPlayOnEnable: 0
ForceTimescaleMode: 0
ForcedTimescaleMode: 1
DurationMultiplier: 1
TimescaleMultiplier: 1
ApplyExternalTimeScale: 1
ExternalTimeScale: 1
RandomizeDuration: 0
RandomDurationMultiplier: {x: 0.5, y: 1.5}
DisplayFullDurationDetails: 0
PlayerTimescaleMode: 0
OnlyPlayIfWithinRange: 0
RangeCenter: {fileID: 0}
RangeDistance: 5
UseRangeFalloff: 0
RangeFalloff:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 1
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
RemapRangeFalloff: {x: 0, y: 1}
IgnoreRangeEvents: 0
CooldownDuration: 0
InitialDelay: 0
CanPlay: 1
CanPlayWhileAlreadyPlaying: 1
ChanceToPlay: 100
FeedbacksIntensity: 1
Events:
TriggerMMFeedbacksEvents: 0
TriggerUnityEvents: 1
OnPlay:
m_PersistentCalls:
m_Calls: []
OnPause:
m_PersistentCalls:
m_Calls: []
OnStop:
m_PersistentCalls:
m_Calls: []
OnResume:
m_PersistentCalls:
m_Calls: []
OnChangeDirection:
m_PersistentCalls:
m_Calls: []
OnComplete:
m_PersistentCalls:
m_Calls: []
OnRestoreInitialValues:
m_PersistentCalls:
m_Calls: []
OnSkipToTheEnd:
m_PersistentCalls:
m_Calls: []
OnInitializationComplete:
m_PersistentCalls:
m_Calls: []
OnEnable:
m_PersistentCalls:
m_Calls: []
OnDisable:
m_PersistentCalls:
m_Calls: []
DebugActive: 0
InScriptDrivenPause: 0
FeedbacksList:
- rid: 5266334308210049411
KeepPlayModeChanges: 0
PerformanceMode: 0
RestoreInitialValuesOnDisable: 0
StopFeedbacksOnDisable: 0
PlayCount: 0
references:
version: 2
RefIds:
- rid: 5266334308210049411
type: {class: MMF_FreezeFrame, ns: MoreMountains.Feedbacks, asm: MoreMountains.Tools}
data:
Active: 1
UniqueID: 338322809
Label: Freeze Frame
OriginalLabel: Freeze Frame
ChannelMode: 0
Channel: 0
MMChannelDefinition: {fileID: 0}
Chance: 100
Timing:
TimescaleMode: 0
applyOwnerExternalTimescale: 1
ExcludeFromHoldingPauses: 0
ContributeToTotalDuration: 1
InitialDelay: 0
CooldownDuration: 0
InterruptsOnStop: 1
NumberOfRepeats: 0
RepeatForever: 0
DelayBetweenRepeats: 1
PlayCount: 0
LimitPlayCount: 0
MaxPlayCount: 3
SetPlayCountToZeroOnReset: 0
MMFeedbacksDirectionCondition: 0
PlayDirection: 0
ConstantIntensity: 0
UseIntensityInterval: 0
IntensityIntervalMin: 0
IntensityIntervalMax: 0
Sequence: {fileID: 0}
TrackID: 0
Quantized: 0
TargetBPM: 120
AutomatedTargetAcquisition:
Mode: 0
ChildIndex: 0
RandomizeOutput: 0
RandomMultiplier: {x: 0.8, y: 1}
RandomizeDuration: 0
RandomDurationMultiplier: {x: 0.5, y: 2}
UseRange: 0
RangeDistance: 5
UseRangeFalloff: 0
RangeFalloff:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
- serializedVersion: 3
time: 1
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
RemapRangeFalloff: {x: 0, y: 1}
AutomaticShakerSetupButton:
ButtonText: Automatic Shaker Setup
Owner: {fileID: 1970790365688036326}
DebugActive: 0
FreezeFrameDuration: 0.04
MinimumTimescaleThreshold: 0.1
feedbackDataCollection: {fileID: 0}

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 3b079ad02f2fecb4db40aa5dfe189f0d
guid: 8e834d924ef5d504b86c12279e78a9a2
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -0,0 +1,106 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 3fc5f071bddbe134ab39c8fdf1f21bc3, type: 3}
m_Name: DefaultMapGenerationConfig
m_EditorClassIdentifier: Assembly-CSharp::Cielonos.MainGame.Map.MapGenerationConfig
serializationData:
SerializedFormat: 2
SerializedBytes:
ReferencedUnityObjects: []
SerializedBytesString:
Prefab: {fileID: 0}
PrefabModificationsReferencedUnityObjects: []
PrefabModifications: []
SerializationNodes:
- Name: specialNodeCounts
Entry: 7
Data: 0|System.Collections.Generic.Dictionary`2[[Cielonos.MainGame.MapNodeType,
Assembly-CSharp],[System.Int32, mscorlib]], mscorlib
- Name: comparer
Entry: 7
Data: 1|System.Collections.Generic.EnumEqualityComparer`1[[Cielonos.MainGame.MapNodeType,
Assembly-CSharp]], mscorlib
- Name:
Entry: 12
Data: 0
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 12
Data: 4
- Name:
Entry: 7
Data:
- Name: $k
Entry: 3
Data: 2
- Name: $v
Entry: 3
Data: 3
- Name:
Entry: 8
Data:
- Name:
Entry: 7
Data:
- Name: $k
Entry: 3
Data: 4
- Name: $v
Entry: 3
Data: 2
- Name:
Entry: 8
Data:
- Name:
Entry: 7
Data:
- Name: $k
Entry: 3
Data: 5
- Name: $v
Entry: 3
Data: 1
- Name:
Entry: 8
Data:
- Name:
Entry: 7
Data:
- Name: $k
Entry: 3
Data: 6
- Name: $v
Entry: 3
Data: 2
- Name:
Entry: 8
Data:
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:
gridRadius: 5
targetRoomCount: 25
minBossDistance: 5
specialNodeMinDistanceFromStart: 2
specialNodeMinSameTypeDistance: 2
normalCombatZoneDataNames: []
eliteCombatZoneDataNames: []
bossCombatZoneDataName:
nodeSpacing: 120

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 41dce0caab3bfde428411011fa85fdb8
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,38 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 1909a1a45fa45594e94a89aa02e3dfe2, type: 3}
m_Name: MapPreviewer
m_EditorClassIdentifier: Assembly-CSharp::Cielonos.MainGame.Map.MapPreviewer
serializationData:
SerializedFormat: 2
SerializedBytes:
ReferencedUnityObjects: []
SerializedBytesString:
Prefab: {fileID: 0}
PrefabModificationsReferencedUnityObjects: []
PrefabModifications: []
SerializationNodes: []
config: {fileID: 11400000, guid: 41dce0caab3bfde428411011fa85fdb8, type: 2}
previewSize: 600
nodeRadius: 6
edgeThickness: 1
colorStart: {r: 0.4, g: 0.9, b: 0.4, a: 1}
colorNormalCombat: {r: 0.85, g: 0.35, b: 0.35, a: 1}
colorEliteCombat: {r: 0.9, g: 0.55, b: 0.15, a: 1}
colorBossCombat: {r: 0.7, g: 0.15, b: 0.85, a: 1}
colorMechanicalTable: {r: 0.3, g: 0.7, b: 1, a: 1}
colorLogisticsCenter: {r: 1, g: 0.85, b: 0.2, a: 1}
colorMedicalStation: {r: 0.3, g: 0.85, b: 0.6, a: 1}
previewData:
startPosition: {x: 0, y: 0}
bossPosition: {x: 1, y: -4}
totalNodes: 26

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d444710512b9524469eb782ddfc49d42
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -47,7 +47,7 @@ namespace Cielonos.MainGame.Characters
}
}
public void SmartTurnToTarget(CharacterBase target, float maxTurnAngle = 150f)
public void SmartTurnToTarget(CharacterBase target, float maxTurnAngle = 360f)
{
Vector3 directionToTarget = (target.centerPoint.position - owner.centerPoint.position).Flatten();
if (directionToTarget.sqrMagnitude < 0.001f) return;

View File

@@ -157,8 +157,8 @@ namespace Cielonos.MainGame.Characters.Inventory
{
if (autoRotate)
{
float angleLimit = player.viewSc.lockTargetModule.isLocking ? 240 : 150;
player.landMovementSc.SmartTurnToTarget(target, angleLimit);
//float angleLimit = player.viewSc.lockTargetModule.isLocking ? 240 : 150;
player.landMovementSc.SmartTurnToTarget(target);
}
if (keepAdsorption)

View File

@@ -309,7 +309,7 @@ namespace Cielonos.MainGame.Characters.Inventory.Collections
.SetAttackSubmodule<NormalArea>(attackUnit)
.SetTimeSubmodule<NormalArea>(1f, 0.02f)
.SetHitSubmodule<NormalArea>()
.SetForceSubmodule<NormalArea>(1.5f, true);
.SetForceSubmodule<NormalArea>(2f, true);
slash.attackSm.breakthroughAction = (enemy, hitPosition) =>
{
@@ -355,7 +355,7 @@ namespace Cielonos.MainGame.Characters.Inventory.Collections
.SetAttackSubmodule<NormalArea>(attackUnit)
.SetTimeSubmodule<NormalArea>(1f, 0.04f)
.SetHitSubmodule<NormalArea>()
.SetForceSubmodule<NormalArea>(3f, true);
.SetForceSubmodule<NormalArea>(4f, true);
slash.attackSm.breakthroughAction = (enemy, hitPosition) =>
{
@@ -386,7 +386,7 @@ namespace Cielonos.MainGame.Characters.Inventory.Collections
.SetAttackSubmodule<NormalArea>(attackUnit)
.SetTimeSubmodule<NormalArea>(1f, 0.04f)
.SetHitSubmodule<NormalArea>()
.SetForceSubmodule<NormalArea>(3f, true);
.SetForceSubmodule<NormalArea>(4f, true);
slash.attackSm.breakthroughAction = (enemy, hitPosition) =>
{
@@ -414,7 +414,7 @@ namespace Cielonos.MainGame.Characters.Inventory.Collections
.SetAttackSubmodule<NormalArea>(attackUnit)
.SetTimeSubmodule<NormalArea>(1f, 0.04f)
.SetHitSubmodule<NormalArea>()
.SetForceSubmodule<NormalArea>(10f, true);
.SetForceSubmodule<NormalArea>(8f, true);
slash.attackSm.breakthroughAction = (enemy, hitPosition) =>
{

View File

@@ -36,6 +36,14 @@ namespace Cielonos.MainGame.Effects.Feedback
[Tooltip("开启时,结果叠加在初始值上;关闭时,结果为绝对值")]
public bool relativeToInitial;
public FloatCurveChannel(AnimationCurve curve, float remapMin, float remapMax, bool relativeToInitial)
{
this.curve = curve;
this.remapMin = remapMin;
this.remapMax = remapMax;
this.relativeToInitial = relativeToInitial;
}
/// <summary>
/// 创建默认的曲线通道。
/// </summary>

View File

@@ -27,17 +27,13 @@ namespace Cielonos.MainGame.Effects.Feedback
[HideIf("modifySpeed")]
[LabelText("速度")]
[Range(0f, 100f)]
public float speed = 30f;
public float speed = 10f;
protected override void TriggerEvent(FeedbackContext context)
{
FloatCurveChannel finalSpeedCurve = modifySpeed
? speedCurve
: new FloatCurveChannel
{
curve = AnimationCurve.Constant(0f, 1f, speed),
relativeToInitial = false
};
FloatCurveChannel finalSpeedCurve = modifySpeed
? speedCurve
: new FloatCurveChannel(AnimationCurve.Constant(0, 1, 1), 0, speed, false);
RGBSplitGlitchShakeEvent.Trigger(
context,

View File

@@ -14,40 +14,86 @@ namespace Cielonos.MainGame.Effects.Feedback
{
public override string DisplayName => "Strobe Flash";
/// <summary>
/// 是否修改频率和颜色参数。
/// </summary>
[TitleGroup("闪烁设置")]
[LabelText("修改额外参数")]
public bool modifyExtra;
// ─── Frequency ───
[ShowIf("modifyExtra")]
[TitleGroup("频率设置")]
[LabelText("频率模式")]
public StrobeFrequencyMode frequencyMode = StrobeFrequencyMode.Constant;
[TitleGroup("频率设置")]
[ShowIf("@frequencyMode == StrobeFrequencyMode.Constant")]
[LabelText("固定频率")]
[Range(0f, 100f)]
public float constantFrequency = 15f;
[TitleGroup("频率设置")]
[ShowIf("@frequencyMode == StrobeFrequencyMode.Curve")]
[LabelText("频率曲线")]
public FloatCurveChannel frequencyCurve = FloatCurveChannel.CreateDefault(remapMax: 15f);
public FloatCurveChannel frequencyCurve = FloatCurveChannel.CreateDefault(remapMax: 30f);
[ShowIf("modifyExtra")]
[TitleGroup("频率设置")]
[ShowIf("@frequencyMode == StrobeFrequencyMode.Manual")]
[LabelText("手动曲线Y >= 1 时翻转)")]
public AnimationCurve manualCurve = AnimationCurve.Constant(0f, 1f, 0f);
// ─── Color High ───
[TitleGroup("颜色设置")]
[LabelText("修改高颜色")]
public bool modifyColorHigh;
[TitleGroup("颜色设置")]
[ShowIf("modifyColorHigh")]
[LabelText("使用渐变色")]
public bool useColorHighGradient;
[TitleGroup("颜色设置")]
[ShowIf("@modifyColorHigh && !useColorHighGradient")]
[LabelText("高颜色")]
public ColorCurveChannel colorHigh = ColorCurveChannel.CreateDefault();
public Color colorHighConstant = Color.white;
[ShowIf("modifyExtra")]
[TitleGroup("颜色设置")]
[ShowIf("@modifyColorHigh && useColorHighGradient")]
[LabelText("高颜色渐变")]
public ColorCurveChannel colorHighCurve = ColorCurveChannel.CreateDefault();
// ─── Color Low ───
[TitleGroup("颜色设置")]
[LabelText("修改低颜色")]
public bool modifyColorLow;
[TitleGroup("颜色设置")]
[ShowIf("modifyColorLow")]
[LabelText("使用渐变色")]
public bool useColorLowGradient;
[TitleGroup("颜色设置")]
[ShowIf("@modifyColorLow && !useColorLowGradient")]
[LabelText("低颜色")]
public ColorCurveChannel colorLow = ColorCurveChannel.CreateDefault();
public Color colorLowConstant = Color.black;
[TitleGroup("颜色设置")]
[ShowIf("@modifyColorLow && useColorLowGradient")]
[LabelText("低颜色渐变")]
public ColorCurveChannel colorLowCurve = ColorCurveChannel.CreateDefault();
protected override void TriggerEvent(FeedbackContext context)
{
StrobeFlashShakeEvent.Trigger(
context,
context.duration,
modifyExtra,
frequencyMode,
constantFrequency,
frequencyCurve,
colorHigh,
colorLow
manualCurve,
modifyColorHigh, useColorHighGradient, colorHighConstant, colorHighCurve,
modifyColorLow, useColorLowGradient, colorLowConstant, colorLowCurve
);
}
protected override void StopEvent(FeedbackContext context)
{
StrobeFlashShakeEvent.Trigger(context, 0f, stop: true);
StrobeFlashShakeEvent.Trigger(context, stop: true);
}
public override bool Validate(out string error)

View File

@@ -89,8 +89,10 @@ namespace Cielonos.MainGame.Effects.Feedback
float additiveIntensity = 0f;
float absoluteIntensity = 0f;
bool hasAbsolute = false;
bool hasAbsoluteIntensity = false;
float additiveSpeed = 0f;
float absoluteSpeed = 0f;
bool hasAbsoluteSpeed = false;
for (int i = _activeShakes.Count - 1; i >= 0; i--)
{
@@ -107,10 +109,19 @@ namespace Cielonos.MainGame.Effects.Feedback
else
{
absoluteIntensity = intensityValue;
hasAbsolute = true;
hasAbsoluteIntensity = true;
}
additiveSpeed += shake.speedCurve.Evaluate(normalizedTime);
float speedValue = shake.speedCurve.Evaluate(normalizedTime);
if (shake.speedCurve.relativeToInitial)
{
additiveSpeed += speedValue;
}
else
{
absoluteSpeed = speedValue;
hasAbsoluteSpeed = true;
}
if (shake.IsFinished)
{
@@ -118,9 +129,10 @@ namespace Cielonos.MainGame.Effects.Feedback
}
}
float finalIntensity = hasAbsolute ? absoluteIntensity : _initialIntensity + additiveIntensity;
float finalIntensity = hasAbsoluteIntensity ? absoluteIntensity : _initialIntensity + additiveIntensity;
float finalSpeed = hasAbsoluteSpeed ? absoluteSpeed : _initialSpeed + additiveSpeed;
_component.intensity.value = finalIntensity;
_component.speed.value = _initialSpeed + additiveSpeed;
_component.speed.value = finalSpeed;
if (_activeShakes.Count == 0)
{

View File

@@ -5,6 +5,19 @@ using UnityEngine;
namespace Cielonos.MainGame.Effects.Feedback
{
/// <summary>
/// 频率控制模式。
/// </summary>
public enum StrobeFrequencyMode
{
/// <summary>使用固定频率数值。</summary>
Constant,
/// <summary>使用 FloatCurveChannel 以动画曲线控制频率。</summary>
Curve,
/// <summary>使用 AnimationCurve 手动控制 ManualInvertY >= 1 时翻转)。</summary>
Manual
}
/// <summary>
/// 黑白闪震动事件。
/// </summary>
@@ -17,11 +30,18 @@ namespace Cielonos.MainGame.Effects.Feedback
public delegate void ShakeDelegate(
FeedbackContext feedbackContext,
float duration,
bool modifyExtra,
StrobeFrequencyMode frequencyMode,
float constantFrequency,
FloatCurveChannel frequencyCurve,
ColorCurveChannel colorHigh,
ColorCurveChannel colorLow,
AnimationCurve manualCurve,
bool modifyColorHigh,
bool useColorHighGradient,
Color colorHighConstant,
ColorCurveChannel colorHighCurve,
bool modifyColorLow,
bool useColorLowGradient,
Color colorLowConstant,
ColorCurveChannel colorLowCurve,
bool stop
);
@@ -30,14 +50,25 @@ namespace Cielonos.MainGame.Effects.Feedback
public static void Trigger(
FeedbackContext feedbackContext,
float duration,
bool modifyExtra = false,
StrobeFrequencyMode frequencyMode = StrobeFrequencyMode.Constant,
float constantFrequency = 15f,
FloatCurveChannel frequencyCurve = default,
ColorCurveChannel colorHigh = default,
ColorCurveChannel colorLow = default,
AnimationCurve manualCurve = null,
bool modifyColorHigh = false,
bool useColorHighGradient = false,
Color colorHighConstant = default,
ColorCurveChannel colorHighCurve = default,
bool modifyColorLow = false,
bool useColorLowGradient = false,
Color colorLowConstant = default,
ColorCurveChannel colorLowCurve = default,
bool stop = false)
{
OnEvent?.Invoke(feedbackContext, duration, modifyExtra, frequencyCurve, colorHigh, colorLow, stop);
OnEvent?.Invoke(feedbackContext,
frequencyMode, constantFrequency, frequencyCurve, manualCurve,
modifyColorHigh, useColorHighGradient, colorHighConstant, colorHighCurve,
modifyColorLow, useColorLowGradient, colorLowConstant, colorLowCurve,
stop);
}
}
@@ -46,28 +77,52 @@ namespace Cielonos.MainGame.Effects.Feedback
/// </summary>
public class StrobeFlashShakeInstance : ShakeInstanceBase
{
public readonly bool modifyExtra;
public readonly StrobeFrequencyMode frequencyMode;
public readonly float constantFrequency;
public readonly FloatCurveChannel frequencyCurve;
public readonly ColorCurveChannel colorHigh;
public readonly ColorCurveChannel colorLow;
public readonly AnimationCurve manualCurve;
public readonly bool modifyColorHigh;
public readonly bool useColorHighGradient;
public readonly Color colorHighConstant;
public readonly ColorCurveChannel colorHighCurve;
public readonly bool modifyColorLow;
public readonly bool useColorLowGradient;
public readonly Color colorLowConstant;
public readonly ColorCurveChannel colorLowCurve;
public StrobeFlashShakeInstance(
FeedbackContext feedbackContext,
bool modifyExtra,
StrobeFrequencyMode frequencyMode,
float constantFrequency,
FloatCurveChannel frequencyCurve,
ColorCurveChannel colorHigh,
ColorCurveChannel colorLow)
AnimationCurve manualCurve,
bool modifyColorHigh,
bool useColorHighGradient,
Color colorHighConstant,
ColorCurveChannel colorHighCurve,
bool modifyColorLow,
bool useColorLowGradient,
Color colorLowConstant,
ColorCurveChannel colorLowCurve)
: base(feedbackContext.timeSettings, feedbackContext.player.TimeProvider, feedbackContext.duration)
{
this.modifyExtra = modifyExtra;
this.frequencyMode = frequencyMode;
this.constantFrequency = constantFrequency;
this.frequencyCurve = frequencyCurve;
this.colorHigh = colorHigh;
this.colorLow = colorLow;
this.manualCurve = manualCurve;
this.modifyColorHigh = modifyColorHigh;
this.useColorHighGradient = useColorHighGradient;
this.colorHighConstant = colorHighConstant;
this.colorHighCurve = colorHighCurve;
this.modifyColorLow = modifyColorLow;
this.useColorLowGradient = useColorLowGradient;
this.colorLowConstant = colorLowConstant;
this.colorLowCurve = colorLowCurve;
}
}
/// <summary>
/// StrobeFlash 的震动聚合器。
/// StrobeFlash 的震动聚合器。最新添加的 Shake 具有最高优先级。
/// </summary>
[AddComponentMenu("SLS Utilities/Feedback Shakers/Strobe Flash Shaker")]
public class StrobeFlashShaker : MonoBehaviour
@@ -100,55 +155,72 @@ namespace Cielonos.MainGame.Effects.Feedback
{
if (!_resolved || _activeShakes.Count == 0) return;
float latestFrequency = _initialFrequency;
Color latestColorHigh = _initialColorHigh;
Color latestColorLow = _initialColorLow;
bool hasExtra = false;
for (int i = _activeShakes.Count - 1; i >= 0; i--)
{
StrobeFlashShakeInstance shake = _activeShakes[i];
shake.timer += shake.timeProvider.GetDeltaTime(shake.timeSettings);
float normalizedTime = shake.timer / shake.duration;
if (shake.modifyExtra && !shake.IsFinished)
{
latestFrequency = shake.frequencyCurve.Evaluate(normalizedTime);
latestColorHigh = shake.colorHigh.Evaluate(normalizedTime);
latestColorLow = shake.colorLow.Evaluate(normalizedTime);
hasExtra = true;
}
if (shake.IsFinished)
{
_activeShakes[i].timer += _activeShakes[i].timeProvider.GetDeltaTime(_activeShakes[i].timeSettings);
if (_activeShakes[i].IsFinished)
_activeShakes.RemoveAt(i);
}
}
_component.enableEffect.value = true;
_component.autoFlash.value = true;
if (hasExtra)
{
_component.frequency.value = latestFrequency;
_component.colorHigh.value = latestColorHigh;
_component.colorLow.value = latestColorLow;
}
if (_activeShakes.Count == 0)
{
Restore();
return;
}
// 最新添加(最高索引)的 Shake 具有最高优先级。
StrobeFlashShakeInstance dominant = _activeShakes[_activeShakes.Count - 1];
float normalizedTime = dominant.timer / dominant.duration;
_component.enableEffect.value = true;
switch (dominant.frequencyMode)
{
case StrobeFrequencyMode.Constant:
_component.autoFlash.value = true;
_component.manualInvert.value = false;
_component.frequency.value = dominant.constantFrequency;
break;
case StrobeFrequencyMode.Curve:
_component.autoFlash.value = true;
_component.manualInvert.value = false;
_component.frequency.value = dominant.frequencyCurve.Evaluate(normalizedTime);
break;
case StrobeFrequencyMode.Manual:
_component.autoFlash.value = false;
_component.manualInvert.value = dominant.manualCurve.Evaluate(normalizedTime) >= 1f;
break;
}
if (dominant.modifyColorHigh)
{
_component.colorHigh.value = dominant.useColorHighGradient
? dominant.colorHighCurve.Evaluate(normalizedTime)
: dominant.colorHighConstant;
}
if (dominant.modifyColorLow)
{
_component.colorLow.value = dominant.useColorLowGradient
? dominant.colorLowCurve.Evaluate(normalizedTime)
: dominant.colorLowConstant;
}
}
private void OnShakeEvent(
FeedbackContext feedbackContext,
float duration,
bool modifyExtra,
StrobeFrequencyMode frequencyMode,
float constantFrequency,
FloatCurveChannel frequencyCurve,
ColorCurveChannel colorHigh,
ColorCurveChannel colorLow,
AnimationCurve manualCurve,
bool modifyColorHigh,
bool useColorHighGradient,
Color colorHighConstant,
ColorCurveChannel colorHighCurve,
bool modifyColorLow,
bool useColorLowGradient,
Color colorLowConstant,
ColorCurveChannel colorLowCurve,
bool stop)
{
if (stop) { StopAll(); return; }
@@ -156,7 +228,10 @@ namespace Cielonos.MainGame.Effects.Feedback
if (!_resolved) return;
var instance = new StrobeFlashShakeInstance(
feedbackContext, modifyExtra, frequencyCurve, colorHigh, colorLow
feedbackContext,
frequencyMode, constantFrequency, frequencyCurve, manualCurve,
modifyColorHigh, useColorHighGradient, colorHighConstant, colorHighCurve,
modifyColorLow, useColorLowGradient, colorLowConstant, colorLowCurve
);
_activeShakes.Add(instance);
}
@@ -176,6 +251,9 @@ namespace Cielonos.MainGame.Effects.Feedback
private void Restore()
{
if (!_resolved) return;
_component.enableEffect.value = false;
_component.autoFlash.value = false;
_component.manualInvert.value = false;
_component.frequency.value = _initialFrequency;
_component.colorHigh.value = _initialColorHigh;
_component.colorLow.value = _initialColorLow;

View File

@@ -1,8 +1,8 @@
fileFormatVersion: 2
guid: 18cfbdc87454ce345a403f5701b05a87
NativeFormatImporter:
guid: fa86055ddf16697439a17745c83a4456
folderAsset: yes
DefaultImporter:
externalObjects: {}
mainObjectFileID: 7400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,72 @@
using System.Collections.Generic;
using Sirenix.OdinInspector;
using UnityEngine;
namespace Cielonos.MainGame.Map
{
[CreateAssetMenu(fileName = "MapGenerationConfig", menuName = "Cielonos/Map/MapGenerationConfig")]
public class MapGenerationConfig : SerializedScriptableObject
{
// ----------------------------------------------------------------
// 地图结构
// ----------------------------------------------------------------
[Title("地图结构")]
[Tooltip("网格的半径大小(实际网格为 (2*gridRadius+1) x (2*gridRadius+1)")]
[MinValue(3), MaxValue(10)]
public int gridRadius = 5;
[Tooltip("期望生成的房间总数(不含起点和 Boss")]
[MinValue(8), MaxValue(80)]
public int targetRoomCount = 20;
[Tooltip("Boss 节点与起点之间的最小距离(曼哈顿距离)")]
[MinValue(3)]
public int minBossDistance = 5;
// ----------------------------------------------------------------
// 特殊节点数量配额
// ----------------------------------------------------------------
[Title("特殊节点配额")]
[Tooltip("每种特殊节点类型在整张地图中的数量上限")]
[DictionaryDrawerSettings(KeyLabel = "节点类型", ValueLabel = "数量")]
public Dictionary<MapNodeType, int> specialNodeCounts = new Dictionary<MapNodeType, int>
{
{ MapNodeType.EliteCombat, 3 },
{ MapNodeType.MechanicalTable, 2 },
{ MapNodeType.LogisticsCenter, 2 },
{ MapNodeType.MedicalStation, 2 },
};
[Tooltip("特殊节点与起点之间的最小距离BFS 步数),避免起点附近出现商店等")]
[MinValue(1)]
public int specialNodeMinDistanceFromStart = 2;
[Tooltip("同类特殊节点之间的最小距离BFS 步数),防止同类型节点扎堆")]
[MinValue(1)]
public int specialNodeMinSameTypeDistance = 1;
// ----------------------------------------------------------------
// ZoneData 资产名配置
// ----------------------------------------------------------------
[Title("ZoneData 资产名配置")]
[Tooltip("可用的普通战斗 ZoneData 资产名列表(随机抽取分配给 NormalCombat 节点)")]
public List<string> normalCombatZoneDataNames = new List<string>();
[Tooltip("可用的精英战斗 ZoneData 资产名列表(随机抽取分配给 EliteCombat 节点)")]
public List<string> eliteCombatZoneDataNames = new List<string>();
[Tooltip("Boss 战斗 ZoneData 资产名(固定分配给 Boss 节点)")]
public string bossCombatZoneDataName;
// ----------------------------------------------------------------
// UI 布局参数
// ----------------------------------------------------------------
[Title("UI 布局参数")]
[Tooltip("节点之间的间距(用于 UI 坐标计算)")]
public float nodeSpacing = 120f;
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 3fc5f071bddbe134ab39c8fdf1f21bc3

View File

@@ -0,0 +1,465 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace Cielonos.MainGame.Map
{
/// <summary>
/// 全联通地图生成器,生成类似"以撒的结合"/"挺进地牢"的 2D 网格地图。
/// 所有节点双向互通,玩家可以自由走遍地图中的每一个房间。
/// </summary>
public static class MapGenerator
{
/// <summary>网格四方向偏移。</summary>
private static readonly Vector2Int[] Directions =
{
Vector2Int.up,
Vector2Int.down,
Vector2Int.left,
Vector2Int.right
};
/// <summary>生成失败时允许的最大重试次数。</summary>
private const int MAX_GENERATION_RETRIES = 10;
/// <summary>
/// 根据配置生成一份完整的全联通 RunMapData。
/// 若特殊节点配额无法满足,则重新生成,最多重试 <see cref="MAX_GENERATION_RETRIES"/> 次。
/// 所有重试均失败时返回 null 并输出警告。
/// </summary>
public static RunMapData Generate(MapGenerationConfig config)
{
for (int attempt = 1; attempt <= MAX_GENERATION_RETRIES; attempt++)
{
RunMapData result = TryGenerate(config);
if (result != null)
return result;
Debug.Log(
$"[MapGenerator] 第 {attempt} 次生成失败(特殊节点配额未满足),正在重新生成...");
}
Debug.LogWarning(
$"[MapGenerator] 连续 {MAX_GENERATION_RETRIES} 次生成均失败,终止地图生成。" +
$"请检查 specialNodeCounts / specialNodeMinSameTypeDistance / targetRoomCount 是否过于严格。");
return null;
}
/// <summary>
/// 执行单次地图生成。若特殊节点配额无法完全满足则返回 null。
/// </summary>
private static RunMapData TryGenerate(MapGenerationConfig config)
{
RunMapData mapData = new RunMapData
{
nodes = new Dictionary<Vector2Int, RunMapNode>()
};
// --- 1. 起点 ---
Vector2Int startPos = Vector2Int.zero;
mapData.startPosition = startPos;
PlaceNode(mapData, startPos, MapNodeType.Start);
// --- 2. 扩展房间 ---
ExpandRooms(mapData, config);
// --- 3. 建立所有相邻节点之间的双向连接 ---
ConnectAllAdjacentNodes(mapData);
// --- 4. 放置 Boss 节点(最远的死胡同) ---
PlaceBossNode(mapData, config);
// --- 5. 分配特殊节点类型(配额未满足则本次生成失败)---
if (!AssignSpecialNodes(mapData, config))
return null;
// --- 6. 为剩余节点分配 ZoneData ---
AssignZoneData(mapData, config);
// --- 7. 计算 UI 坐标 ---
AssignUIPositions(mapData, config);
mapData.totalNodes = mapData.nodes.Count;
return mapData;
}
// ================================================================
// 房间扩展(类以撒算法)
// ================================================================
/// <summary>
/// 从起点开始,使用队列式随机扩展在网格上铺开房间。
/// 每次从已有房间中随机选一个,向随机方向尝试扩展。
/// </summary>
private static void ExpandRooms(RunMapData mapData, MapGenerationConfig config)
{
int targetCount = config.targetRoomCount + 1; // +1 包含起点
List<Vector2Int> existingPositions = new List<Vector2Int>(mapData.nodes.Keys);
int maxAttempts = targetCount * 20;
int attempts = 0;
while (mapData.nodes.Count < targetCount && attempts < maxAttempts)
{
attempts++;
// 从已有节点中随机选一个作为扩展源
Vector2Int source = existingPositions[Random.Range(0, existingPositions.Count)];
// 随机选择一个方向
Vector2Int dir = Directions[Random.Range(0, Directions.Length)];
Vector2Int candidate = source + dir;
// 检查是否已存在、是否在网格范围内
if (mapData.nodes.ContainsKey(candidate)) continue;
if (!IsWithinGrid(candidate, config.gridRadius)) continue;
// 限制邻居数量,避免地图过于密集(最多 3 个已有邻居)
int adjacentCount = CountAdjacentNodes(mapData, candidate);
if (adjacentCount > MAX_ADJACENT_FOR_EXPANSION) continue;
PlaceNode(mapData, candidate, MapNodeType.NormalCombat);
existingPositions.Add(candidate);
}
if (mapData.nodes.Count < targetCount)
{
Debug.LogWarning(
$"[MapGenerator] 仅生成 {mapData.nodes.Count}/{targetCount} 个房间" +
$"(网格半径 {config.gridRadius} 可能过小)。");
}
}
/// <summary>扩展时允许的最大已有邻居数,避免生成过于密集的块状区域。</summary>
private const int MAX_ADJACENT_FOR_EXPANSION = 2;
// ================================================================
// 连接建立
// ================================================================
/// <summary>
/// 遍历所有节点,为每对相邻节点建立双向连接。
/// </summary>
private static void ConnectAllAdjacentNodes(RunMapData mapData)
{
foreach (KeyValuePair<Vector2Int, RunMapNode> kvp in mapData.nodes)
{
Vector2Int pos = kvp.Key;
RunMapNode node = kvp.Value;
foreach (Vector2Int dir in Directions)
{
Vector2Int neighborPos = pos + dir;
if (mapData.nodes.ContainsKey(neighborPos) &&
!node.connectedPositions.Contains(neighborPos))
{
node.connectedPositions.Add(neighborPos);
}
}
}
}
// ================================================================
// Boss 放置
// ================================================================
/// <summary>
/// 将距离起点最远的死胡同节点设为 Boss 节点。
/// 若没有足够远的死胡同,则选距离最远的任意节点。
/// </summary>
private static void PlaceBossNode(RunMapData mapData, MapGenerationConfig config)
{
Dictionary<Vector2Int, int> distances = ComputeBfsDistances(mapData, mapData.startPosition);
// 优先选择满足最小距离的死胡同(度数 == 1
Vector2Int bestPos = mapData.startPosition;
int bestDist = -1;
foreach (KeyValuePair<Vector2Int, int> kvp in distances)
{
if (kvp.Key == mapData.startPosition) continue;
RunMapNode node = mapData.nodes[kvp.Key];
bool isDeadEnd = node.Degree == 1;
bool meetsMinDist = kvp.Value >= config.minBossDistance;
if (meetsMinDist && isDeadEnd && kvp.Value > bestDist)
{
bestDist = kvp.Value;
bestPos = kvp.Key;
}
}
// 若没找到满足条件的死胡同,退而求其次选最远节点
if (bestDist < 0)
{
foreach (KeyValuePair<Vector2Int, int> kvp in distances)
{
if (kvp.Key == mapData.startPosition) continue;
if (kvp.Value > bestDist)
{
bestDist = kvp.Value;
bestPos = kvp.Key;
}
}
}
mapData.nodes[bestPos].nodeType = MapNodeType.BossCombat;
mapData.bossPosition = bestPos;
}
// ================================================================
// 特殊节点分配
// ================================================================
/// <summary>
/// 按配额分配特殊节点。优先放在死胡同,其次放在低度数节点。
/// 所有特殊节点需满足:与起点的最小距离约束、同类节点间的最小距离约束。
/// </summary>
/// <returns>所有类型的配额均完全满足时返回 true任意类型放置数量不足时返回 false。</returns>
private static bool AssignSpecialNodes(RunMapData mapData, MapGenerationConfig config)
{
Dictionary<Vector2Int, int> distancesFromStart =
ComputeBfsDistances(mapData, mapData.startPosition);
// 收集可用候选节点(排除起点和 Boss
List<Vector2Int> candidates = mapData.nodes.Keys
.Where(pos =>
pos != mapData.startPosition &&
pos != mapData.bossPosition &&
distancesFromStart.TryGetValue(pos, out int dist) &&
dist >= config.specialNodeMinDistanceFromStart)
.OrderBy(pos => mapData.nodes[pos].Degree) // 死胡同优先
.ThenByDescending(pos => distancesFromStart[pos]) // 距离远的优先
.ToList();
// 记录每种类型已放置的节点坐标,用于同类距离检查
Dictionary<MapNodeType, List<Vector2Int>> placedByType =
new Dictionary<MapNodeType, List<Vector2Int>>();
foreach (KeyValuePair<MapNodeType, int> quota in config.specialNodeCounts)
{
MapNodeType nodeType = quota.Key;
int targetCount = quota.Value;
if (!placedByType.ContainsKey(nodeType))
placedByType[nodeType] = new List<Vector2Int>();
int placed = 0;
List<Vector2Int> toRemove = new List<Vector2Int>();
foreach (Vector2Int pos in candidates)
{
if (placed >= targetCount) break;
// 同类距离约束检查
if (!SatisfiesSameTypeDistance(mapData, pos, placedByType[nodeType],
config.specialNodeMinSameTypeDistance))
{
continue;
}
mapData.nodes[pos].nodeType = nodeType;
placedByType[nodeType].Add(pos);
placed++;
toRemove.Add(pos);
}
// 从候选池移除已分配的节点
foreach (Vector2Int pos in toRemove)
candidates.Remove(pos);
// 配额未满足,本次生成失败
if (placed < targetCount)
return false;
}
return true;
}
/// <summary>
/// 检查候选位置与所有已放置的同类节点之间的 BFS 距离是否满足最小距离约束。
/// </summary>
private static bool SatisfiesSameTypeDistance(
RunMapData mapData,
Vector2Int candidate,
List<Vector2Int> placedSameType,
int minDistance)
{
if (placedSameType.Count == 0 || minDistance <= 1) return true;
// 从候选位置出发做一次 BFS只需要探索到 minDistance 深度即可
Dictionary<Vector2Int, int> distances = ComputeBfsDistancesWithLimit(
mapData, candidate, minDistance);
foreach (Vector2Int placedPos in placedSameType)
{
if (distances.TryGetValue(placedPos, out int dist) && dist < minDistance)
{
return false;
}
}
return true;
}
/// <summary>
/// 限深度 BFS仅探索到 maxDepth 步即停止,用于距离约束检查以减少不必要的遍历。
/// </summary>
private static Dictionary<Vector2Int, int> ComputeBfsDistancesWithLimit(
RunMapData mapData, Vector2Int start, int maxDepth)
{
Dictionary<Vector2Int, int> distances = new Dictionary<Vector2Int, int>();
Queue<Vector2Int> queue = new Queue<Vector2Int>();
distances[start] = 0;
queue.Enqueue(start);
while (queue.Count > 0)
{
Vector2Int current = queue.Dequeue();
int currentDist = distances[current];
if (currentDist >= maxDepth) continue;
RunMapNode node = mapData.nodes[current];
foreach (Vector2Int neighbor in node.connectedPositions)
{
if (!distances.ContainsKey(neighbor))
{
distances[neighbor] = currentDist + 1;
queue.Enqueue(neighbor);
}
}
}
return distances;
}
// ================================================================
// ZoneData 分配
// ================================================================
/// <summary>
/// 为所有战斗类型节点分配 ZoneData 资产名。
/// </summary>
private static void AssignZoneData(RunMapData mapData, MapGenerationConfig config)
{
foreach (RunMapNode node in mapData.nodes.Values)
{
node.zoneDataAssetName = ResolveZoneDataName(node.nodeType, config);
}
}
/// <summary>
/// 根据节点类型从配置中随机抽取对应的 ZoneData 资产名。
/// 非战斗类型节点返回空字符串。
/// </summary>
private static string ResolveZoneDataName(MapNodeType nodeType, MapGenerationConfig config)
{
switch (nodeType)
{
case MapNodeType.NormalCombat:
return PickRandom(config.normalCombatZoneDataNames);
case MapNodeType.EliteCombat:
return PickRandom(config.eliteCombatZoneDataNames);
case MapNodeType.BossCombat:
return config.bossCombatZoneDataName ?? string.Empty;
default:
return string.Empty;
}
}
// ================================================================
// UI 坐标
// ================================================================
/// <summary>
/// 根据网格坐标计算每个节点的 UI 位置。
/// </summary>
private static void AssignUIPositions(RunMapData mapData, MapGenerationConfig config)
{
foreach (KeyValuePair<Vector2Int, RunMapNode> kvp in mapData.nodes)
{
kvp.Value.position = new Vector2(
kvp.Key.x * config.nodeSpacing,
kvp.Key.y * config.nodeSpacing
);
}
}
// ================================================================
// 工具方法
// ================================================================
/// <summary>在指定位置创建并放置一个节点。</summary>
private static void PlaceNode(RunMapData mapData, Vector2Int pos, MapNodeType nodeType)
{
RunMapNode node = new RunMapNode
{
gridPosition = pos,
nodeType = nodeType,
position = Vector2.zero,
sceneName = string.Empty,
zoneDataAssetName = string.Empty,
connectedPositions = new List<Vector2Int>()
};
mapData.nodes[pos] = node;
}
/// <summary>检查坐标是否在网格范围内。</summary>
private static bool IsWithinGrid(Vector2Int pos, int gridRadius)
{
return Mathf.Abs(pos.x) <= gridRadius && Mathf.Abs(pos.y) <= gridRadius;
}
/// <summary>计算候选位置周围已有节点的数量。</summary>
private static int CountAdjacentNodes(RunMapData mapData, Vector2Int pos)
{
int count = 0;
foreach (Vector2Int dir in Directions)
{
if (mapData.nodes.ContainsKey(pos + dir)) count++;
}
return count;
}
/// <summary>
/// BFS 计算从起点到所有节点的最短步数距离。
/// </summary>
private static Dictionary<Vector2Int, int> ComputeBfsDistances(
RunMapData mapData, Vector2Int start)
{
Dictionary<Vector2Int, int> distances = new Dictionary<Vector2Int, int>();
Queue<Vector2Int> queue = new Queue<Vector2Int>();
distances[start] = 0;
queue.Enqueue(start);
while (queue.Count > 0)
{
Vector2Int current = queue.Dequeue();
int currentDist = distances[current];
RunMapNode node = mapData.nodes[current];
foreach (Vector2Int neighbor in node.connectedPositions)
{
if (!distances.ContainsKey(neighbor))
{
distances[neighbor] = currentDist + 1;
queue.Enqueue(neighbor);
}
}
}
return distances;
}
/// <summary>从列表中随机取一个元素,列表为空时返回空字符串。</summary>
private static string PickRandom(List<string> list)
{
if (list == null || list.Count == 0) return string.Empty;
return list[Random.Range(0, list.Count)];
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 07f5101bb66f25042a8cec2b0b5e7c86

View File

@@ -0,0 +1,396 @@
using System.Collections.Generic;
using System.Linq;
using Cielonos.MainGame.Map;
using Sirenix.OdinInspector;
using UnityEngine;
#if UNITY_EDITOR
using Sirenix.Utilities.Editor;
using UnityEditor;
#endif
namespace Cielonos.MainGame.Map
{
/// <summary>
/// 地图预览器,在 Inspector 中可视化生成并展示全联通网格地图。
/// </summary>
[CreateAssetMenu(fileName = "MapPreviewer", menuName = "Cielonos/Map/MapPreviewer")]
public class MapPreviewer : SerializedScriptableObject
{
// ----------------------------------------------------------------
// 配置
// ----------------------------------------------------------------
[Title("配置")]
[Required("需要指定 MapGenerationConfig")]
public MapGenerationConfig config;
[Title("预览外观")]
[Range(300f, 1000f)]
public float previewSize = 600f;
[MinValue(6f), MaxValue(24f)]
public float nodeRadius = 12f;
[Range(1f, 6f)]
public float edgeThickness = 2.5f;
// ----------------------------------------------------------------
// 节点颜色映射
// ----------------------------------------------------------------
[Title("节点颜色")]
public Color colorStart = new Color(0.4f, 0.9f, 0.4f);
public Color colorNormalCombat = new Color(0.85f, 0.35f, 0.35f);
public Color colorEliteCombat = new Color(0.9f, 0.55f, 0.15f);
public Color colorBossCombat = new Color(0.7f, 0.15f, 0.85f);
public Color colorMechanicalTable = new Color(0.3f, 0.7f, 1.0f);
public Color colorLogisticsCenter = new Color(1.0f, 0.85f, 0.2f);
public Color colorMedicalStation = new Color(0.3f, 0.85f, 0.6f);
#if UNITY_EDITOR
// ----------------------------------------------------------------
// 运行时缓存(仅 Editor
// ----------------------------------------------------------------
[HideInInspector]
public RunMapData previewData;
// ----------------------------------------------------------------
// 按钮
// ----------------------------------------------------------------
[Title("操作")]
[Button("生成随机地图", ButtonSizes.Large), GUIColor(0.4f, 0.85f, 0.5f)]
public void GeneratePreview()
{
if (config == null)
{
Debug.LogWarning("[MapPreviewer] 请先指定 MapGenerationConfig。");
return;
}
previewData = MapGenerator.Generate(config);
EditorUtility.SetDirty(this);
}
[Button("清空预览", ButtonSizes.Medium), GUIColor(0.85f, 0.4f, 0.4f)]
public void ClearPreview()
{
previewData = null;
EditorUtility.SetDirty(this);
}
// ----------------------------------------------------------------
// Inspector 绘制
// ----------------------------------------------------------------
[OnInspectorGUI]
private void DrawMapCanvas()
{
if (previewData == null || previewData.nodes == null || previewData.nodes.Count == 0)
{
SirenixEditorGUI.InfoMessageBox("尚未生成地图,请点击「生成随机地图」按钮。");
return;
}
GUILayout.Space(8f);
SirenixEditorGUI.Title("地图预览", $"共 {previewData.totalNodes} 个房间", TextAlignment.Center, horizontalLine: true);
GUILayout.Space(4f);
// 预留正方形画布
Rect canvasRect = GUILayoutUtility.GetRect(
GUIContent.none,
GUIStyle.none,
GUILayout.ExpandWidth(true),
GUILayout.Height(previewSize)
);
// 深色背景
SirenixEditorGUI.DrawSolidRect(canvasRect, new Color(0.12f, 0.12f, 0.15f, 1f));
// 计算屏幕坐标
Dictionary<Vector2Int, Vector2> screenPositions = ComputeScreenPositions(canvasRect);
// 绘制连线(先画)
DrawEdges(screenPositions);
// 绘制节点
DrawNodes(screenPositions);
// 图例
DrawLegend(canvasRect);
// 统计信息
DrawStats(canvasRect);
GUILayout.Space(4f);
}
// ----------------------------------------------------------------
// 坐标映射
// ----------------------------------------------------------------
private Dictionary<Vector2Int, Vector2> ComputeScreenPositions(Rect canvas)
{
Dictionary<Vector2Int, Vector2> result = new Dictionary<Vector2Int, Vector2>();
if (previewData.nodes.Count == 0) return result;
// 找出网格坐标的边界
int minX = int.MaxValue, maxX = int.MinValue;
int minY = int.MaxValue, maxY = int.MinValue;
foreach (Vector2Int pos in previewData.nodes.Keys)
{
if (pos.x < minX) minX = pos.x;
if (pos.x > maxX) maxX = pos.x;
if (pos.y < minY) minY = pos.y;
if (pos.y > maxY) maxY = pos.y;
}
int gridWidth = Mathf.Max(maxX - minX, 1);
int gridHeight = Mathf.Max(maxY - minY, 1);
const float paddingRatio = 0.08f;
float padX = canvas.width * paddingRatio;
float padY = canvas.height * paddingRatio;
float cellW = (canvas.width - padX * 2f) / gridWidth;
float cellH = (canvas.height - padY * 2f) / gridHeight;
float cellSize = Mathf.Min(cellW, cellH);
// 居中偏移
float totalW = gridWidth * cellSize;
float totalH = gridHeight * cellSize;
float offsetX = canvas.x + (canvas.width - totalW) * 0.5f;
float offsetY = canvas.y + (canvas.height - totalH) * 0.5f;
foreach (Vector2Int pos in previewData.nodes.Keys)
{
float sx = offsetX + (pos.x - minX) * cellSize;
// Y 轴翻转:网格 Y 越大 → 画布 Y 越小(向上)
float sy = offsetY + (maxY - pos.y) * cellSize;
result[pos] = new Vector2(sx, sy);
}
return result;
}
// ----------------------------------------------------------------
// 连线绘制
// ----------------------------------------------------------------
private void DrawEdges(Dictionary<Vector2Int, Vector2> positions)
{
if (Event.current.type != EventType.Repaint) return;
Color edgeColor = new Color(0.45f, 0.45f, 0.55f, 0.7f);
HashSet<(Vector2Int, Vector2Int)> drawnEdges = new HashSet<(Vector2Int, Vector2Int)>();
foreach (KeyValuePair<Vector2Int, RunMapNode> kvp in previewData.nodes)
{
Vector2Int fromPos = kvp.Key;
if (!positions.TryGetValue(fromPos, out Vector2 fromScreen)) continue;
foreach (Vector2Int toPos in kvp.Value.connectedPositions)
{
// 避免双向连接绘制两次
var edgeKey = fromPos.x < toPos.x || (fromPos.x == toPos.x && fromPos.y < toPos.y)
? (fromPos, toPos)
: (toPos, fromPos);
if (drawnEdges.Contains(edgeKey)) continue;
drawnEdges.Add(edgeKey);
if (!positions.TryGetValue(toPos, out Vector2 toScreen)) continue;
DrawThickLine(fromScreen, toScreen, edgeColor, edgeThickness);
}
}
}
private static void DrawThickLine(Vector2 from, Vector2 to, Color color, float thickness)
{
Handles.color = color;
Vector2 dir = (to - from).normalized;
Vector2 perp = new Vector2(-dir.y, dir.x);
int steps = Mathf.Max(1, Mathf.RoundToInt(thickness));
float halfT = (steps - 1) * 0.5f;
for (int i = 0; i < steps; i++)
{
float offset = (i - halfT) * 0.8f;
Vector3 f3 = new Vector3(from.x + perp.x * offset, from.y + perp.y * offset, 0f);
Vector3 t3 = new Vector3(to.x + perp.x * offset, to.y + perp.y * offset, 0f);
Handles.DrawLine(f3, t3);
}
}
// ----------------------------------------------------------------
// 节点绘制
// ----------------------------------------------------------------
private void DrawNodes(Dictionary<Vector2Int, Vector2> positions)
{
if (Event.current.type != EventType.Repaint) return;
foreach (KeyValuePair<Vector2Int, RunMapNode> kvp in previewData.nodes)
{
if (!positions.TryGetValue(kvp.Key, out Vector2 center)) continue;
RunMapNode node = kvp.Value;
Color nodeColor = GetNodeColor(node.nodeType);
// 外圈(深色边框)
float outerR = nodeRadius + 2f;
Handles.color = new Color(0.05f, 0.05f, 0.05f, 0.9f);
Handles.DrawSolidDisc(new Vector3(center.x, center.y, 0f), Vector3.forward, outerR);
// 节点填充
Handles.color = nodeColor;
Handles.DrawSolidDisc(new Vector3(center.x, center.y, 0f), Vector3.forward, nodeRadius);
// 节点标签
DrawNodeLabel(node, center);
}
}
private void DrawNodeLabel(RunMapNode node, Vector2 center)
{
string label = GetNodeShortLabel(node.nodeType);
GUIStyle style = new GUIStyle(EditorStyles.miniLabel)
{
alignment = TextAnchor.MiddleCenter,
fontStyle = FontStyle.Bold,
fontSize = 9,
normal = { textColor = Color.white }
};
float labelW = 48f;
float labelH = 16f;
Rect labelRect = new Rect(center.x - labelW * 0.5f, center.y + nodeRadius + 2f, labelW, labelH);
GUI.Label(labelRect, label, style);
}
// ----------------------------------------------------------------
// 图例
// ----------------------------------------------------------------
private void DrawLegend(Rect canvas)
{
if (Event.current.type != EventType.Repaint) return;
var entries = new (MapNodeType type, string label)[]
{
(MapNodeType.Start, "起点"),
(MapNodeType.NormalCombat, "普通战斗"),
(MapNodeType.EliteCombat, "精英战斗"),
(MapNodeType.BossCombat, "Boss"),
(MapNodeType.MechanicalTable, "机械台"),
(MapNodeType.LogisticsCenter, "物流中心"),
(MapNodeType.MedicalStation, "医疗站"),
};
const float dotSize = 10f;
const float itemH = 16f;
const float itemW = 90f;
const float padLeft = 8f;
const float padBottom = 8f;
float totalH = entries.Length * itemH + 4f;
float startY = canvas.yMax - padBottom - totalH;
Rect bgRect = new Rect(canvas.x + padLeft - 4f, startY - 2f, itemW + 8f, totalH + 4f);
SirenixEditorGUI.DrawSolidRect(bgRect, new Color(0f, 0f, 0f, 0.45f));
GUIStyle labelStyle = new GUIStyle(EditorStyles.miniLabel)
{
normal = { textColor = new Color(0.85f, 0.85f, 0.85f) }
};
for (int i = 0; i < entries.Length; i++)
{
float y = startY + i * itemH;
Handles.color = GetNodeColor(entries[i].type);
Handles.DrawSolidDisc(
new Vector3(canvas.x + padLeft + dotSize * 0.5f, y + itemH * 0.5f, 0f),
Vector3.forward, dotSize * 0.5f);
Rect textRect = new Rect(canvas.x + padLeft + dotSize + 4f, y, itemW - dotSize - 4f, itemH);
GUI.Label(textRect, entries[i].label, labelStyle);
}
}
// ----------------------------------------------------------------
// 统计信息
// ----------------------------------------------------------------
private void DrawStats(Rect canvas)
{
if (Event.current.type != EventType.Repaint) return;
// 统计各类型数量
Dictionary<MapNodeType, int> counts = new Dictionary<MapNodeType, int>();
foreach (RunMapNode node in previewData.nodes.Values)
{
if (!counts.ContainsKey(node.nodeType))
counts[node.nodeType] = 0;
counts[node.nodeType]++;
}
string stats = string.Join(" | ", counts
.OrderBy(kvp => kvp.Key)
.Select(kvp => $"{GetNodeShortLabel(kvp.Key)}: {kvp.Value}"));
GUIStyle style = new GUIStyle(EditorStyles.miniLabel)
{
alignment = TextAnchor.MiddleRight,
normal = { textColor = new Color(0.7f, 0.7f, 0.7f) }
};
const float padRight = 8f;
const float padTop = 6f;
Rect statsRect = new Rect(canvas.x, canvas.y + padTop, canvas.width - padRight, 16f);
GUI.Label(statsRect, stats, style);
}
// ----------------------------------------------------------------
// 工具方法
// ----------------------------------------------------------------
private Color GetNodeColor(MapNodeType type)
{
return type switch
{
MapNodeType.Start => colorStart,
MapNodeType.NormalCombat => colorNormalCombat,
MapNodeType.EliteCombat => colorEliteCombat,
MapNodeType.BossCombat => colorBossCombat,
MapNodeType.MechanicalTable => colorMechanicalTable,
MapNodeType.LogisticsCenter => colorLogisticsCenter,
MapNodeType.MedicalStation => colorMedicalStation,
_ => Color.white,
};
}
private static string GetNodeShortLabel(MapNodeType type)
{
return type switch
{
MapNodeType.Start => "Start",
MapNodeType.NormalCombat => "Combat",
MapNodeType.EliteCombat => "Elite",
MapNodeType.BossCombat => "BOSS",
MapNodeType.MechanicalTable => "Chest",
MapNodeType.LogisticsCenter => "Shop",
MapNodeType.MedicalStation => "Med",
_ => "?",
};
}
#endif
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 1909a1a45fa45594e94a89aa02e3dfe2

View File

@@ -0,0 +1,10 @@
using RootMotion;
using UnityEngine;
namespace Cielonos.MainGame
{
public class RunManager : Singleton<RunManager>
{
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 8222c6b4127177848ab9c9e8fdc0650d

View File

@@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Cielonos.MainGame
{
[Serializable]
public class RunMapNode
{
public Vector2Int gridPosition; // 节点在网格中的坐标
public MapNodeType nodeType;
public Vector2 position; // UI 定位用
public string sceneName; // 对应的 ZoneData.sceneName战斗节点
public string zoneDataAssetName; // 关联的 ZoneData 资产名
public List<Vector2Int> connectedPositions; // 双向连接的相邻节点坐标列表
/// <summary>
/// 该节点的连接数(度数)。度数为 1 的节点为"死胡同"。
/// </summary>
public int Degree => connectedPositions?.Count ?? 0;
}
public enum MapNodeType
{
Start, // 起始节点
NormalCombat, // 普通战斗
EliteCombat, // 精英战斗(更强的敌人配置)
BossCombat, // Boss 战
MechanicalTable, // 机械台(宝箱房,可获取装备)
LogisticsCenter, // 物流中心(商店)
MedicalStation, // 医疗站点恢复HP
}
[Serializable]
public class RunMapData
{
public Dictionary<Vector2Int, RunMapNode> nodes; // 所有节点,按网格坐标索引
public Vector2Int startPosition; // 起始节点坐标
public Vector2Int bossPosition; // Boss 节点坐标
public int totalNodes; // 节点总数
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: cc9a61a4bf301a349bb971b3362a79f8

View File

@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Cielonos.MainGame
{
[Serializable]
public class RunState
{
public RunMapData mapData; // 本局生成的地图
public Vector2Int currentPosition; // 当前所在节点的网格坐标
public HashSet<Vector2Int> visitedNodes; // 已访问节点坐标集合
public float elapsedTime; // 本局已用时间
public int roomsCleared; // 已清理房间数
public int enemiesDefeated; // 已击杀敌人数
public bool isCompleted; // 是否通关
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 83f1dcc80a3c27c4a9340d8cb779c9c7

View File

@@ -1,17 +0,0 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: c203ecf84f1bcc24192fd302209a1a4c, type: 3}
m_Name: DefaultNode 1
m_EditorClassIdentifier: SLSUtilities::SLSUtilities.Map.MapNodeData
nodeName: Default2
debugColor: {r: 1, g: 0, b: 0, a: 1}
weight: 1

View File

@@ -1,17 +0,0 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: c203ecf84f1bcc24192fd302209a1a4c, type: 3}
m_Name: DefaultNode
m_EditorClassIdentifier: SLSUtilities::SLSUtilities.Map.MapNodeData
nodeName: Default
debugColor: {r: 1, g: 1, b: 1, a: 1}
weight: 1

View File

@@ -1,162 +0,0 @@
using System.Collections.Generic;
using System.Linq; // 需要引用 Linq 进行排序
using UnityEngine;
namespace SLSUtilities.Map
{
public class LayeredMapGenerator : MapGeneratorBase
{
[Header("分层生成设置")]
[Tooltip("地图有多少层(环)")]
public int layerCount = 3;
[Tooltip("每一层的半径间距")]
public float radiusStep = 5f;
[Tooltip("每一层最少/最多生成多少个房间")]
public Vector2Int nodesPerLayerRange = new Vector2Int(5, 8); // 建议最小值稍微调高一点
[Tooltip("位置随机偏移量")]
public float positionJitter = 1.0f;
[Header("连通性设置")]
[Range(0f, 1f)]
public float ringConnectChance = 1.0f; // 设为1方便调试环状结构
// 辅助数据:按层级索引
private Dictionary<int, List<MapNode>> nodesByLayer = new Dictionary<int, List<MapNode>>();
// 覆盖基类的 GenerateMap
[ContextMenu("Generate Layered Map")]
public override void GenerateMap()
{
base.ClearMap();
nodesByLayer.Clear();
GenerateNodesInLayers();
ConnectLayers();
}
private void GenerateNodesInLayers()
{
int globalID = 0;
// --- Layer 0 (Center) ---
MapNode centerNode = new MapNode(globalID++, Vector2.zero, defaultNodeData);
allNodes.Add(centerNode);
nodesByLayer[0] = new List<MapNode> { centerNode };
List<int> layerNodeCounts = new List<int>();
for (int layerIndex = 1; layerIndex <= layerCount; layerIndex++)
{
layerNodeCounts.Add(Random.Range(nodesPerLayerRange.x, nodesPerLayerRange.y + 1));
}
layerNodeCounts.Sort(); // 从小到大排序,确保外层节点数不少于内层
// --- Layer 1 to N ---
for (int layerIndex = 1; layerIndex <= layerCount; layerIndex++)
{
List<MapNode> currentLayerNodes = new List<MapNode>();
int count = layerNodeCounts[layerIndex - 1];
float currentRadius = layerIndex * radiusStep; // 半径随层级增长略微加快
Debug.Log($"Layer {layerIndex}: Generating {count} nodes at radius {currentRadius}");
for (int i = 0; i < count; i++)
{
float angleStep = 360f / count;
float currentAngle = (i * angleStep); // 先不加随机角度,靠 jitter 产生偏移
float radian = currentAngle * Mathf.Deg2Rad;
// 基础极坐标位置
float x = Mathf.Cos(radian) * currentRadius;
float y = Mathf.Sin(radian) * currentRadius;
Vector2 basePos = new Vector2(x, y);
// 加上 Jitter
Vector2 finalPos = basePos + (Random.insideUnitCircle * positionJitter);
MapNode newNode = new MapNode(globalID++, finalPos, defaultNodeData);
allNodes.Add(newNode);
currentLayerNodes.Add(newNode);
}
// 【关键优化点】:在生成完这一层所有点后,根据实际生成的“角度”重新排序
// 这样即使 Jitter 把点的位置打乱了,连接时依然是顺时针有序的,不会出现交叉
currentLayerNodes = currentLayerNodes.OrderBy(n =>
Mathf.Atan2(n.position.y, n.position.x)
).ToList();
nodesByLayer[layerIndex] = currentLayerNodes;
}
}
private void ConnectLayers()
{
for (int layerIndex = 1; layerIndex <= layerCount; layerIndex++)
{
if (!nodesByLayer.ContainsKey(layerIndex)) continue;
List<MapNode> currentLayer = nodesByLayer[layerIndex];
List<MapNode> previousLayer = nodesByLayer[layerIndex - 1];
for (int i = 0; i < currentLayer.Count; i++)
{
MapNode currentNode = currentLayer[i];
// 1. 向心连接 (Connect to inner layer)
MapNode targetInner = FindClosestNode(currentNode, previousLayer);
CreateEdge(currentNode, targetInner);
// 2. 环状连接 (Ring Connection)
if (Random.value <= ringConnectChance)
{
// 因为我们在生成时已经按 Atan2 排序了,所以 i+1 一定是几何上的相邻点
int nextIndex = (i + 1) % currentLayer.Count;
MapNode neighborNode = currentLayer[nextIndex];
if (!ConnectionExists(currentNode, neighborNode))
{
CreateEdge(currentNode, neighborNode);
}
}
}
}
}
private void CreateEdge(MapNode a, MapNode b)
{
// 简单的防重检查
if (!ConnectionExists(a, b))
{
allEdges.Add(new MapEdge(a, b, true));
}
}
private bool ConnectionExists(MapNode a, MapNode b)
{
foreach (var edge in allEdges)
{
if ((edge.fromNode == a && edge.toNode == b) ||
(edge.fromNode == b && edge.toNode == a))
return true;
}
return false;
}
private MapNode FindClosestNode(MapNode source, List<MapNode> candidates)
{
MapNode bestTarget = null;
float minDst = float.MaxValue;
foreach (var target in candidates)
{
float dst = Vector2.Distance(source.position, target.position);
if (dst < minDst)
{
minDst = dst;
bestTarget = target;
}
}
return bestTarget;
}
}
}

View File

@@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: 072ed2f87a13a1b4fbf73fa9fc545ca5

View File

@@ -1,88 +0,0 @@
using UnityEngine;
using System.Collections.Generic;
namespace SLSUtilities.Map
{
// 将类声明为 abstract表示它不能直接挂载使用必须被继承
public abstract class MapGeneratorBase : MonoBehaviour
{
[Header("基础配置")] public MapNodeData defaultNodeData;
// 存储生成的地图数据 (protected 使得子类可以访问)
[Header("生成结果 (Debug)")] [SerializeField] // 加上这个是为了在Inspector里能看到方便调试
protected List<MapNode> allNodes = new List<MapNode>();
[SerializeField] protected List<MapEdge> allEdges = new List<MapEdge>();
// 抽象方法:强制子类必须实现这个方法
public abstract void GenerateMap();
[ContextMenu("Clear Map")]
public virtual void ClearMap()
{
allNodes.Clear();
allEdges.Clear();
}
// 通用的清理与重置逻辑
protected void ResetIDs()
{
// 如果需要重新整理ID可以在这里写
}
// 通用的 Gizmos 绘制逻辑
protected virtual void OnDrawGizmos()
{
if (allNodes == null) return;
// 画边
Gizmos.color = Color.gray;
if (allEdges != null)
{
foreach (var edge in allEdges)
{
if (edge.fromNode != null && edge.toNode != null)
Gizmos.DrawLine(edge.fromNode.position, edge.toNode.position);
}
}
// 画节点
foreach (var node in allNodes)
{
Gizmos.color = node.data != null ? node.data.debugColor : Color.white;
Gizmos.DrawSphere(node.position, 0.5f);
}
}
}
[System.Serializable]
public class MapNode
{
public int id; // 唯一ID
public Vector2 position; // 在地图上的坐标
public MapNodeData data; // 引用上面的ScriptableObject数据
// 构造函数
public MapNode(int id, Vector2 pos, MapNodeData data)
{
this.id = id;
this.position = pos;
this.data = data;
}
}
[System.Serializable]
public class MapEdge
{
public MapNode fromNode;
public MapNode toNode;
public bool isBidirectional; // 是否双向
public MapEdge(MapNode from, MapNode to, bool bidirectional)
{
this.fromNode = from;
this.toNode = to;
this.isBidirectional = bidirectional;
}
}
}

View File

@@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: 5fb9c1d28c78ce94595b66cc283b2b49

View File

@@ -1,12 +0,0 @@
using UnityEngine;
namespace SLSUtilities.Map
{
[CreateAssetMenu(fileName = "MapNodeData", menuName = "SLSUtilities/Map/Map Node Data", order = 1)]
public class MapNodeData : ScriptableObject
{
public string nodeName;
public Color debugColor = Color.white;
public float weight = 1.0f;
}
}

View File

@@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: c203ecf84f1bcc24192fd302209a1a4c

View File

@@ -14,7 +14,7 @@
"bezi3d"
],
"unity": "2018.3",
"version": "0.84.5",
"version": "0.85.2",
"type": "library",
"hideInEditor": false,
"dependencies": {