Compare commits
2 Commits
e846296fca
...
1f4e20f512
Author | SHA1 | Date |
---|---|---|
|
1f4e20f512 | |
|
350e6d67b2 |
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 38e9902db9777f94b89e56e581e38646
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,29 @@
|
|||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fcb6451023416b841bcd0f8ef63f0e07, type: 3}
|
||||
m_Name: Assets/Artists/Configs/Bullet/NewScriptableBulletServiceData.asset
|
||||
m_EditorClassIdentifier:
|
||||
layerMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
material: {fileID: 0}
|
||||
bulletScaleCurve:
|
||||
allow: 0
|
||||
value:
|
||||
serializedVersion: 2
|
||||
m_Curve: []
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
debug: 0
|
||||
rectangleMesh: {fileID: 0}
|
||||
quadMesh: {fileID: 0}
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b01808c2576581442ad1ccfa22043c5e
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -34,7 +34,8 @@ MonoBehaviour:
|
|||
hdrDebugViewPS: {fileID: 4800000, guid: 573620ae32aec764abd4d728906d2587, type: 3}
|
||||
m_RendererFeatures:
|
||||
- {fileID: -6494507711637086765}
|
||||
m_RendererFeatureMap: d31dd648a5dfdea5
|
||||
- {fileID: 6330780336224773197}
|
||||
m_RendererFeatureMap: d31dd648a5dfdea54da4b4832c73db57
|
||||
m_UseNativeRenderPass: 0
|
||||
postProcessData: {fileID: 11400000, guid: 41439944d30ece34e96484bdb6645b55, type: 2}
|
||||
xrSystemData: {fileID: 11400000, guid: 60e1133243b97e347b653163a8c01b64, type: 2}
|
||||
|
@ -73,3 +74,24 @@ MonoBehaviour:
|
|||
m_CopyDepthMode: 1
|
||||
m_AccurateGbufferNormals: 0
|
||||
m_IntermediateTextureMode: 1
|
||||
--- !u!114 &6330780336224773197
|
||||
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: 5c845a4670d681a46ad45532b21e3488, type: 3}
|
||||
m_Name: VolumetricFogRendererFeature
|
||||
m_EditorClassIdentifier:
|
||||
m_Active: 1
|
||||
volumetricFogSettings:
|
||||
enable: 0
|
||||
renderPassEvent: 100
|
||||
densityAndLightingComputeShader: {fileID: 7200000, guid: 9068eedc2333d524bba83267d923d5a9, type: 3}
|
||||
fogDensity: 0.2
|
||||
fogFarPlaneDistance: 100
|
||||
fogExtinctonCoeffient: 2
|
||||
fogStartHeight: -50
|
||||
|
|
|
@ -161,7 +161,7 @@ MonoBehaviour:
|
|||
active: 1
|
||||
mode:
|
||||
m_OverrideState: 1
|
||||
m_Value: 2
|
||||
m_Value: 1
|
||||
neutralHDRRangeReductionMode:
|
||||
m_OverrideState: 0
|
||||
m_Value: 2
|
||||
|
|
|
@ -9,10 +9,11 @@ GameObject:
|
|||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 7552042800852554496}
|
||||
- component: {fileID: 2476209963240049585}
|
||||
- component: {fileID: 690332996188739794}
|
||||
- component: {fileID: 2162917695259611933}
|
||||
- component: {fileID: 4295018689683312157}
|
||||
- component: {fileID: 1423627268194580453}
|
||||
- component: {fileID: 1376806574884562321}
|
||||
m_Layer: 0
|
||||
m_Name: node_interaction
|
||||
m_TagString: Untagged
|
||||
|
@ -35,26 +36,6 @@ Transform:
|
|||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &2476209963240049585
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1382892546537064314}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: db48a34ef668447439789f37091202ae, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
root: {fileID: 0}
|
||||
type:
|
||||
rid: -2
|
||||
references:
|
||||
version: 2
|
||||
RefIds:
|
||||
- rid: -2
|
||||
type: {class: , ns: , asm: }
|
||||
--- !u!65 &690332996188739794
|
||||
BoxCollider:
|
||||
m_ObjectHideFlags: 0
|
||||
|
@ -103,8 +84,6 @@ MonoBehaviour:
|
|||
m_Script: {fileID: 11500000, guid: 054d7fc7589c04d4a8412a6f82b32d6c, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
worldNodeService:
|
||||
rid: 2091307956764147727
|
||||
worldNode:
|
||||
rid: 2091307956764147728
|
||||
references:
|
||||
|
@ -112,9 +91,6 @@ MonoBehaviour:
|
|||
RefIds:
|
||||
- rid: -2
|
||||
type: {class: , ns: , asm: }
|
||||
- rid: 2091307956764147727
|
||||
type: {class: WorldNodeService, ns: BITKit.WorldNode, asm: BITKit.WorldNode}
|
||||
data:
|
||||
- rid: 2091307956764147728
|
||||
type: {class: WorldInfoNode, ns: BITKit.WorldNode, asm: BITKit.WorldNode}
|
||||
data:
|
||||
|
@ -126,3 +102,36 @@ MonoBehaviour:
|
|||
type: {class: Reference, ns: BITKit, asm: BITKit}
|
||||
data:
|
||||
value: "\u5BF9\u8BDD"
|
||||
--- !u!114 &1423627268194580453
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1382892546537064314}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 230e015069b45484f9c85d1aba1e901c, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
--- !u!114 &1376806574884562321
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1382892546537064314}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 054d7fc7589c04d4a8412a6f82b32d6c, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
worldNode:
|
||||
rid: 7572707351853268992
|
||||
references:
|
||||
version: 2
|
||||
RefIds:
|
||||
- rid: 7572707351853268992
|
||||
type: {class: WorldInteractable, ns: Net.Project.B.Interaction, asm: Com.Project.B.Interaction}
|
||||
data:
|
||||
gameObject: {fileID: 1382892546537064314}
|
||||
|
|
|
@ -4,6 +4,7 @@ using BITKit.UX;
|
|||
using BITKit.UX.Settings;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Net.Like.Xue.Tokyo.UX;
|
||||
using Net.Project.B.UX;
|
||||
using Project.B.Player;
|
||||
|
@ -26,6 +27,7 @@ namespace Net.Like.Xue.Tokyo
|
|||
await global::Project.B.Program.AddProjectBServices(serviceCollection,source);
|
||||
|
||||
serviceCollection.AddSingleton<IUXService, UXService>();
|
||||
serviceCollection.AddSingleton<ILogger<IUXInitialize>, UnityLogger<IUXInitialize>>();
|
||||
|
||||
serviceCollection.AddSingleton<UXRadialMenu>();
|
||||
serviceCollection.AddSingleton<UXContextMenu>();
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace Net.Like.Xue.Tokyo.UX
|
|||
|
||||
_levelContainer.Clear();
|
||||
|
||||
foreach (var gameMapData in _entitiesService.QueryComponents<ScriptableGameMapData>())
|
||||
foreach (var gameMapData in _entitiesService.QueryComponents<ScriptableGameMapData>().ToArray())
|
||||
{
|
||||
var button = _levelContainer.Create<Button>();
|
||||
|
||||
|
|
|
@ -24,8 +24,8 @@
|
|||
<ui:Instance template="ux_dialogue_choose_template" name="ux_dialogue_choose_template" />
|
||||
</ui:VisualElement>
|
||||
<ui:VisualElement name="comic-container" class="root" style="background-color: rgba(0, 0, 0, 0.67); display: none;" />
|
||||
<ui:ScrollView picking-mode="Ignore" name="dialogue-container" horizontal-scroller-visibility="Hidden" vertical-scroller-visibility="Hidden" class="flex-center dialogue-container" style="min-width: 512px; bottom: -25%; max-height: 300px; padding-top: 16px; padding-right: 32px; padding-bottom: 16px; padding-left: 32px; border-top-left-radius: 8px; border-top-right-radius: 8px; border-bottom-right-radius: 8px; border-bottom-left-radius: 8px; max-width: 768px; background-color: rgb(239, 239, 239);">
|
||||
<ui:VisualElement name="dialogue-container" picking-mode="Ignore" style="position: absolute; left: 0; right: 0; bottom: 0; min-height: 128px; align-items: center; justify-content: center; background-image: url("project://database/Assets/BITKit/Unity/Art/Backgrounds/BG_Gradient_Half_BT_.png?fileID=21300000&guid=d19ac049792985540825b54b0b002529&type=3#BG_Gradient_Half_BT_"); -unity-background-image-tint-color: rgb(0, 0, 0);">
|
||||
<ui:Instance template="ux_dialogue_template" name="ux_dialogue_template" />
|
||||
<ui:Instance template="ux_dialogue_template" name="ux_dialogue_template" />
|
||||
</ui:ScrollView>
|
||||
</ui:VisualElement>
|
||||
</ui:UXML>
|
||||
|
|
|
@ -120,7 +120,7 @@ GameObject:
|
|||
- component: {fileID: 2768128531421549133}
|
||||
- component: {fileID: 543792417896382739}
|
||||
- component: {fileID: 155117670096915963}
|
||||
- component: {fileID: 3910482476716799981}
|
||||
- component: {fileID: 6952296513455952381}
|
||||
m_Layer: 0
|
||||
m_Name: Door_into
|
||||
m_TagString: Untagged
|
||||
|
@ -247,25 +247,23 @@ MonoBehaviour:
|
|||
m_Script: {fileID: 11500000, guid: 054d7fc7589c04d4a8412a6f82b32d6c, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
worldNodeService:
|
||||
rid: 2091307956764147762
|
||||
worldNode:
|
||||
rid: 2091307956764147763
|
||||
references:
|
||||
version: 2
|
||||
RefIds:
|
||||
- rid: 2091307956764147762
|
||||
type: {class: WorldNodeService, ns: BITKit.WorldNode, asm: BITKit.WorldNode}
|
||||
data:
|
||||
- rid: 2091307956764147763
|
||||
type: {class: UnityDoorNode, ns: Net.Project.B.WorldNode, asm: Net.Project.B.WorldNode}
|
||||
data:
|
||||
State: 0
|
||||
InteractionType: 0
|
||||
IsDoubleSwing: 0
|
||||
DoorTransform: {fileID: 0}
|
||||
OpenPosition: {x: 0, y: 0, z: 0}
|
||||
ClosePosition: {x: 0, y: 0, z: 0}
|
||||
OpenEulerAngles: {x: 0, y: -130, z: 0}
|
||||
CloseEulerAngles: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &3910482476716799981
|
||||
--- !u!114 &6952296513455952381
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
|
@ -274,14 +272,6 @@ MonoBehaviour:
|
|||
m_GameObject: {fileID: 7158368870209922743}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: db48a34ef668447439789f37091202ae, type: 3}
|
||||
m_Script: {fileID: 11500000, guid: 230e015069b45484f9c85d1aba1e901c, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
root: {fileID: 0}
|
||||
type:
|
||||
rid: -2
|
||||
references:
|
||||
version: 2
|
||||
RefIds:
|
||||
- rid: -2
|
||||
type: {class: , ns: , asm: }
|
||||
|
|
|
@ -46,7 +46,7 @@ GameObject:
|
|||
- component: {fileID: 672689658587241719}
|
||||
- component: {fileID: 5447911508180368965}
|
||||
- component: {fileID: 3051974059932780283}
|
||||
- component: {fileID: 4981852654128749101}
|
||||
- component: {fileID: 8571751102882834292}
|
||||
m_Layer: 0
|
||||
m_Name: bathroom_stall_door
|
||||
m_TagString: Untagged
|
||||
|
@ -171,25 +171,23 @@ MonoBehaviour:
|
|||
m_Script: {fileID: 11500000, guid: 054d7fc7589c04d4a8412a6f82b32d6c, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
worldNodeService:
|
||||
rid: 2091307956764147997
|
||||
worldNode:
|
||||
rid: 2091307956764148006
|
||||
references:
|
||||
version: 2
|
||||
RefIds:
|
||||
- rid: 2091307956764147997
|
||||
type: {class: WorldNodeService, ns: BITKit.WorldNode, asm: BITKit.WorldNode}
|
||||
data:
|
||||
- rid: 2091307956764148006
|
||||
type: {class: UnityDoorNode, ns: Net.Project.B.WorldNode, asm: Net.Project.B.WorldNode}
|
||||
data:
|
||||
State: 0
|
||||
InteractionType: 0
|
||||
IsDoubleSwing: 0
|
||||
DoorTransform: {fileID: 0}
|
||||
OpenPosition: {x: 0, y: 0, z: 0}
|
||||
ClosePosition: {x: 0, y: 0, z: 0}
|
||||
OpenEulerAngles: {x: 0, y: -95, z: 0}
|
||||
CloseEulerAngles: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &4981852654128749101
|
||||
--- !u!114 &8571751102882834292
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
|
@ -198,17 +196,9 @@ MonoBehaviour:
|
|||
m_GameObject: {fileID: 5116359717230829548}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: db48a34ef668447439789f37091202ae, type: 3}
|
||||
m_Script: {fileID: 11500000, guid: 230e015069b45484f9c85d1aba1e901c, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
root: {fileID: 0}
|
||||
type:
|
||||
rid: -2
|
||||
references:
|
||||
version: 2
|
||||
RefIds:
|
||||
- rid: -2
|
||||
type: {class: , ns: , asm: }
|
||||
--- !u!1 &5968141520449823935
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
|
|
@ -487,8 +487,8 @@ GameObject:
|
|||
- component: {fileID: 7818755487502105268}
|
||||
- component: {fileID: 6565591625926741997}
|
||||
- component: {fileID: 3903722726346411355}
|
||||
- component: {fileID: 7850791539630329601}
|
||||
- component: {fileID: 6467428601299859334}
|
||||
- component: {fileID: 3612612946052493959}
|
||||
m_Layer: 0
|
||||
m_Name: door
|
||||
m_TagString: Untagged
|
||||
|
@ -583,26 +583,6 @@ BoxCollider:
|
|||
serializedVersion: 3
|
||||
m_Size: {x: 0.8555361, y: 2.1814704, z: 0.04242524}
|
||||
m_Center: {x: 0.42519653, y: 1.0907464, z: 0.011998258}
|
||||
--- !u!114 &7850791539630329601
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1983624427771257316}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: db48a34ef668447439789f37091202ae, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
root: {fileID: 0}
|
||||
type:
|
||||
rid: -2
|
||||
references:
|
||||
version: 2
|
||||
RefIds:
|
||||
- rid: -2
|
||||
type: {class: , ns: , asm: }
|
||||
--- !u!114 &6467428601299859334
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
|
@ -615,24 +595,34 @@ MonoBehaviour:
|
|||
m_Script: {fileID: 11500000, guid: 054d7fc7589c04d4a8412a6f82b32d6c, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
worldNodeService:
|
||||
rid: 2091307956764148349
|
||||
worldNode:
|
||||
rid: 2091307956764148350
|
||||
references:
|
||||
version: 2
|
||||
RefIds:
|
||||
- rid: 2091307956764148349
|
||||
type: {class: WorldNodeService, ns: BITKit.WorldNode, asm: BITKit.WorldNode}
|
||||
data:
|
||||
- rid: 2091307956764148350
|
||||
type: {class: UnityDoorNode, ns: Net.Project.B.WorldNode, asm: Net.Project.B.WorldNode}
|
||||
data:
|
||||
State: 0
|
||||
InteractionType: 0
|
||||
IsDoubleSwing: 0
|
||||
DoorTransform: {fileID: 0}
|
||||
OpenPosition: {x: 0, y: 0, z: 0}
|
||||
ClosePosition: {x: 0, y: 0, z: 0}
|
||||
OpenEulerAngles: {x: 0, y: -146.117, z: 0}
|
||||
CloseEulerAngles: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &3612612946052493959
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1983624427771257316}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 230e015069b45484f9c85d1aba1e901c, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
--- !u!1 &2808515620288770340
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
|
|
@ -14,7 +14,6 @@ GameObject:
|
|||
- component: {fileID: 6882496406062716677}
|
||||
- component: {fileID: 8728660391319503135}
|
||||
- component: {fileID: 8259535070200094537}
|
||||
- component: {fileID: 6768904110236230067}
|
||||
- component: {fileID: 2417275751680684476}
|
||||
m_Layer: 0
|
||||
m_Name: turnstile
|
||||
|
@ -151,31 +150,12 @@ MonoBehaviour:
|
|||
data:
|
||||
State: 0
|
||||
InteractionType: 6
|
||||
IsDoubleSwing: 0
|
||||
DoorTransform: {fileID: 4218687044597356771}
|
||||
OpenPosition: {x: 0, y: 0.82074326, z: 0}
|
||||
ClosePosition: {x: 0, y: 0.82074326, z: 0}
|
||||
OpenEulerAngles: {x: 0, y: 90, z: 0}
|
||||
CloseEulerAngles: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &6768904110236230067
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1070295965451434600}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: db48a34ef668447439789f37091202ae, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
root: {fileID: 0}
|
||||
type:
|
||||
rid: -2
|
||||
references:
|
||||
version: 2
|
||||
RefIds:
|
||||
- rid: -2
|
||||
type: {class: , ns: , asm: }
|
||||
--- !u!114 &2417275751680684476
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
|
|
|
@ -1216,7 +1216,8 @@ PrefabInstance:
|
|||
propertyPath: m_LocalEulerAnglesHint.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
m_RemovedComponents: []
|
||||
m_RemovedComponents:
|
||||
- {fileID: 0}
|
||||
m_RemovedGameObjects: []
|
||||
m_AddedGameObjects: []
|
||||
m_AddedComponents: []
|
||||
|
@ -15430,10 +15431,6 @@ PrefabInstance:
|
|||
serializedVersion: 3
|
||||
m_TransformParent: {fileID: 2119821103}
|
||||
m_Modifications:
|
||||
- target: {fileID: 3065127462969329239, guid: ca1d1c8019fd1dd4a9632c50505fd7d2, type: 3}
|
||||
propertyPath: m_RootOrder
|
||||
value: 464
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 3065127462969329239, guid: ca1d1c8019fd1dd4a9632c50505fd7d2, type: 3}
|
||||
propertyPath: m_LocalPosition.x
|
||||
value: -3.802002
|
||||
|
@ -24606,7 +24603,6 @@ GameObject:
|
|||
- component: {fileID: 997149599}
|
||||
- component: {fileID: 997149598}
|
||||
- component: {fileID: 997149600}
|
||||
- component: {fileID: 997149601}
|
||||
- component: {fileID: 997149602}
|
||||
m_Layer: 6
|
||||
m_Name: "Dialog_\u5165\u5883\u68C0\u67E5"
|
||||
|
@ -24711,25 +24707,6 @@ MonoBehaviour:
|
|||
allowAdd: 1
|
||||
allowRemove: 1
|
||||
initialItems: []
|
||||
--- !u!114 &997149601
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 997149596}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: db48a34ef668447439789f37091202ae, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
type:
|
||||
rid: -2
|
||||
references:
|
||||
version: 2
|
||||
RefIds:
|
||||
- rid: -2
|
||||
type: {class: , ns: , asm: }
|
||||
--- !u!114 &997149602
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
|
@ -29744,7 +29721,8 @@ PrefabInstance:
|
|||
propertyPath: m_LocalEulerAnglesHint.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
m_RemovedComponents: []
|
||||
m_RemovedComponents:
|
||||
- {fileID: 0}
|
||||
m_RemovedGameObjects: []
|
||||
m_AddedGameObjects: []
|
||||
m_AddedComponents: []
|
||||
|
@ -31313,7 +31291,8 @@ PrefabInstance:
|
|||
propertyPath: m_LocalEulerAnglesHint.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
m_RemovedComponents: []
|
||||
m_RemovedComponents:
|
||||
- {fileID: 0}
|
||||
m_RemovedGameObjects: []
|
||||
m_AddedGameObjects: []
|
||||
m_AddedComponents: []
|
||||
|
@ -31814,7 +31793,8 @@ PrefabInstance:
|
|||
propertyPath: m_LocalEulerAnglesHint.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
m_RemovedComponents: []
|
||||
m_RemovedComponents:
|
||||
- {fileID: 0}
|
||||
m_RemovedGameObjects: []
|
||||
m_AddedGameObjects: []
|
||||
m_AddedComponents: []
|
||||
|
@ -33196,7 +33176,8 @@ PrefabInstance:
|
|||
propertyPath: m_LocalEulerAnglesHint.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
m_RemovedComponents: []
|
||||
m_RemovedComponents:
|
||||
- {fileID: 0}
|
||||
m_RemovedGameObjects: []
|
||||
m_AddedGameObjects: []
|
||||
m_AddedComponents: []
|
||||
|
@ -53310,7 +53291,8 @@ PrefabInstance:
|
|||
propertyPath: m_LocalEulerAnglesHint.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
m_RemovedComponents: []
|
||||
m_RemovedComponents:
|
||||
- {fileID: 0}
|
||||
m_RemovedGameObjects: []
|
||||
m_AddedGameObjects: []
|
||||
m_AddedComponents: []
|
||||
|
@ -53664,7 +53646,8 @@ PrefabInstance:
|
|||
propertyPath: m_LocalEulerAnglesHint.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
m_RemovedComponents: []
|
||||
m_RemovedComponents:
|
||||
- {fileID: 0}
|
||||
m_RemovedGameObjects: []
|
||||
m_AddedGameObjects: []
|
||||
m_AddedComponents: []
|
||||
|
@ -55537,10 +55520,6 @@ PrefabInstance:
|
|||
serializedVersion: 3
|
||||
m_TransformParent: {fileID: 2119821103}
|
||||
m_Modifications:
|
||||
- target: {fileID: 1387476619567384428, guid: 87fe4b4ce2a2dd9408e4370fa61afa52, type: 3}
|
||||
propertyPath: m_RootOrder
|
||||
value: 462
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 1387476619567384428, guid: 87fe4b4ce2a2dd9408e4370fa61afa52, type: 3}
|
||||
propertyPath: m_LocalPosition.x
|
||||
value: -3.0470047
|
||||
|
@ -57859,7 +57838,8 @@ PrefabInstance:
|
|||
propertyPath: m_LocalEulerAnglesHint.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
m_RemovedComponents: []
|
||||
m_RemovedComponents:
|
||||
- {fileID: 0}
|
||||
m_RemovedGameObjects: []
|
||||
m_AddedGameObjects: []
|
||||
m_AddedComponents: []
|
||||
|
|
|
@ -831463,7 +831463,7 @@ MonoBehaviour:
|
|||
m_PreserveMeshAssetOnDestroy: 0
|
||||
assetGuid:
|
||||
m_Mesh: {fileID: 1386274396}
|
||||
m_VersionIndex: 917
|
||||
m_VersionIndex: 923
|
||||
m_IsSelectable: 1
|
||||
m_SelectedFaces:
|
||||
m_SelectedEdges: []
|
||||
|
|
|
@ -26,7 +26,7 @@ RenderSettings:
|
|||
m_AmbientIntensity: 0.73
|
||||
m_AmbientMode: 0
|
||||
m_SubtractiveShadowColor: {r: 0.35417888, g: 0.45028526, b: 0.9308176, a: 1}
|
||||
m_SkyboxMaterial: {fileID: 2100000, guid: 1a8130968946512468b2ef495b8023bd, type: 2}
|
||||
m_SkyboxMaterial: {fileID: 2100000, guid: 097a5e6e5584dae47b9d289d3d0c2081, type: 2}
|
||||
m_HaloStrength: 0.5
|
||||
m_FlareStrength: 1
|
||||
m_FlareFadeSpeed: 3
|
||||
|
@ -9834,134 +9834,6 @@ GameObject:
|
|||
m_CorrespondingSourceObject: {fileID: 6930776766761356102, guid: 4b8e722b1d534124fab002c65922b79d, type: 3}
|
||||
m_PrefabInstance: {fileID: 160728285}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
--- !u!1 &165109071
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 165109074}
|
||||
- component: {fileID: 165109073}
|
||||
- component: {fileID: 165109072}
|
||||
m_Layer: 0
|
||||
m_Name: minimap_camera
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!114 &165109072
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 165109071}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: a79441f348de89743a2939f4d699eac1, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_RenderShadows: 1
|
||||
m_RequiresDepthTextureOption: 2
|
||||
m_RequiresOpaqueTextureOption: 2
|
||||
m_CameraType: 0
|
||||
m_Cameras: []
|
||||
m_RendererIndex: -1
|
||||
m_VolumeLayerMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 1
|
||||
m_VolumeTrigger: {fileID: 0}
|
||||
m_VolumeFrameworkUpdateModeOption: 1
|
||||
m_RenderPostProcessing: 0
|
||||
m_Antialiasing: 0
|
||||
m_AntialiasingQuality: 2
|
||||
m_StopNaN: 0
|
||||
m_Dithering: 0
|
||||
m_ClearDepth: 1
|
||||
m_AllowXRRendering: 1
|
||||
m_AllowHDROutput: 1
|
||||
m_UseScreenCoordOverride: 0
|
||||
m_ScreenSizeOverride: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_ScreenCoordScaleBias: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_RequiresDepthTexture: 0
|
||||
m_RequiresColorTexture: 0
|
||||
m_Version: 2
|
||||
m_TaaSettings:
|
||||
m_Quality: 3
|
||||
m_FrameInfluence: 0.1
|
||||
m_JitterScale: 1
|
||||
m_MipBias: 0
|
||||
m_VarianceClampScale: 0.9
|
||||
m_ContrastAdaptiveSharpening: 0
|
||||
--- !u!20 &165109073
|
||||
Camera:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 165109071}
|
||||
m_Enabled: 1
|
||||
serializedVersion: 2
|
||||
m_ClearFlags: 2
|
||||
m_BackGroundColor: {r: 0.3921569, g: 0.38431376, b: 0.37647063, a: 0}
|
||||
m_projectionMatrixMode: 1
|
||||
m_GateFitMode: 2
|
||||
m_FOVAxisMode: 0
|
||||
m_Iso: 200
|
||||
m_ShutterSpeed: 0.005
|
||||
m_Aperture: 16
|
||||
m_FocusDistance: 10
|
||||
m_FocalLength: 50
|
||||
m_BladeCount: 5
|
||||
m_Curvature: {x: 2, y: 11}
|
||||
m_BarrelClipping: 0.25
|
||||
m_Anamorphism: 0
|
||||
m_SensorSize: {x: 36, y: 24}
|
||||
m_LensShift: {x: 0, y: 0}
|
||||
m_NormalizedViewPortRect:
|
||||
serializedVersion: 2
|
||||
x: 0
|
||||
y: 0
|
||||
width: 1
|
||||
height: 1
|
||||
near clip plane: 0.3
|
||||
far clip plane: 1000
|
||||
field of view: 60
|
||||
orthographic: 1
|
||||
orthographic size: 64
|
||||
m_Depth: 0
|
||||
m_CullingMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 1
|
||||
m_RenderingPath: -1
|
||||
m_TargetTexture: {fileID: 8400000, guid: 9a9e60eda7295fc47907b25d62d9dd79, type: 2}
|
||||
m_TargetDisplay: 0
|
||||
m_TargetEye: 3
|
||||
m_HDR: 1
|
||||
m_AllowMSAA: 1
|
||||
m_AllowDynamicResolution: 0
|
||||
m_ForceIntoRT: 0
|
||||
m_OcclusionCulling: 1
|
||||
m_StereoConvergence: 10
|
||||
m_StereoSeparation: 0.022
|
||||
--- !u!4 &165109074
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 165109071}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0.35355338, y: 0.35355338, z: -0.1464466, w: 0.8535535}
|
||||
m_LocalPosition: {x: -72, y: 61.79, z: -18.4}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 45, y: 45, z: 0}
|
||||
--- !u!1001 &166153296
|
||||
PrefabInstance:
|
||||
m_ObjectHideFlags: 0
|
||||
|
@ -33241,6 +33113,7 @@ GameObject:
|
|||
m_Component:
|
||||
- component: {fileID: 573918679}
|
||||
- component: {fileID: 573918678}
|
||||
- component: {fileID: 573918680}
|
||||
m_Layer: 0
|
||||
m_Name: info_player_start
|
||||
m_TagString: Untagged
|
||||
|
@ -33260,16 +33133,11 @@ MonoBehaviour:
|
|||
m_Script: {fileID: 11500000, guid: 054d7fc7589c04d4a8412a6f82b32d6c, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
worldNodeService:
|
||||
rid: 550035120411901952
|
||||
worldNode:
|
||||
rid: 550035120411901953
|
||||
references:
|
||||
version: 2
|
||||
RefIds:
|
||||
- rid: 550035120411901952
|
||||
type: {class: WorldNodeService, ns: BITKit.WorldNode, asm: BITKit.WorldNode}
|
||||
data:
|
||||
- rid: 550035120411901953
|
||||
type: {class: WorldInfoPlayerStart, ns: BITKit.WorldNode, asm: BITKit.WorldNode}
|
||||
data:
|
||||
|
@ -33288,6 +33156,18 @@ Transform:
|
|||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &573918680
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 573918677}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 230e015069b45484f9c85d1aba1e901c, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
--- !u!1001 &573994322
|
||||
PrefabInstance:
|
||||
m_ObjectHideFlags: 0
|
||||
|
@ -43272,8 +43152,8 @@ Light:
|
|||
serializedVersion: 10
|
||||
m_Type: 1
|
||||
m_Shape: 0
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_Intensity: 0.5
|
||||
m_Color: {r: 0.08199832, g: 0.10084592, b: 0.3018868, a: 0}
|
||||
m_Intensity: 0
|
||||
m_Range: 10
|
||||
m_SpotAngle: 30
|
||||
m_InnerSpotAngle: 21.80208
|
||||
|
@ -43331,12 +43211,12 @@ Transform:
|
|||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 739831700}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: -0.16261207, y: 0.9078989, z: -0.3858497, w: -0.019924013}
|
||||
m_LocalRotation: {x: 0.9848078, y: 0, z: 0, w: 0.17364824}
|
||||
m_LocalPosition: {x: -24.03235, y: 7.067, z: 126.68066}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1370539313}
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 45, y: -1267.256, z: -23.318}
|
||||
--- !u!114 &739831703
|
||||
MonoBehaviour:
|
||||
|
@ -112964,8 +112844,7 @@ MonoBehaviour:
|
|||
sources:
|
||||
- {fileID: 1370539313}
|
||||
- {fileID: 983876297}
|
||||
minimapCamera: {fileID: 165109073}
|
||||
allowCulling: 1
|
||||
allowCulling: 0
|
||||
--- !u!1001 &983906136
|
||||
PrefabInstance:
|
||||
m_ObjectHideFlags: 0
|
||||
|
@ -134897,8 +134776,6 @@ Transform:
|
|||
- {fileID: 1627010135}
|
||||
- {fileID: 134655476}
|
||||
- {fileID: 446406516}
|
||||
- {fileID: 1918141543}
|
||||
- {fileID: 739831702}
|
||||
- {fileID: 991626444}
|
||||
- {fileID: 1625446444}
|
||||
- {fileID: 257274406}
|
||||
|
@ -141955,6 +141832,54 @@ GameObject:
|
|||
m_CorrespondingSourceObject: {fileID: 6670758144064960994, guid: ad59fe36454ec3242a145c2b90aca8da, type: 3}
|
||||
m_PrefabInstance: {fileID: 1463338394}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
--- !u!1 &1467199912
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1467199914}
|
||||
- component: {fileID: 1467199913}
|
||||
m_Layer: 0
|
||||
m_Name: TimeOfDaysController
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!114 &1467199913
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1467199912}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5cc5ff230f5ab58468b15e270e924eb9, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
todGlobalParameters: {fileID: 11400000, guid: 4a62b45a7aae0bc419854bb8e5a934b5, type: 2}
|
||||
MainLight: {fileID: 1918141542}
|
||||
LensFlare: {fileID: 0}
|
||||
isTimeFlow: 0
|
||||
--- !u!4 &1467199914
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1467199912}
|
||||
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: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1001 &1467531986
|
||||
PrefabInstance:
|
||||
m_ObjectHideFlags: 0
|
||||
|
@ -149006,6 +148931,67 @@ GameObject:
|
|||
m_CorrespondingSourceObject: {fileID: 7219182003715457656, guid: 25f43441d35cf9f4e8a71514ee06f7c5, type: 3}
|
||||
m_PrefabInstance: {fileID: 1587351041}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
--- !u!1001 &1591477169
|
||||
PrefabInstance:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 2
|
||||
m_Modification:
|
||||
serializedVersion: 3
|
||||
m_TransformParent: {fileID: 0}
|
||||
m_Modifications:
|
||||
- target: {fileID: 641277380591036102, guid: 98352849c75d3674198e1053c3cda8ab, type: 3}
|
||||
propertyPath: orthographic size
|
||||
value: 88.4
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2363770275507355875, guid: 98352849c75d3674198e1053c3cda8ab, type: 3}
|
||||
propertyPath: m_Name
|
||||
value: node_minimap_camera
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 5630170439344028599, guid: 98352849c75d3674198e1053c3cda8ab, type: 3}
|
||||
propertyPath: m_LocalPosition.x
|
||||
value: -44.1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 5630170439344028599, guid: 98352849c75d3674198e1053c3cda8ab, type: 3}
|
||||
propertyPath: m_LocalPosition.y
|
||||
value: 64
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 5630170439344028599, guid: 98352849c75d3674198e1053c3cda8ab, type: 3}
|
||||
propertyPath: m_LocalPosition.z
|
||||
value: 15.6
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 5630170439344028599, guid: 98352849c75d3674198e1053c3cda8ab, type: 3}
|
||||
propertyPath: m_LocalRotation.w
|
||||
value: 0.7071068
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 5630170439344028599, guid: 98352849c75d3674198e1053c3cda8ab, type: 3}
|
||||
propertyPath: m_LocalRotation.x
|
||||
value: 0.7071068
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 5630170439344028599, guid: 98352849c75d3674198e1053c3cda8ab, type: 3}
|
||||
propertyPath: m_LocalRotation.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 5630170439344028599, guid: 98352849c75d3674198e1053c3cda8ab, type: 3}
|
||||
propertyPath: m_LocalRotation.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 5630170439344028599, guid: 98352849c75d3674198e1053c3cda8ab, type: 3}
|
||||
propertyPath: m_LocalEulerAnglesHint.x
|
||||
value: 90
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 5630170439344028599, guid: 98352849c75d3674198e1053c3cda8ab, type: 3}
|
||||
propertyPath: m_LocalEulerAnglesHint.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 5630170439344028599, guid: 98352849c75d3674198e1053c3cda8ab, type: 3}
|
||||
propertyPath: m_LocalEulerAnglesHint.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
m_RemovedComponents: []
|
||||
m_RemovedGameObjects: []
|
||||
m_AddedGameObjects: []
|
||||
m_AddedComponents: []
|
||||
m_SourcePrefab: {fileID: 100100000, guid: 98352849c75d3674198e1053c3cda8ab, type: 3}
|
||||
--- !u!1001 &1595363822
|
||||
PrefabInstance:
|
||||
m_ObjectHideFlags: 0
|
||||
|
@ -166300,8 +166286,8 @@ Light:
|
|||
serializedVersion: 10
|
||||
m_Type: 1
|
||||
m_Shape: 0
|
||||
m_Color: {r: 1, g: 0.5954333, b: 0.15408784, a: 1}
|
||||
m_Intensity: 2
|
||||
m_Color: {r: 0.59622675, g: 0.17803897, b: 0.029666651, a: 0.13960838}
|
||||
m_Intensity: 1.0000038
|
||||
m_Range: 10
|
||||
m_SpotAngle: 30
|
||||
m_InnerSpotAngle: 21.80208
|
||||
|
@ -166359,12 +166345,12 @@ Transform:
|
|||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1918141541}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0.11295298, y: -0.87966466, z: 0.45643884, w: 0.07138252}
|
||||
m_LocalRotation: {x: 0.9832549, y: 0, z: 0, w: 0.18223552}
|
||||
m_LocalPosition: {x: -13.302677, y: 9.037246, z: -51.681026}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1370539313}
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 55, y: -1617.755, z: -13.465}
|
||||
--- !u!114 &1918141544
|
||||
MonoBehaviour:
|
||||
|
@ -178669,8 +178655,11 @@ GameObject:
|
|||
SceneRoots:
|
||||
m_ObjectHideFlags: 0
|
||||
m_Roots:
|
||||
- {fileID: 739831702}
|
||||
- {fileID: 1918141543}
|
||||
- {fileID: 1370539313}
|
||||
- {fileID: 983876297}
|
||||
- {fileID: 483500788}
|
||||
- {fileID: 165109074}
|
||||
- {fileID: 573918679}
|
||||
- {fileID: 1467199914}
|
||||
- {fileID: 1591477169}
|
||||
|
|
|
@ -37,6 +37,14 @@ MonoBehaviour:
|
|||
FilterRuleName: CollectAll
|
||||
AssetTags:
|
||||
UserData:
|
||||
- CollectPath: Assets/Artists/Configs/Bullet/NewScriptableBulletServiceData.asset
|
||||
CollectorGUID: b01808c2576581442ad1ccfa22043c5e
|
||||
CollectorType: 0
|
||||
AddressRuleName: AddressByFileName
|
||||
PackRuleName: PackDirectory
|
||||
FilterRuleName: CollectAll
|
||||
AssetTags: scriptable_object
|
||||
UserData:
|
||||
- GroupName: Prefab
|
||||
GroupDesc:
|
||||
AssetTags:
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.AccessControl;
|
||||
using System.Threading;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
@ -10,51 +12,77 @@ using Microsoft.Extensions.Logging;
|
|||
|
||||
namespace BITKit.Entities
|
||||
{
|
||||
public class EntitiesService:IEntitiesService,IDisposable
|
||||
public class EntitiesService : IEntitiesService, IDisposable
|
||||
{
|
||||
private static int _count;
|
||||
|
||||
|
||||
private readonly ILogger<EntitiesService> _logger;
|
||||
private readonly IFixedTicker _ticker;
|
||||
private static int _count;
|
||||
private static readonly ConcurrentQueue<IEntity> OnAddQueue = new();
|
||||
|
||||
private readonly ConcurrentQueue<IEntity> _onAddQueue = new();
|
||||
private readonly ConcurrentDictionary<int, HashSet<int>> _typeCaches = new();
|
||||
|
||||
public EntitiesService(ILogger<EntitiesService> logger, IFixedTicker ticker)
|
||||
{
|
||||
_count++;
|
||||
|
||||
_logger = logger;
|
||||
_ticker = ticker;
|
||||
|
||||
|
||||
_count++;
|
||||
|
||||
|
||||
logger.LogInformation($"已创建EntitiesService,当前有:{_count}个实例");
|
||||
|
||||
_ticker.Add(OnTick);
|
||||
}
|
||||
|
||||
private void OnTick(float obj)
|
||||
{
|
||||
while (OnAddQueue.TryDequeue(out var entity))
|
||||
while (_onAddQueue.TryDequeue(out var entity))
|
||||
{
|
||||
OnAdd?.Invoke(entity);
|
||||
|
||||
foreach (var serviceDescriptor in entity.ServiceCollection)
|
||||
{
|
||||
var typeHash = serviceDescriptor.ServiceType.GetHashCode();
|
||||
var hashSet = _typeCaches.GetOrCreate(typeHash);
|
||||
hashSet.Add(entity.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private static readonly ConcurrentDictionary<int, IEntity> Entities = new();
|
||||
public event Action<IEntity> OnAdd;
|
||||
public event Action<IEntity> OnRemove;
|
||||
IReadOnlyDictionary<int, IEntity> IEntitiesService.Entities => Entities;
|
||||
|
||||
public bool Register(IEntity entity)
|
||||
{
|
||||
if (!Entities.TryAdd(entity.Id, entity)) return false;
|
||||
OnAddQueue.Enqueue(entity);
|
||||
_onAddQueue.Enqueue(entity);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool UnRegister(IEntity entity)
|
||||
{
|
||||
if (!Entities.TryRemove(entity.Id, out _)) return false;
|
||||
OnRemove?.Invoke(entity);
|
||||
OnRemove?.Invoke(entity);
|
||||
|
||||
foreach (var serviceDescriptor in entity.ServiceCollection)
|
||||
{
|
||||
var typeHash = serviceDescriptor.ServiceType.GetHashCode();
|
||||
var hashSet = _typeCaches.GetOrCreate(typeHash);
|
||||
hashSet.Remove(entity.Id);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public CancellationToken CancellationToken => _cancellationTokenSource.Token;
|
||||
private readonly CancellationTokenSource _cancellationTokenSource = new();
|
||||
|
||||
public IEntity Get(int id)
|
||||
{
|
||||
return Entities[id];
|
||||
|
@ -70,194 +98,247 @@ namespace BITKit.Entities
|
|||
return Entities.GetOrAdd(id, factory);
|
||||
}
|
||||
|
||||
public IEntity[] Query<T>()
|
||||
public Span<T> QueryComponents<T>()
|
||||
{
|
||||
throw new NotImplementedException("Obsoleted");
|
||||
}
|
||||
var pool = ArrayPool<T>.Shared;
|
||||
var hashset = _typeCaches.GetOrCreate(typeof(T).GetHashCode());
|
||||
|
||||
public T[] QueryComponents<T>()
|
||||
{
|
||||
var list = new List<T>();
|
||||
foreach (var entity in Entities.Values)
|
||||
var count = hashset.Count;
|
||||
var array = pool.Rent(count); // ✅ 从池中获取数组,避免 GC
|
||||
|
||||
var i = 0;
|
||||
foreach (var id in hashset)
|
||||
{
|
||||
if (entity.ServiceProvider.GetService<T>() is { } t1)
|
||||
{
|
||||
list.Add(t1);
|
||||
}
|
||||
array[i] = Entities[id].ServiceProvider.GetRequiredService<T>();
|
||||
i++;
|
||||
}
|
||||
|
||||
return list.ToArray();
|
||||
// return _queryCache.GetOrAdd(typeof(T), type =>
|
||||
// {
|
||||
// return _entities.Values.Where(entity => entity.TryGetComponent(out T component)).ToArray();
|
||||
// }).Cast<T>().ToArray();
|
||||
// 🚀 使用 `GCHandle` 固定数组,防止被 GC 移动
|
||||
var handle = GCHandle.Alloc(array, GCHandleType.Pinned);
|
||||
try
|
||||
{
|
||||
return new Span<T>(array, 0, count); // ✅ 返回 `Span<T>`,无额外拷贝
|
||||
}
|
||||
finally
|
||||
{
|
||||
handle.Free(); // ✅ 释放 `GCHandle`,防止内存泄漏
|
||||
pool.Return(array); // ✅ 归还 ArrayPool
|
||||
}
|
||||
}
|
||||
|
||||
public (T, T1)[] QueryComponents<T, T1>()
|
||||
{
|
||||
var list = new List<(T, T1)>();
|
||||
foreach (var entity in Entities.Values)
|
||||
{
|
||||
if (entity.ServiceProvider.GetService<T>() is { } t1 &&
|
||||
entity.ServiceProvider.GetService<T1>() is { } t2)
|
||||
{
|
||||
list.Add((t1, t2));
|
||||
}
|
||||
}
|
||||
|
||||
return list.ToArray();
|
||||
// List<(T, T1)> list = new();
|
||||
// foreach (var entity in _entities.Values)
|
||||
// {
|
||||
// if (entity.TryGetComponent(out T t) && entity.TryGetComponent(out T1 t1))
|
||||
// list.Add((t, t1));
|
||||
// }
|
||||
// return list.ToArray();
|
||||
}
|
||||
public (T, T1, T2)[] QueryComponents<T, T1, T2>()
|
||||
{
|
||||
var list = new List<(T, T1, T2)>();
|
||||
foreach (var entity in Entities.Values)
|
||||
{
|
||||
if (entity.ServiceProvider.GetService<T>() is { } t1 &&
|
||||
entity.ServiceProvider.GetService<T1>() is { } t2 &&
|
||||
entity.ServiceProvider.GetService<T2>() is { } t3)
|
||||
{
|
||||
list.Add((t1, t2, t3));
|
||||
}
|
||||
}
|
||||
|
||||
return list.ToArray();
|
||||
// List<(T, T1, T2)> list = new();
|
||||
// foreach (var entity in _entities.Values)
|
||||
// {
|
||||
// if (entity.TryGetComponent(out T t) && entity.TryGetComponent(out T1 t1) && entity.TryGetComponent(out T2 t2))
|
||||
// list.Add((t, t1, t2));
|
||||
// }
|
||||
// return list.ToArray();
|
||||
}
|
||||
|
||||
public (T, T1, T2, T3)[] QueryComponents<T, T1, T2, T3>()
|
||||
public Span<(T, T1)> QueryComponents<T, T1>()
|
||||
{
|
||||
var list = new List<(T, T1, T2, T3)>();
|
||||
foreach (var entity in Entities.Values)
|
||||
{
|
||||
if (entity.ServiceProvider.GetService<T>() is { } t1 &&
|
||||
entity.ServiceProvider.GetService<T1>() is { } t2 &&
|
||||
entity.ServiceProvider.GetService<T2>() is { } t3 &&
|
||||
entity.ServiceProvider.GetService<T3>() is { } t4)
|
||||
{
|
||||
list.Add((t1, t2, t3, t4));
|
||||
}
|
||||
}
|
||||
|
||||
return list.ToArray();
|
||||
// List<(T, T1, T2, T3)> list = new();
|
||||
// foreach (var entity in _entities.Values)
|
||||
// {
|
||||
// if (entity.TryGetComponent(out T t) && entity.TryGetComponent(out T1 t1) && entity.TryGetComponent(out T2 t2) && entity.TryGetComponent(out T3 t3))
|
||||
// list.Add((t, t1, t2, t3));
|
||||
// }
|
||||
// return list.ToArray();
|
||||
}
|
||||
var pool = ArrayPool<(T, T1)>.Shared;
|
||||
var hashset = _typeCaches.GetOrCreate(typeof(T).GetHashCode());
|
||||
var t1Set = _typeCaches.GetOrCreate(typeof(T1).GetHashCode());
|
||||
|
||||
public (T, T1, T2, T3, T4)[] QueryComponents<T, T1, T2, T3, T4>()
|
||||
{
|
||||
var list = new List<(T, T1, T2, T3, T4)>();
|
||||
foreach (var entity in Entities.Values)
|
||||
{
|
||||
if (entity.ServiceProvider.GetService<T>() is { } t1 &&
|
||||
entity.ServiceProvider.GetService<T1>() is { } t2 &&
|
||||
entity.ServiceProvider.GetService<T2>() is { } t3 &&
|
||||
entity.ServiceProvider.GetService<T3>() is { } t4 &&
|
||||
entity.ServiceProvider.GetService<T4>() is { } t5)
|
||||
{
|
||||
list.Add((t1, t2, t3, t4, t5));
|
||||
}
|
||||
}
|
||||
|
||||
return list.ToArray();
|
||||
// List<(T, T1, T2, T3, T4)> list = new();
|
||||
// foreach (var entity in _entities.Values)
|
||||
// {
|
||||
// if (entity.TryGetComponent(out T t) && entity.TryGetComponent(out T1 t1) && entity.TryGetComponent(out T2 t2) && entity.TryGetComponent(out T3 t3) && entity.TryGetComponent(out T4 t4))
|
||||
// list.Add((t, t1, t2, t3, t4));
|
||||
// }
|
||||
// return list.ToArray();
|
||||
}
|
||||
var count = hashset.Count;
|
||||
var array = pool.Rent(count);
|
||||
|
||||
public (T, T1, T2, T3, T4, T5)[] QueryComponents<T, T1, T2, T3, T4, T5>()
|
||||
{
|
||||
var list = new List<(T, T1, T2, T3, T4, T5)>();
|
||||
foreach (var entity in Entities.Values)
|
||||
var i = 0;
|
||||
foreach (var id in hashset.Intersect(t1Set))
|
||||
{
|
||||
if (entity.ServiceProvider.GetService<T>() is { } t1 &&
|
||||
entity.ServiceProvider.GetService<T1>() is { } t2 &&
|
||||
entity.ServiceProvider.GetService<T2>() is { } t3 &&
|
||||
entity.ServiceProvider.GetService<T3>() is { } t4 &&
|
||||
entity.ServiceProvider.GetService<T4>() is { } t5 &&
|
||||
entity.ServiceProvider.GetService<T5>() is { } t6)
|
||||
{
|
||||
list.Add((t1, t2, t3, t4, t5, t6));
|
||||
}
|
||||
}
|
||||
|
||||
return list.ToArray();
|
||||
// List<(T, T1, T2, T3, T4, T5)> list = new();
|
||||
// foreach (var entity in _entities.Values)
|
||||
// {
|
||||
// if (entity.TryGetComponent(out T t) && entity.TryGetComponent(out T1 t1) && entity.TryGetComponent(out T2 t2) && entity.TryGetComponent(out T3 t3) && entity.TryGetComponent(out T4 t4) && entity.TryGetComponent(out T5 t5))
|
||||
// list.Add((t, t1, t2, t3, t4, t5));
|
||||
// }
|
||||
// return list.ToArray();
|
||||
}
|
||||
|
||||
public (T, T1, T2, T3, T4, T5, T6)[] QueryComponents<T, T1, T2, T3, T4, T5, T6>()
|
||||
{
|
||||
var list = new List<(T, T1, T2, T3, T4, T5, T6)>();
|
||||
foreach (var entity in Entities.Values)
|
||||
{
|
||||
if (entity.ServiceProvider.GetService<T>() is { } t1 &&
|
||||
entity.ServiceProvider.GetService<T1>() is { } t2 &&
|
||||
entity.ServiceProvider.GetService<T2>() is { } t3 &&
|
||||
entity.ServiceProvider.GetService<T3>() is { } t4 &&
|
||||
entity.ServiceProvider.GetService<T4>() is { } t5 &&
|
||||
entity.ServiceProvider.GetService<T5>() is { } t6 &&
|
||||
entity.ServiceProvider.GetService<T6>() is { } t7)
|
||||
{
|
||||
list.Add((t1, t2, t3, t4, t5, t6, t7));
|
||||
}
|
||||
var entity = Entities[id];
|
||||
array[i] = (entity.ServiceProvider.GetRequiredService<T>(),
|
||||
entity.ServiceProvider.GetRequiredService<T1>());
|
||||
i++;
|
||||
}
|
||||
|
||||
return list.ToArray();
|
||||
// List<(T, T1, T2, T3, T4, T5, T6)> list = new();
|
||||
// foreach (var entity in _entities.Values)
|
||||
// {
|
||||
// if (entity.TryGetComponent(out T t) && entity.TryGetComponent(out T1 t1) && entity.TryGetComponent(out T2 t2) && entity.TryGetComponent(out T3 t3) && entity.TryGetComponent(out T4 t4) && entity.TryGetComponent(out T5 t5) && entity.TryGetComponent(out T6 t6))
|
||||
// list.Add((t, t1, t2, t3, t4, t5, t6));
|
||||
// }
|
||||
// return list.ToArray();
|
||||
var handle = GCHandle.Alloc(array, GCHandleType.Pinned);
|
||||
try
|
||||
{
|
||||
return new Span<(T, T1)>(array, 0, count);
|
||||
}
|
||||
finally
|
||||
{
|
||||
handle.Free();
|
||||
pool.Return(array);
|
||||
}
|
||||
}
|
||||
|
||||
public ValueTuple<T, T1, T2, T3, T4, T5, T6, TRest>[] QueryComponents<T, T1, T2, T3, T4, T5, T6, TRest>()
|
||||
where TRest : struct
|
||||
public Span<(T, T1, T2)> QueryComponents<T, T1, T2>()
|
||||
{
|
||||
var list = new List<ValueTuple<T, T1, T2, T3, T4, T5, T6, TRest>>();
|
||||
foreach (var entity in Entities.Values)
|
||||
var pool = ArrayPool<(T, T1, T2)>.Shared;
|
||||
var hashset = _typeCaches.GetOrCreate(typeof(T).GetHashCode());
|
||||
var t1Set = _typeCaches.GetOrCreate(typeof(T1).GetHashCode());
|
||||
var t2Set = _typeCaches.GetOrCreate(typeof(T2).GetHashCode());
|
||||
|
||||
var count = hashset.Count;
|
||||
var array = pool.Rent(count);
|
||||
|
||||
var i = 0;
|
||||
foreach (var id in hashset.Intersect(t1Set).Intersect(t2Set))
|
||||
{
|
||||
if (entity.ServiceProvider.GetService<T>() is { } t1 &&
|
||||
entity.ServiceProvider.GetService<T1>() is { } t2 &&
|
||||
entity.ServiceProvider.GetService<T2>() is { } t3 &&
|
||||
entity.ServiceProvider.GetService<T3>() is { } t4 &&
|
||||
entity.ServiceProvider.GetService<T4>() is { } t5 &&
|
||||
entity.ServiceProvider.GetService<T5>() is { } t6 &&
|
||||
entity.ServiceProvider.GetService<T6>() is { } t7 &&
|
||||
entity.ServiceProvider.GetService<TRest>() is { } t8)
|
||||
{
|
||||
list.Add(new ValueTuple<T, T1, T2, T3, T4, T5, T6, TRest>(t1, t2, t3, t4, t5, t6, t7, t8));
|
||||
}
|
||||
var entity = Entities[id];
|
||||
array[i] = (entity.ServiceProvider.GetRequiredService<T>(),
|
||||
entity.ServiceProvider.GetRequiredService<T1>(),
|
||||
entity.ServiceProvider.GetRequiredService<T2>());
|
||||
i++;
|
||||
}
|
||||
|
||||
var handle = GCHandle.Alloc(array, GCHandleType.Pinned);
|
||||
try
|
||||
{
|
||||
return new Span<(T, T1, T2)>(array, 0, count);
|
||||
}
|
||||
finally
|
||||
{
|
||||
handle.Free();
|
||||
pool.Return(array);
|
||||
}
|
||||
}
|
||||
|
||||
public Span<(T, T1, T2, T3)> QueryComponents<T, T1, T2, T3>()
|
||||
{
|
||||
var pool = ArrayPool<(T, T1, T2, T3)>.Shared;
|
||||
var hashset = _typeCaches.GetOrCreate(typeof(T).GetHashCode());
|
||||
var t1Set = _typeCaches.GetOrCreate(typeof(T1).GetHashCode());
|
||||
var t2Set = _typeCaches.GetOrCreate(typeof(T2).GetHashCode());
|
||||
var t3Set = _typeCaches.GetOrCreate(typeof(T3).GetHashCode());
|
||||
|
||||
var count = hashset.Count;
|
||||
var array = pool.Rent(count);
|
||||
|
||||
var i = 0;
|
||||
foreach (var id in hashset.Intersect(t1Set).Intersect(t2Set).Intersect(t3Set))
|
||||
{
|
||||
var entity = Entities[id];
|
||||
array[i] = (entity.ServiceProvider.GetRequiredService<T>(),
|
||||
entity.ServiceProvider.GetRequiredService<T1>(),
|
||||
entity.ServiceProvider.GetRequiredService<T2>(),
|
||||
entity.ServiceProvider.GetRequiredService<T3>());
|
||||
i++;
|
||||
}
|
||||
|
||||
var handle = GCHandle.Alloc(array, GCHandleType.Pinned);
|
||||
try
|
||||
{
|
||||
return new Span<(T, T1, T2, T3)>(array, 0, count);
|
||||
}
|
||||
finally
|
||||
{
|
||||
handle.Free();
|
||||
pool.Return(array);
|
||||
}
|
||||
}
|
||||
|
||||
public Span<(T, T1, T2, T3, T4)> QueryComponents<T, T1, T2, T3, T4>()
|
||||
{
|
||||
var pool = ArrayPool<(T, T1, T2, T3, T4)>.Shared;
|
||||
var hashset = _typeCaches.GetOrCreate(typeof(T).GetHashCode());
|
||||
var t1Set = _typeCaches.GetOrCreate(typeof(T1).GetHashCode());
|
||||
var t2Set = _typeCaches.GetOrCreate(typeof(T2).GetHashCode());
|
||||
var t3Set = _typeCaches.GetOrCreate(typeof(T3).GetHashCode());
|
||||
var t4Set = _typeCaches.GetOrCreate(typeof(T4).GetHashCode());
|
||||
|
||||
var count = hashset.Count;
|
||||
var array = pool.Rent(count);
|
||||
|
||||
var i = 0;
|
||||
foreach (var id in hashset.Intersect(t1Set).Intersect(t2Set).Intersect(t3Set).Intersect(t4Set))
|
||||
{
|
||||
var entity = Entities[id];
|
||||
array[i] = (entity.ServiceProvider.GetRequiredService<T>(),
|
||||
entity.ServiceProvider.GetRequiredService<T1>(),
|
||||
entity.ServiceProvider.GetRequiredService<T2>(),
|
||||
entity.ServiceProvider.GetRequiredService<T3>(),
|
||||
entity.ServiceProvider.GetRequiredService<T4>());
|
||||
i++;
|
||||
}
|
||||
|
||||
var handle = GCHandle.Alloc(array, GCHandleType.Pinned);
|
||||
try
|
||||
{
|
||||
return new Span<(T, T1, T2, T3, T4)>(array, 0, count);
|
||||
}
|
||||
finally
|
||||
{
|
||||
handle.Free();
|
||||
pool.Return(array);
|
||||
}
|
||||
}
|
||||
|
||||
public Span<(T, T1, T2, T3, T4, T5)> QueryComponents<T, T1, T2, T3, T4, T5>()
|
||||
{
|
||||
var pool = ArrayPool<(T, T1, T2, T3, T4, T5)>.Shared;
|
||||
var hashset = _typeCaches.GetOrCreate(typeof(T).GetHashCode());
|
||||
var t1Set = _typeCaches.GetOrCreate(typeof(T1).GetHashCode());
|
||||
var t2Set = _typeCaches.GetOrCreate(typeof(T2).GetHashCode());
|
||||
var t3Set = _typeCaches.GetOrCreate(typeof(T3).GetHashCode());
|
||||
var t4Set = _typeCaches.GetOrCreate(typeof(T4).GetHashCode());
|
||||
var t5Set = _typeCaches.GetOrCreate(typeof(T5).GetHashCode());
|
||||
|
||||
var count = hashset.Count;
|
||||
var array = pool.Rent(count);
|
||||
|
||||
var i = 0;
|
||||
foreach (var id in hashset.Intersect(t1Set).Intersect(t2Set).Intersect(t3Set).Intersect(t4Set)
|
||||
.Intersect(t5Set))
|
||||
{
|
||||
var entity = Entities[id];
|
||||
array[i] = (entity.ServiceProvider.GetRequiredService<T>(),
|
||||
entity.ServiceProvider.GetRequiredService<T1>(),
|
||||
entity.ServiceProvider.GetRequiredService<T2>(),
|
||||
entity.ServiceProvider.GetRequiredService<T3>(),
|
||||
entity.ServiceProvider.GetRequiredService<T4>(),
|
||||
entity.ServiceProvider.GetRequiredService<T5>()
|
||||
);
|
||||
i++;
|
||||
}
|
||||
|
||||
var handle = GCHandle.Alloc(array, GCHandleType.Pinned);
|
||||
try
|
||||
{
|
||||
return new Span<(T, T1, T2, T3, T4, T5)>(array, 0, count);
|
||||
}
|
||||
finally
|
||||
{
|
||||
handle.Free();
|
||||
pool.Return(array);
|
||||
}
|
||||
}
|
||||
|
||||
public Span<(T, T1, T2, T3, T4, T5, T6)> QueryComponents<T, T1, T2, T3, T4, T5, T6>()
|
||||
{
|
||||
var pool = ArrayPool<(T, T1, T2, T3, T4, T5, T6)>.Shared;
|
||||
var hashset = _typeCaches.GetOrCreate(typeof(T).GetHashCode());
|
||||
var t1Set = _typeCaches.GetOrCreate(typeof(T1).GetHashCode());
|
||||
var t2Set = _typeCaches.GetOrCreate(typeof(T2).GetHashCode());
|
||||
var t3Set = _typeCaches.GetOrCreate(typeof(T3).GetHashCode());
|
||||
var t4Set = _typeCaches.GetOrCreate(typeof(T4).GetHashCode());
|
||||
var t5Set = _typeCaches.GetOrCreate(typeof(T5).GetHashCode());
|
||||
var t6Set = _typeCaches.GetOrCreate(typeof(T6).GetHashCode());
|
||||
|
||||
var count = hashset.Count;
|
||||
var array = pool.Rent(count);
|
||||
|
||||
var i = 0;
|
||||
foreach (var id in hashset.Intersect(t1Set).Intersect(t2Set).Intersect(t3Set).Intersect(t4Set)
|
||||
.Intersect(t5Set).Intersect(t6Set))
|
||||
{
|
||||
var entity = Entities[id];
|
||||
array[i] = (entity.ServiceProvider.GetRequiredService<T>(),
|
||||
entity.ServiceProvider.GetRequiredService<T1>(),
|
||||
entity.ServiceProvider.GetRequiredService<T2>(),
|
||||
entity.ServiceProvider.GetRequiredService<T3>(),
|
||||
entity.ServiceProvider.GetRequiredService<T4>(),
|
||||
entity.ServiceProvider.GetRequiredService<T5>(),
|
||||
entity.ServiceProvider.GetRequiredService<T6>()
|
||||
);
|
||||
i++;
|
||||
}
|
||||
|
||||
var handle = GCHandle.Alloc(array, GCHandleType.Pinned);
|
||||
try
|
||||
{
|
||||
return new Span<(T, T1, T2, T3, T4, T5, T6)>(array, 0, count);
|
||||
}
|
||||
finally
|
||||
{
|
||||
handle.Free();
|
||||
pool.Return(array);
|
||||
}
|
||||
return list.ToArray();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
@ -267,11 +348,11 @@ namespace BITKit.Entities
|
|||
{
|
||||
Entities.Clear();
|
||||
}
|
||||
|
||||
|
||||
_logger.LogInformation($"已释放,还剩{_count}个实例");
|
||||
|
||||
|
||||
_cancellationTokenSource?.Dispose();
|
||||
|
||||
|
||||
_ticker.Remove(OnTick);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,23 +8,24 @@ namespace BITKit.Entities
|
|||
{
|
||||
public class Entity : IEntity, IDisposable
|
||||
{
|
||||
public Entity()
|
||||
{
|
||||
ServiceCollection.AddSingleton<IEntity>(this);
|
||||
}
|
||||
public void WaitForInitializationComplete()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public int Id { get; set; } = Guid.NewGuid().GetHashCode();
|
||||
public CancellationToken CancellationToken { get; set; }
|
||||
|
||||
public IServiceProvider ServiceProvider => _serviceProvider ??= ServiceCollection.BuildServiceProvider();
|
||||
private ServiceProvider _serviceProvider;
|
||||
public IServiceCollection ServiceCollection { get; } = new ServiceCollection();
|
||||
public IServiceCollection ServiceCollection
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_serviceCollection is not null) return _serviceCollection;
|
||||
_serviceCollection = new ServiceCollection();
|
||||
_serviceCollection.AddSingleton<IEntity>(this);
|
||||
return _serviceCollection;
|
||||
}
|
||||
}
|
||||
|
||||
private IServiceCollection _serviceCollection;
|
||||
|
||||
public object[] GetServices() => ServiceCollection.ToArray()
|
||||
.Select(x => _serviceProvider.GetService(x.ServiceType)).ToArray();
|
||||
public void Inject(object obj)
|
||||
{
|
||||
foreach (var fieldInfo in obj.GetType().GetFields(ReflectionHelper.Flags))
|
||||
|
|
|
@ -66,19 +66,13 @@ namespace BITKit.Entities
|
|||
/// 通过Id获取或添加Entity
|
||||
/// </summary>
|
||||
IEntity GetOrAdd(int id,Func<int,IEntity> factory);
|
||||
|
||||
/// <summary>
|
||||
/// 查询Entity,例如
|
||||
/// </summary>
|
||||
/// <para>var rotationEntities=EntitiesService.Query<RotationComponent></para>
|
||||
IEntity[] Query<T>();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 查询1个组件
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns></returns>
|
||||
T[] QueryComponents<T>();
|
||||
Span<T> QueryComponents<T>();
|
||||
|
||||
/// <summary>
|
||||
/// 查询2个组件
|
||||
|
@ -86,7 +80,7 @@ namespace BITKit.Entities
|
|||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="T1"></typeparam>
|
||||
/// <returns></returns>
|
||||
ValueTuple<T, T1>[] QueryComponents<T, T1>();
|
||||
Span<ValueTuple<T, T1>> QueryComponents<T, T1>();
|
||||
|
||||
/// <summary>
|
||||
/// 查询3个组件
|
||||
|
@ -95,7 +89,7 @@ namespace BITKit.Entities
|
|||
/// <typeparam name="T1"></typeparam>
|
||||
/// <typeparam name="T2"></typeparam>
|
||||
/// <returns></returns>
|
||||
ValueTuple<T, T1, T2>[] QueryComponents<T, T1, T2>();
|
||||
Span<ValueTuple<T, T1, T2>> QueryComponents<T, T1, T2>();
|
||||
|
||||
/// <summary>
|
||||
/// 查询4个组件
|
||||
|
@ -105,7 +99,7 @@ namespace BITKit.Entities
|
|||
/// <typeparam name="T2"></typeparam>
|
||||
/// <typeparam name="T3"></typeparam>
|
||||
/// <returns></returns>
|
||||
ValueTuple<T, T1, T2, T3>[] QueryComponents<T, T1, T2, T3>();
|
||||
Span<ValueTuple<T, T1, T2, T3>> QueryComponents<T, T1, T2, T3>();
|
||||
|
||||
/// <summary>
|
||||
/// 查询5个组件
|
||||
|
@ -116,7 +110,7 @@ namespace BITKit.Entities
|
|||
/// <typeparam name="T3"></typeparam>
|
||||
/// <typeparam name="T4"></typeparam>
|
||||
/// <returns></returns>
|
||||
ValueTuple<T, T1, T2, T3, T4>[] QueryComponents<T, T1, T2, T3, T4>();
|
||||
Span<ValueTuple<T, T1, T2, T3, T4>> QueryComponents<T, T1, T2, T3, T4>();
|
||||
/// <summary>
|
||||
/// 查询6个组件
|
||||
/// </summary>
|
||||
|
@ -127,7 +121,7 @@ namespace BITKit.Entities
|
|||
/// <typeparam name="T4"></typeparam>
|
||||
/// <typeparam name="T5"></typeparam>
|
||||
/// <returns></returns>
|
||||
ValueTuple<T, T1, T2, T3, T4, T5>[] QueryComponents<T, T1, T2, T3, T4, T5>();
|
||||
Span<ValueTuple<T, T1, T2, T3, T4, T5>> QueryComponents<T, T1, T2, T3, T4, T5>();
|
||||
|
||||
/// <summary>
|
||||
/// 查询7个组件
|
||||
|
@ -140,7 +134,7 @@ namespace BITKit.Entities
|
|||
/// <typeparam name="T5"></typeparam>
|
||||
/// <typeparam name="T6"></typeparam>
|
||||
/// <returns></returns>
|
||||
ValueTuple<T, T1, T2, T3, T4, T5, T6>[] QueryComponents<T, T1, T2, T3, T4, T5, T6>();
|
||||
Span<ValueTuple<T, T1, T2, T3, T4, T5, T6>> QueryComponents<T, T1, T2, T3, T4, T5, T6>();
|
||||
|
||||
/// <summary>
|
||||
/// 查询8个组件
|
||||
|
@ -154,6 +148,6 @@ namespace BITKit.Entities
|
|||
/// <typeparam name="T6"></typeparam>
|
||||
/// <typeparam name="TRest">剩余实例</typeparam>
|
||||
/// <returns></returns>
|
||||
ValueTuple<T, T1, T2, T3, T4, T5, T6, TRest>[] QueryComponents<T, T1, T2, T3, T4, T5, T6, TRest>() where TRest : struct;
|
||||
//Span<ValueTuple<T, T1, T2, T3, T4, T5, T6, TRest>> QueryComponents<T, T1, T2, T3, T4, T5, T6, TRest>() where TRest : struct;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c9f4b5601bd64124a9efdee9cf9c7226
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,79 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using BITKit;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Net.BITKit.Localization
|
||||
{
|
||||
public class CsvLocalizationService
|
||||
{
|
||||
public string Url { get; set; } =
|
||||
@"http://server.bitfall.icu:21982/com.project.b/net.project.b.localization.csv";
|
||||
|
||||
private readonly ILogger<CsvLocalizationService> _logger;
|
||||
private readonly ILocalizationService _localizationService;
|
||||
|
||||
public CsvLocalizationService(ILocalizationService localizationService, ILogger<CsvLocalizationService> logger)
|
||||
{
|
||||
_localizationService = localizationService;
|
||||
_logger = logger;
|
||||
|
||||
_localizationService.OnLanguageChangeAsync += OnLanguageChangeAsync;
|
||||
}
|
||||
|
||||
public static Dictionary<string, Dictionary<string, string>> ParseCsvToDictionary(string csvData)
|
||||
{
|
||||
var dict = new Dictionary<string, Dictionary<string, string>>();
|
||||
using var reader = new StringReader(csvData);
|
||||
|
||||
var headerLine = reader.ReadLine();
|
||||
if (headerLine == null) return dict;
|
||||
|
||||
var headers = headerLine.Split(',');
|
||||
|
||||
for (var i = 1; i < headers.Length; i++) // 跳过 "Key" 列
|
||||
{
|
||||
dict[headers[i]] = new Dictionary<string, string>();
|
||||
}
|
||||
|
||||
string? line;
|
||||
while ((line = reader.ReadLine()) != null)
|
||||
{
|
||||
var columns = line.Split(',');
|
||||
if (columns.Length < 2) continue;
|
||||
|
||||
var key = columns[0]; // 取 Key 值
|
||||
for (var i = 1; i < columns.Length; i++)
|
||||
{
|
||||
dict[headers[i]][key] = columns[i]; // 填充语言数据
|
||||
}
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
private async UniTask OnLanguageChangeAsync(string arg1, string arg2)
|
||||
{
|
||||
var csv = await new HttpClient().GetStringAsync(Url);
|
||||
|
||||
_logger.LogInformation($"下载完成:\n{csv}");
|
||||
|
||||
foreach (var (lang, dictionary) in ParseCsvToDictionary(csv))
|
||||
{
|
||||
if (_localizationService.LocalizedStrings.TryGetValue(lang, out var currentDictionary) is false)
|
||||
{
|
||||
currentDictionary = new Dictionary<string, string>();
|
||||
_localizationService.LocalizedStrings.Add(lang,currentDictionary);
|
||||
}
|
||||
foreach (var (key, value) in dictionary)
|
||||
{
|
||||
currentDictionary.Set(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c2048d435d8387842b5b0c9bf5498a1f
|
||||
guid: 0a0edc8f5d75b3646a7b405ef830a52d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
|
@ -0,0 +1,111 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using BITKit;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Net.BITKit.Localization
|
||||
{
|
||||
/// <summary>
|
||||
/// 本地化
|
||||
/// </summary>
|
||||
public interface ILocalizationService
|
||||
{
|
||||
public string Prefix { get; }
|
||||
/// <summary>
|
||||
/// 当前语言
|
||||
/// </summary>
|
||||
public string CurrentLanguage { get; }
|
||||
/// <summary>
|
||||
/// 更改回调,通常在此检查并下载语言包
|
||||
/// </summary>
|
||||
public event Func<string,string,UniTask> OnLanguageChangeAsync;
|
||||
/// <summary>
|
||||
/// 语言更改完成回调,UI和World执行更新
|
||||
/// </summary>
|
||||
public event Action<string,string> OnLanguageChanged;
|
||||
/// <summary>
|
||||
/// 获取翻译文本,返回无复制的引用
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="language">语言,默认为当前CultureInfo.Name</param>
|
||||
/// <returns></returns>
|
||||
public string GetLocalizedString(string key,string language=null);
|
||||
public UniTask ChangeLanguageAsync(string newLanguage);
|
||||
public IDictionary<string, IDictionary<string, string>> LocalizedStrings { get; }
|
||||
}
|
||||
|
||||
public class LocalizationService : ILocalizationService,IDisposable
|
||||
{
|
||||
private static LocalizationService _singleton;
|
||||
public string Prefix => "#";
|
||||
private char _prefix = '#';
|
||||
public string CurrentLanguage { get; private set; }
|
||||
|
||||
public event Func<string, string, UniTask> OnLanguageChangeAsync;
|
||||
public event Action<string, string> OnLanguageChanged;
|
||||
|
||||
private readonly ILogger<LocalizationService> _logger;
|
||||
|
||||
public IDictionary<string, IDictionary<string, string>> LocalizedStrings { get; } =
|
||||
new Dictionary<string, IDictionary<string, string>>();
|
||||
|
||||
private readonly ValidHandle _isBusy = new();
|
||||
|
||||
private readonly HashSet<string> _untranslatedKeys = new();
|
||||
|
||||
public LocalizationService(ILogger<LocalizationService> logger)
|
||||
{
|
||||
if (_singleton is not null)
|
||||
{
|
||||
logger.LogError("LocalizationService can only be one singleton");
|
||||
return;
|
||||
}
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
|
||||
public string GetLocalizedString(string key, string language = null)
|
||||
{
|
||||
language ??= CurrentLanguage; // 默认使用当前语言
|
||||
|
||||
if (key[0] != _prefix)
|
||||
{
|
||||
key = _prefix + key;
|
||||
}
|
||||
if (LocalizedStrings.TryGetValue(language, out var langDict) && langDict.TryGetValue(key, out var value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
_untranslatedKeys.Add(key);
|
||||
return key.Replace(Prefix,string.Empty).Replace("_"," "); // 如果找不到翻译,就返回 key 本身(常见策略)
|
||||
}
|
||||
public async UniTask ChangeLanguageAsync(string newLanguage)
|
||||
{
|
||||
if (CurrentLanguage == newLanguage) return;
|
||||
var oldLanguage = CurrentLanguage;
|
||||
CurrentLanguage = newLanguage;
|
||||
|
||||
await _isBusy;
|
||||
using var _ = _isBusy.GetHandle();
|
||||
|
||||
await UniTask.SwitchToMainThread();
|
||||
|
||||
await OnLanguageChangeAsync.UniTaskFunc(oldLanguage, newLanguage);
|
||||
|
||||
// 触发同步事件(例如更新 UI)
|
||||
OnLanguageChanged?.Invoke(oldLanguage, newLanguage);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_isBusy?.Dispose();
|
||||
_singleton = null;
|
||||
_logger.LogInformation("Untranslated keys:\n"+string.Join("\n", _untranslatedKeys));
|
||||
_untranslatedKeys.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: baab5c8590ad6ee44acbc258eeacdc8b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -9,13 +9,16 @@ namespace BITKit.Pool
|
|||
/// </summary>
|
||||
public interface IPoolService
|
||||
{
|
||||
public int DefaultCapacity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 生成对象
|
||||
/// </summary>
|
||||
/// <param name="path">可寻址路径</param>
|
||||
/// <param name="prefab">直接提供的预制体</param>
|
||||
/// <typeparam name="T">类型</typeparam>
|
||||
/// <returns></returns>
|
||||
UniTask<T> Spawn<T>(string path) where T : class;
|
||||
UniTask<T> Spawn<T>(string path,object prefab=null) where T : class;
|
||||
/// <summary>
|
||||
/// 回收对象
|
||||
/// </summary>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
|
@ -24,7 +25,6 @@ namespace BITKit.StateMachine
|
|||
|
||||
public bool Enabled { get; set; } = true;
|
||||
public T CurrentState { get;private set; }
|
||||
public T NextOrCurrentState => _nextTargetState.IfNotAllow(CurrentState);
|
||||
public event Action<T, T> OnStateChanging;
|
||||
public event Func<T, T, UniTask> OnStateChangeAsync;
|
||||
public event Action<T, T> OnStateChanged;
|
||||
|
@ -35,7 +35,13 @@ namespace BITKit.StateMachine
|
|||
public readonly ValidHandle IsBusy=new();
|
||||
private readonly CancellationTokenSource _cancellationTokenSource=new();
|
||||
private readonly Dictionary<int, T> _dictionary = new();
|
||||
private readonly Optional<T> _nextTargetState = new();
|
||||
|
||||
private readonly HashSet<int> _isRegistered = new();
|
||||
|
||||
private CancellationTokenSource _transitionCts;
|
||||
|
||||
private T _entryCompletedState;
|
||||
|
||||
public async void Initialize()
|
||||
{
|
||||
await IsBusy;
|
||||
|
@ -43,33 +49,27 @@ namespace BITKit.StateMachine
|
|||
using var _ = IsBusy.GetHandle();
|
||||
foreach (var (_,value) in StateDictionary)
|
||||
{
|
||||
await value.InitializeAsync();
|
||||
value.Initialize();
|
||||
if (_isRegistered.Add(value.Identifier))
|
||||
{
|
||||
await value.InitializeAsync();
|
||||
value.Initialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public async void UpdateState(float deltaTime)
|
||||
{
|
||||
if (CurrentState is null) return;
|
||||
if (_entryCompletedState is null) return;
|
||||
using var _ = IsBusy.GetHandle();
|
||||
CurrentState.OnStateUpdate(deltaTime);
|
||||
await CurrentState.OnStateUpdateAsync(deltaTime);
|
||||
_entryCompletedState.OnStateUpdate(deltaTime);
|
||||
await _entryCompletedState.OnStateUpdateAsync(deltaTime);
|
||||
}
|
||||
|
||||
|
||||
public async void DisposeState()
|
||||
public void DisposeState()
|
||||
{
|
||||
await IsBusy;
|
||||
if (_cancellationTokenSource.IsCancellationRequested) return;
|
||||
if (CurrentState is null) return;
|
||||
using var _ = IsBusy.GetHandle();
|
||||
CurrentState.Enabled = false;
|
||||
await CurrentState.OnStateExitAsync(CurrentState, null);
|
||||
CurrentState.OnStateExit(CurrentState, null);
|
||||
CurrentState = null;
|
||||
TransitionState(null);
|
||||
}
|
||||
|
||||
public T TransitionState<TState>() where TState : T
|
||||
{
|
||||
T nextState;
|
||||
|
@ -96,50 +96,60 @@ namespace BITKit.StateMachine
|
|||
nextState.Identifier = nextState.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
if (Equals(nextState, CurrentState)) return;
|
||||
if(_nextTargetState.Allow && Equals(_nextTargetState.Value,nextState))return;
|
||||
if (_nextTargetState.Allow)
|
||||
{
|
||||
_nextTargetState.Value = nextState;
|
||||
return;
|
||||
}
|
||||
_nextTargetState.SetValueThenAllow(nextState);
|
||||
await IsBusy;
|
||||
|
||||
if(CurrentState==nextState)return;
|
||||
if(_cancellationTokenSource.IsCancellationRequested)return;
|
||||
using var _ = IsBusy.GetHandle();
|
||||
|
||||
OnStateChanging?.Invoke(CurrentState,nextState);
|
||||
await OnStateChangeAsync.UniTaskFunc(CurrentState,nextState);
|
||||
|
||||
if (nextState is not null && _dictionary.TryAdd(nextState.Identifier, nextState))
|
||||
{
|
||||
await nextState.InitializeAsync();
|
||||
if(_cancellationTokenSource.IsCancellationRequested)return;
|
||||
nextState.Initialize();
|
||||
}
|
||||
if (CurrentState is not null)
|
||||
{
|
||||
CurrentState.Enabled = false;
|
||||
await CurrentState.OnStateExitAsync(CurrentState, nextState);
|
||||
if(_cancellationTokenSource.IsCancellationRequested)return;
|
||||
CurrentState.OnStateExit(CurrentState,nextState);
|
||||
}
|
||||
|
||||
if (_nextTargetState.Allow && _nextTargetState.Value != nextState)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var tempState = CurrentState;
|
||||
CurrentState = _nextTargetState.Value;
|
||||
_nextTargetState.Clear();
|
||||
nextState.Enabled = true;
|
||||
await nextState.OnStateEntryAsync(tempState);
|
||||
if(_cancellationTokenSource.IsCancellationRequested)return;
|
||||
nextState.OnStateEntry(tempState);
|
||||
OnStateChanged?.Invoke(tempState,nextState);
|
||||
|
||||
CurrentState = nextState;
|
||||
|
||||
_transitionCts?.Cancel();
|
||||
_transitionCts = new CancellationTokenSource();
|
||||
|
||||
var ct = _transitionCts.Token;
|
||||
|
||||
await IsBusy;
|
||||
using var _ = IsBusy.GetHandle();
|
||||
if(ct.IsCancellationRequested||_cancellationTokenSource.IsCancellationRequested)return;
|
||||
|
||||
OnStateChanging?.Invoke(tempState,nextState);
|
||||
|
||||
if (tempState is not null)
|
||||
{
|
||||
if (_entryCompletedState == tempState)
|
||||
{
|
||||
_entryCompletedState = null;
|
||||
}
|
||||
|
||||
tempState.Enabled = false;
|
||||
await tempState.OnStateExitAsync(tempState, nextState);
|
||||
tempState.OnStateExit(tempState,nextState);
|
||||
if(_cancellationTokenSource.IsCancellationRequested)return;
|
||||
}
|
||||
|
||||
if(ct.IsCancellationRequested)return;
|
||||
|
||||
await OnStateChangeAsync.UniTaskFunc(CurrentState,nextState);
|
||||
|
||||
if(ct.IsCancellationRequested)return;
|
||||
|
||||
if (nextState is not null)
|
||||
{
|
||||
if (_isRegistered.Add(nextState.Identifier))
|
||||
{
|
||||
await RegisterAsync(nextState);
|
||||
if(ct.IsCancellationRequested || _cancellationTokenSource.IsCancellationRequested)return;
|
||||
}
|
||||
|
||||
nextState.Enabled = true;
|
||||
await nextState.OnStateEntryAsync(CurrentState);
|
||||
nextState.OnStateEntry(CurrentState);
|
||||
if(ct.IsCancellationRequested || _cancellationTokenSource.IsCancellationRequested)return;
|
||||
|
||||
_entryCompletedState = nextState;
|
||||
}
|
||||
|
||||
OnStateChanged?.Invoke(tempState, nextState);
|
||||
|
||||
}
|
||||
public T TransitionState(T nextState)
|
||||
|
@ -148,27 +158,49 @@ namespace BITKit.StateMachine
|
|||
return nextState;
|
||||
}
|
||||
|
||||
private async UniTask RegisterAsync(T newState)
|
||||
{
|
||||
StateDictionary.TryAdd(newState.GetType(),newState);
|
||||
|
||||
_dictionary.TryAdd(newState.Identifier, newState);
|
||||
|
||||
|
||||
newState.Initialize();
|
||||
await newState.InitializeAsync();
|
||||
}
|
||||
|
||||
public async void Register(T newState)
|
||||
{
|
||||
await IsBusy;
|
||||
using var _ = IsBusy.GetHandle();
|
||||
await RegisterAsync(newState);
|
||||
}
|
||||
public async void UnRegister(T newState)
|
||||
{
|
||||
if (newState is null) return;
|
||||
if (Dictionary.ContainsKey(newState.Identifier) is false) return;
|
||||
_dictionary.Remove(newState.Identifier);
|
||||
|
||||
await IsBusy;
|
||||
using var _ = IsBusy.GetHandle();
|
||||
|
||||
if (Equals(CurrentState, newState))
|
||||
{
|
||||
await CurrentState.OnStateExitAsync(CurrentState, null);
|
||||
CurrentState.OnStateExit(CurrentState, null);
|
||||
if (CurrentState is IAsyncDisposable asyncDisposable)
|
||||
{
|
||||
await asyncDisposable.DisposeAsync();
|
||||
}
|
||||
if (CurrentState is IDisposable disposable)
|
||||
{
|
||||
disposable.Dispose();
|
||||
}
|
||||
|
||||
CurrentState = null;
|
||||
}
|
||||
|
||||
if (newState is IAsyncDisposable asyncDisposable)
|
||||
{
|
||||
await asyncDisposable.DisposeAsync();
|
||||
}
|
||||
if (newState is IDisposable disposable)
|
||||
{
|
||||
disposable.Dispose();
|
||||
}
|
||||
|
||||
OnStateUnRegistered?.Invoke(newState);
|
||||
}
|
||||
public void Dispose()
|
||||
|
|
|
@ -7,7 +7,6 @@ namespace BITKit.UX
|
|||
public interface IUXDialogue
|
||||
{
|
||||
void Show(string content,string title = "Alert",Action confirmAction=null,Action<bool> onChoose=null);
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -135,7 +135,9 @@ namespace BITKit
|
|||
[RuntimeInitializeOnLoadMethod]
|
||||
private static void Reload()
|
||||
{
|
||||
|
||||
BITApp.WalkUntilInitialize = new();
|
||||
|
||||
|
||||
IsPlaying = true;
|
||||
//启动BITApp
|
||||
BITApp.SynchronizationContext = SynchronizationContext.Current;
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ee77d81b8f27d6a44923a2a6901a66e0
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"name": "Net.BITKit.Impact.Unity",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:14fe60d984bf9f84eac55c6ea033a8f4",
|
||||
"GUID:89bd0da52dc3cc94daadea6252c6ad1b",
|
||||
"GUID:d525ad6bd40672747bde77962f1c401e",
|
||||
"GUID:49b49c76ee64f6b41bf28ef951cb0e50"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 24866f14213d2124aa20be037476b521
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,29 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Policy;
|
||||
using AYellowpaper.SerializedCollections;
|
||||
using BITKit;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Net.BITKit.Impact
|
||||
{
|
||||
|
||||
public class ScriptableImpact : ScriptableObject,ITag
|
||||
{
|
||||
[SerializeReference, SubclassSelector] private IReference[] tags;
|
||||
[SerializeField] private int priority;
|
||||
|
||||
[SerializeField] private Transform[] prefabs;
|
||||
[SerializeField] private AudioClip[] audioClips;
|
||||
|
||||
public int Hash { get; set; }
|
||||
public IReadOnlyCollection<string> Tags => tags.Select(x=>x.Get()).ToArray();
|
||||
|
||||
public Transform Prefab => prefabs.Random();
|
||||
public AudioClip AudioClip => audioClips.Random();
|
||||
public int Priority => priority;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ac8fd6229773587428b5dca77471e986
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -42,7 +42,9 @@ namespace BITKit.Pool
|
|||
ReadyPool.Clear();
|
||||
}
|
||||
|
||||
public async UniTask<T> Spawn<T>(string path) where T : class
|
||||
public int DefaultCapacity { get; set; } = 8;
|
||||
|
||||
public async UniTask<T> Spawn<T>(string path,object prefab) where T : class
|
||||
{
|
||||
if (Pool.ContainsKey(path))
|
||||
{
|
||||
|
@ -55,7 +57,7 @@ namespace BITKit.Pool
|
|||
return obj as T;
|
||||
}
|
||||
|
||||
if (usingList.Count>0)
|
||||
if (usingList.Count>=DefaultCapacity)
|
||||
{
|
||||
obj = usingList[0];
|
||||
usingList.RemoveAt(0);
|
||||
|
@ -81,13 +83,33 @@ namespace BITKit.Pool
|
|||
#if UNITY_5_3_OR_NEWER
|
||||
if (typeof(Object).IsAssignableFrom(typeof(T)))
|
||||
{
|
||||
var asset =await ModService.LoadAsset<T>(path);
|
||||
var asset =prefab as T ?? await ModService.LoadAsset<T>(path);
|
||||
if (asset is Object o)
|
||||
{
|
||||
var instance = Object.Instantiate(o);
|
||||
list.Add(instance);
|
||||
UsingPool.GetOrCreate(path).Add(instance);
|
||||
ReadyPool.GetOrCreate(path);
|
||||
|
||||
if (instance is GameObject gameObject)
|
||||
{
|
||||
gameObject.GetCancellationTokenOnDestroy().Register(DisposeGo);
|
||||
|
||||
void DisposeGo()
|
||||
{
|
||||
Pool.GetOrCreate(path).TryRemove(gameObject);
|
||||
UsingPool.GetOrCreate(path).TryRemove(gameObject);
|
||||
var queue = ReadyPool.GetOrCreate(path);
|
||||
var removeObjectList = new List<object>(queue);
|
||||
removeObjectList.TryRemove(gameObject);
|
||||
queue.Clear();
|
||||
foreach (var x in removeObjectList)
|
||||
{
|
||||
queue.Enqueue(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return instance as T;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class NewBehaviourScript : MonoBehaviour
|
||||
{
|
||||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c849275eb4fd266468253c3fb286f6c1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,73 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using BITKit;
|
||||
using BITKit.UX;
|
||||
using Net.BITKit.Localization;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace Net.BITKit.UX
|
||||
{
|
||||
public class UXLocalization
|
||||
{
|
||||
public string USS { get; set; } = "localized";
|
||||
private readonly IUXService _uxService;
|
||||
private readonly ILocalizationService _localizationService;
|
||||
|
||||
public UXLocalization(IUXService uxService, ILocalizationService localizationService)
|
||||
{
|
||||
_uxService = uxService;
|
||||
_localizationService = localizationService;
|
||||
|
||||
_localizationService.OnLanguageChanged += OnLanguageChanged;
|
||||
}
|
||||
|
||||
private void OnLanguageChanged(string arg1, string arg2)
|
||||
{
|
||||
if(_uxService.Root is not VisualElement visualElement)return;
|
||||
|
||||
foreach (var x in visualElement.Query<Label>(className:USS).ToList())
|
||||
{
|
||||
if (string.IsNullOrEmpty(x.viewDataKey))continue;
|
||||
x.text = _localizationService.GetLocalizedString('#'+x.viewDataKey);
|
||||
}
|
||||
|
||||
foreach (var x in visualElement.Query<Button>(className:USS).ToList())
|
||||
{
|
||||
if(string.IsNullOrEmpty(x.viewDataKey))continue;
|
||||
x.text = _localizationService.GetLocalizedString('#'+x.viewDataKey);
|
||||
}
|
||||
|
||||
foreach (var x in visualElement.Query(className:USS).ToList())
|
||||
{
|
||||
if(string.IsNullOrEmpty(x.viewDataKey))continue;
|
||||
|
||||
ContinueWithBaseType(x.GetType());
|
||||
continue;
|
||||
|
||||
void ContinueWithBaseType(Type type)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (type == null || type == typeof(object)) return;
|
||||
if (type.GetProperty("label", ReflectionHelper.Flags) is { } propertyInfo)
|
||||
{
|
||||
//Debug.Log($"{x.name}:#{x.viewDataKey}");
|
||||
propertyInfo.SetValue(x, _localizationService.GetLocalizedString('#' + x.viewDataKey));
|
||||
}
|
||||
else
|
||||
{
|
||||
type = type.BaseType;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 01963dbed2bec23468d2a4b617bdcfc5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -3,6 +3,7 @@ using System.Collections;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Net.BITKit.Localization;
|
||||
using Newtonsoft.Json;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
@ -15,11 +16,13 @@ namespace BITKit.UX.Settings
|
|||
public interface IUXSettings:IUXPanel{}
|
||||
public class UXSettings<T,TValue> : UIToolkitSubPanel<T>,IUXSettings where T: IUXPanel
|
||||
{
|
||||
private readonly ILocalizationService _localizationService;
|
||||
private readonly TValue _value;
|
||||
private readonly IWrapper<TValue> _valueWrapper;
|
||||
public UXSettings(IServiceProvider serviceProvider, IWrapper<TValue> valueWrapper) : base(serviceProvider)
|
||||
public UXSettings(IServiceProvider serviceProvider, IWrapper<TValue> valueWrapper, ILocalizationService localizationService) : base(serviceProvider)
|
||||
{
|
||||
_valueWrapper = valueWrapper;
|
||||
_localizationService = localizationService;
|
||||
_value = _valueWrapper.Value;
|
||||
}
|
||||
|
||||
|
@ -36,80 +39,98 @@ namespace BITKit.UX.Settings
|
|||
_settingsContainer.Clear();
|
||||
foreach (var propertyInfo in typeof(TValue).GetProperties())
|
||||
{
|
||||
if(propertyInfo.SetMethod is null)continue;
|
||||
var name = propertyInfo.GetDisplayName();
|
||||
var value = propertyInfo.GetValue(_valueWrapper.Value);
|
||||
switch (propertyInfo.PropertyType)
|
||||
|
||||
if (CreateVisualElement() is { } visualElement)
|
||||
{
|
||||
case var type when type == typeof(bool):
|
||||
visualElement.viewDataKey = name;
|
||||
visualElement.AddToClassList("localized");
|
||||
}
|
||||
|
||||
VisualElement CreateVisualElement()
|
||||
{
|
||||
switch (propertyInfo.PropertyType)
|
||||
{
|
||||
var checkBox = _settingsContainer.Create<Toggle>();
|
||||
checkBox.label = name;
|
||||
checkBox.SetValueWithoutNotify(value.As<bool>());
|
||||
checkBox.RegisterValueChangedCallback(x =>
|
||||
case var type when type == typeof(bool):
|
||||
{
|
||||
propertyInfo.SetValue(_value,x.newValue);
|
||||
Save();
|
||||
});
|
||||
}
|
||||
break;
|
||||
case var type when type == typeof(float):
|
||||
{
|
||||
var slider = _settingsContainer.Create<Slider>();
|
||||
slider.label = name;
|
||||
slider.showInputField = true;
|
||||
slider.showMixedValue = true;
|
||||
slider.lowValue = 1;
|
||||
slider.highValue = 100;
|
||||
slider.SetValueWithoutNotify(value.As<float>());
|
||||
slider.RegisterValueChangedCallback(x =>
|
||||
var checkBox = _settingsContainer.Create<Toggle>();
|
||||
checkBox.label = _localizationService.GetLocalizedString(name);
|
||||
checkBox.SetValueWithoutNotify(value.As<bool>());
|
||||
checkBox.RegisterValueChangedCallback(x =>
|
||||
{
|
||||
propertyInfo.SetValue(_value, x.newValue);
|
||||
Save();
|
||||
});
|
||||
return checkBox;
|
||||
}
|
||||
break;
|
||||
case var type when type == typeof(float):
|
||||
{
|
||||
propertyInfo.SetValue(_value,x.newValue);
|
||||
Save();
|
||||
});
|
||||
}
|
||||
break;
|
||||
case var type when type == typeof(int):
|
||||
{
|
||||
var slider = _settingsContainer.Create<SliderInt>();
|
||||
slider.label = name;
|
||||
slider.showInputField = true;
|
||||
slider.showMixedValue = true;
|
||||
slider.lowValue = 1;
|
||||
slider.highValue = 100;
|
||||
slider.SetValueWithoutNotify(value.As<int>());
|
||||
slider.RegisterValueChangedCallback(x =>
|
||||
var slider = _settingsContainer.Create<Slider>();
|
||||
slider.label = _localizationService.GetLocalizedString(name);
|
||||
slider.showInputField = true;
|
||||
slider.showMixedValue = true;
|
||||
slider.lowValue = 1;
|
||||
slider.highValue = 100;
|
||||
slider.SetValueWithoutNotify(value.As<float>());
|
||||
slider.RegisterValueChangedCallback(x =>
|
||||
{
|
||||
propertyInfo.SetValue(_value, x.newValue);
|
||||
Save();
|
||||
});
|
||||
return slider;
|
||||
}
|
||||
break;
|
||||
case var type when type == typeof(int):
|
||||
{
|
||||
propertyInfo.SetValue(_value,x.newValue);
|
||||
Save();
|
||||
});
|
||||
}
|
||||
break;
|
||||
case var type when type == typeof(string):
|
||||
{
|
||||
var textField = _settingsContainer.Create<TextField>();
|
||||
textField.label = name;
|
||||
textField.SetValueWithoutNotify(value.As<string>());
|
||||
textField.RegisterValueChangedCallback(x =>
|
||||
var slider = _settingsContainer.Create<SliderInt>();
|
||||
slider.label = _localizationService.GetLocalizedString(name);
|
||||
slider.showInputField = true;
|
||||
slider.showMixedValue = true;
|
||||
slider.lowValue = 1;
|
||||
slider.highValue = 100;
|
||||
slider.SetValueWithoutNotify(value.As<int>());
|
||||
slider.RegisterValueChangedCallback(x =>
|
||||
{
|
||||
propertyInfo.SetValue(_value, x.newValue);
|
||||
Save();
|
||||
});
|
||||
return slider;
|
||||
}
|
||||
break;
|
||||
case var type when type == typeof(string):
|
||||
{
|
||||
propertyInfo.SetValue(_value,x.newValue);
|
||||
Save();
|
||||
});
|
||||
}
|
||||
break;
|
||||
case var type when type.IsEnum:
|
||||
{
|
||||
var enumField = _settingsContainer.Create<EnumField>();
|
||||
enumField.label = name;
|
||||
|
||||
enumField.Init(value as Enum);
|
||||
enumField.SetValueWithoutNotify(value as Enum);
|
||||
enumField.RegisterValueChangedCallback(x =>
|
||||
var textField = _settingsContainer.Create<TextField>();
|
||||
textField.label = _localizationService.GetLocalizedString(name);
|
||||
textField.SetValueWithoutNotify(value.As<string>());
|
||||
textField.RegisterValueChangedCallback(x =>
|
||||
{
|
||||
propertyInfo.SetValue(_value, x.newValue);
|
||||
Save();
|
||||
});
|
||||
return textField;
|
||||
}
|
||||
break;
|
||||
case var type when type.IsEnum:
|
||||
{
|
||||
propertyInfo.SetValue(_value,x.newValue);
|
||||
Save();
|
||||
});
|
||||
var enumField = _settingsContainer.Create<EnumField>();
|
||||
enumField.label = _localizationService.GetLocalizedString(name);
|
||||
|
||||
enumField.Init(value as Enum);
|
||||
enumField.SetValueWithoutNotify(value as Enum);
|
||||
enumField.RegisterValueChangedCallback(x =>
|
||||
{
|
||||
propertyInfo.SetValue(_value, x.newValue);
|
||||
Save();
|
||||
});
|
||||
return enumField;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -461,6 +461,11 @@ namespace BITKit
|
|||
return true;
|
||||
}
|
||||
component = self.GetComponentInParent<T>(true);
|
||||
if (component is not null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
component = self.GetComponent<T>();
|
||||
return component is not null;
|
||||
}
|
||||
public static bool TryGetFirstOrDefault<T>(this IEnumerable<T> self, out T value)
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fdd91b53bafc0804d8d8382169b67308
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"name": "Net.Project.B.VFX.Unity",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:d525ad6bd40672747bde77962f1c401e",
|
||||
"GUID:49b49c76ee64f6b41bf28ef951cb0e50",
|
||||
"GUID:14fe60d984bf9f84eac55c6ea033a8f4",
|
||||
"GUID:24866f14213d2124aa20be037476b521"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 21442fa5e0c49e3408652e96f6565891
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,63 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BITKit;
|
||||
using BITKit.Entities;
|
||||
using Net.BITKit.Impact;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Net.BITKit.VFX
|
||||
{
|
||||
public class VFXService
|
||||
{
|
||||
private readonly IEntitiesService _entitiesService;
|
||||
private readonly IReadOnlyCollection<ScriptableImpact> _scriptableImpacts;
|
||||
|
||||
public VFXService(IEntitiesService entitiesService)
|
||||
{
|
||||
_entitiesService = entitiesService;
|
||||
_scriptableImpacts = _entitiesService.QueryComponents<ScriptableImpact>().ToArray();
|
||||
}
|
||||
|
||||
public AudioClip GetAudioClip(IReadOnlyCollection<string> tags)
|
||||
{
|
||||
var bestMatches = Search(tags);
|
||||
|
||||
return bestMatches.AudioClip;
|
||||
}
|
||||
|
||||
public Transform GetPrefab(IReadOnlyCollection<string> tags)
|
||||
{
|
||||
var bestMatches = Search(tags);
|
||||
return bestMatches.Prefab;
|
||||
}
|
||||
|
||||
private ScriptableImpact Search(IReadOnlyCollection<string> tags)
|
||||
{
|
||||
var maxPoint = 0;
|
||||
var max = new HashSet<ScriptableImpact>();
|
||||
foreach (var impact in _scriptableImpacts)
|
||||
{
|
||||
var point = impact.Tags.Intersect(tags).Count();
|
||||
if (point > maxPoint)
|
||||
{
|
||||
maxPoint = point;
|
||||
max.Clear();
|
||||
max.Add(impact);
|
||||
}else if (point == maxPoint)
|
||||
{
|
||||
max.Add(impact);
|
||||
}
|
||||
}
|
||||
|
||||
if (max.Count is 1)
|
||||
{
|
||||
return max.First();
|
||||
}
|
||||
|
||||
return max.OrderByDescending(x => x.Priority).First();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0bee817d1b196f842899232c3a28d504
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -21,10 +21,11 @@ Material:
|
|||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Billboard
|
||||
m_Shader: {fileID: -6465566751694194690, guid: fc56a447eb0944f4f9fc3b51a4913759, type: 3}
|
||||
m_Shader: {fileID: 4800000, guid: 86ce7e600deb17e429b8be445bb652f7, type: 3}
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords: []
|
||||
m_ValidKeywords:
|
||||
- SHAKEUV_ON
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
|
@ -37,6 +38,14 @@ Material:
|
|||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
- _A:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _AlphaTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _BaseMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
|
@ -45,6 +54,18 @@ Material:
|
|||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _ColorRampTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _ColorRampTexGradient:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _ColorSwapTex:
|
||||
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}
|
||||
|
@ -57,14 +78,30 @@ Material:
|
|||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DistortTex:
|
||||
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:
|
||||
- _FadeBurnTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _FadeTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _GlowTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 10904, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTexture:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
|
@ -73,14 +110,34 @@ Material:
|
|||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _NormalMap:
|
||||
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}
|
||||
- _OutlineDistortTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _OutlineTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _OverlayTex:
|
||||
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}
|
||||
- _ShineMask:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _SpecGlossMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
|
@ -99,40 +156,216 @@ Material:
|
|||
m_Offset: {x: 0, y: 0}
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- PixelSnap: 0
|
||||
- _Alpha: 1
|
||||
- _AlphaClip: 0
|
||||
- _AlphaCutoffValue: 0.25
|
||||
- _AlphaOutlineBlend: 1
|
||||
- _AlphaOutlineGlow: 5
|
||||
- _AlphaOutlineMinAlpha: 0
|
||||
- _AlphaOutlinePower: 1
|
||||
- _AlphaRoundThreshold: 0.5
|
||||
- _AlphaToMask: 0
|
||||
- _BillboardY: 0
|
||||
- _Blend: 0
|
||||
- _BlendModePreserveSpecular: 1
|
||||
- _BlurHD: 0
|
||||
- _BlurIntensity: 10
|
||||
- _Brightness: 0
|
||||
- _BumpScale: 1
|
||||
- _ChromAberrAlpha: 0.4
|
||||
- _ChromAberrAmount: 1
|
||||
- _ClearCoatMask: 0
|
||||
- _ClearCoatSmoothness: 0
|
||||
- _ClipUvDown: 0
|
||||
- _ClipUvLeft: 0
|
||||
- _ClipUvRight: 0
|
||||
- _ClipUvUp: 0
|
||||
- _ColorChangeLuminosity: 0
|
||||
- _ColorChangeTolerance: 0.25
|
||||
- _ColorChangeTolerance2: 0.25
|
||||
- _ColorChangeTolerance3: 0.25
|
||||
- _ColorRampBlend: 1
|
||||
- _ColorRampLuminosity: 0
|
||||
- _ColorRampOutline: 0
|
||||
- _ColorSwapBlend: 1
|
||||
- _ColorSwapBlueLuminosity: 0.5
|
||||
- _ColorSwapGreenLuminosity: 0.5
|
||||
- _ColorSwapRedLuminosity: 0.5
|
||||
- _Contrast: 1
|
||||
- _Cull: 2
|
||||
- _CullingOption: 0
|
||||
- _Cutoff: 0.5
|
||||
- _DetailAlbedoMapScale: 1
|
||||
- _DetailNormalMapScale: 1
|
||||
- _DistortAmount: 0.5
|
||||
- _DistortTexXSpeed: 5
|
||||
- _DistortTexYSpeed: 5
|
||||
- _DstBlend: 0
|
||||
- _DstBlendAlpha: 0
|
||||
- _EditorDrawers: 6
|
||||
- _EnableExternalAlpha: 0
|
||||
- _EnvironmentReflections: 1
|
||||
- _FadeAmount: -0.1
|
||||
- _FadeBurnGlow: 2
|
||||
- _FadeBurnTransition: 0.075
|
||||
- _FadeBurnWidth: 0.025
|
||||
- _FishEyeUvAmount: 0.35
|
||||
- _FlickerAlpha: 0
|
||||
- _FlickerFreq: 0.2
|
||||
- _FlickerPercent: 0.05
|
||||
- _GhostBlend: 1
|
||||
- _GhostColorBoost: 1
|
||||
- _GhostTransparency: 0
|
||||
- _GlitchAmount: 3
|
||||
- _GlitchSize: 1
|
||||
- _GlossMapScale: 0
|
||||
- _Glossiness: 0
|
||||
- _GlossyReflections: 0
|
||||
- _Glow: 10
|
||||
- _GlowGlobal: 1
|
||||
- _GradBlend: 1
|
||||
- _GradBoostX: 1.2
|
||||
- _GradBoostY: 1.2
|
||||
- _GradIsRadial: 0
|
||||
- _GrassManualAnim: 1
|
||||
- _GrassManualToggle: 0
|
||||
- _GrassRadialBend: 0.1
|
||||
- _GrassSpeed: 2
|
||||
- _GrassWind: 20
|
||||
- _GreyscaleBlend: 1
|
||||
- _GreyscaleLuminosity: 0
|
||||
- _GreyscaleOutline: 0
|
||||
- _HandDrawnAmount: 10
|
||||
- _HandDrawnSpeed: 5
|
||||
- _HitEffectBlend: 1
|
||||
- _HitEffectGlow: 5
|
||||
- _HologramBlend: 1
|
||||
- _HologramMaxAlpha: 0.75
|
||||
- _HologramMinAlpha: 0.1
|
||||
- _HologramStripesAmount: 0.1
|
||||
- _HologramStripesSpeed: 4.5
|
||||
- _HologramUnmodAmount: 0
|
||||
- _HsvBright: 1
|
||||
- _HsvSaturation: 1
|
||||
- _HsvShift: 180
|
||||
- _InnerOutlineAlpha: 1
|
||||
- _InnerOutlineGlow: 4
|
||||
- _InnerOutlineThickness: 1
|
||||
- _MaxXUV: 1
|
||||
- _MaxYUV: 1
|
||||
- _Metallic: 0
|
||||
- _MinXUV: 0
|
||||
- _MinYUV: 0
|
||||
- _MotionBlurAngle: 0.1
|
||||
- _MotionBlurDist: 1.25
|
||||
- _MyDstMode: 10
|
||||
- _MySrcMode: 5
|
||||
- _NegativeAmount: 1
|
||||
- _NormalStrength: 1
|
||||
- _OcclusionStrength: 1
|
||||
- _OffsetUvX: 0
|
||||
- _OffsetUvY: 0
|
||||
- _OnlyInnerOutline: 0
|
||||
- _OnlyOutline: 0
|
||||
- _OutlineAlpha: 1
|
||||
- _OutlineDistortAmount: 0.5
|
||||
- _OutlineDistortTexXSpeed: 5
|
||||
- _OutlineDistortTexYSpeed: 5
|
||||
- _OutlineGlow: 1
|
||||
- _OutlinePixelWidth: 1
|
||||
- _OutlineTexXSpeed: 10
|
||||
- _OutlineTexYSpeed: 0
|
||||
- _OutlineWidth: 0.004
|
||||
- _OverlayBlend: 1
|
||||
- _OverlayGlow: 1
|
||||
- _OverlayTextureScrollXSpeed: 0.25
|
||||
- _OverlayTextureScrollYSpeed: 0.25
|
||||
- _Parallax: 0.005
|
||||
- _PinchUvAmount: 0.35
|
||||
- _PixelateSize: 32
|
||||
- _PosterizeGamma: 0.75
|
||||
- _PosterizeNumColors: 8
|
||||
- _PosterizeOutline: 0
|
||||
- _QueueControl: 0
|
||||
- _QueueOffset: 0
|
||||
- _RadialClip: 45
|
||||
- _RadialClip2: 0
|
||||
- _RadialStartAngle: 90
|
||||
- _RandomSeed: 0
|
||||
- _ReceiveShadows: 1
|
||||
- _RectSize: 1
|
||||
- _RotateUvAmount: 0
|
||||
- _RoundWaveSpeed: 2
|
||||
- _RoundWaveStrength: 0.7
|
||||
- _ShadowAlpha: 0.5
|
||||
- _ShadowX: 0.1
|
||||
- _ShadowY: -0.05
|
||||
- _ShakeUvSpeed: 1
|
||||
- _ShakeUvX: 0
|
||||
- _ShakeUvY: 5
|
||||
- _ShineGlow: 1
|
||||
- _ShineLocation: 0.5
|
||||
- _ShineRotate: 0
|
||||
- _ShineWidth: 0.1
|
||||
- _Smoothness: 0.5
|
||||
- _SmoothnessTextureChannel: 0
|
||||
- _SpecularHighlights: 1
|
||||
- _SrcBlend: 1
|
||||
- _SrcBlendAlpha: 1
|
||||
- _Surface: 0
|
||||
- _TextureScrollXSpeed: 1
|
||||
- _TextureScrollYSpeed: 0
|
||||
- _TwistUvAmount: 1
|
||||
- _TwistUvPosX: 0.5
|
||||
- _TwistUvPosY: 0.5
|
||||
- _TwistUvRadius: 0.75
|
||||
- _WarpScale: 0.5
|
||||
- _WarpSpeed: 8
|
||||
- _WarpStrength: 0.025
|
||||
- _WaveAmount: 7
|
||||
- _WaveSpeed: 10
|
||||
- _WaveStrength: 7.5
|
||||
- _WaveX: 0
|
||||
- _WaveY: 0.5
|
||||
- _WindQuality: 0
|
||||
- _WorkflowMode: 1
|
||||
- _ZTestMode: 4
|
||||
- _ZWrite: 1
|
||||
- _ZoomUvAmount: 0.5
|
||||
m_Colors:
|
||||
- _AlphaOutlineColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _BaseColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _ColorChangeNewCol: {r: 1, g: 1, b: 0, a: 1}
|
||||
- _ColorChangeNewCol2: {r: 1, g: 1, b: 0, a: 1}
|
||||
- _ColorChangeNewCol3: {r: 1, g: 1, b: 0, a: 1}
|
||||
- _ColorChangeTarget: {r: 1, g: 0, b: 0, a: 1}
|
||||
- _ColorChangeTarget2: {r: 1, g: 0, b: 0, a: 1}
|
||||
- _ColorChangeTarget3: {r: 1, g: 0, b: 0, a: 1}
|
||||
- _ColorSwapBlue: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _ColorSwapGreen: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _ColorSwapRed: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _Distance_Fade: {r: 0, g: 4, b: 0, a: 0}
|
||||
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
- _FadeBurnColor: {r: 1, g: 1, b: 0, a: 1}
|
||||
- _Flip: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _GlowColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _GradBotLeftCol: {r: 0, g: 0, b: 1, a: 1}
|
||||
- _GradBotRightCol: {r: 0, g: 1, b: 0, a: 1}
|
||||
- _GradTopLeftCol: {r: 1, g: 0, b: 0, a: 1}
|
||||
- _GradTopRightCol: {r: 1, g: 1, b: 0, a: 1}
|
||||
- _GreyscaleTintColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _Height_Fade: {r: 0, g: 1, b: 0, a: 0}
|
||||
- _HitEffectColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _HologramStripeColor: {r: 0, g: 1, b: 1, a: 1}
|
||||
- _HueVariation: {r: 1, g: 0.5, b: 0, a: 0.1}
|
||||
- _InnerOutlineColor: {r: 1, g: 0, b: 0, a: 1}
|
||||
- _OutlineColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _OverlayColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _RGBA: {r: 1, g: 1, b: 1, a: 0.8705882}
|
||||
- _RendererColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _ShadowColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
- _ShineColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
|
||||
m_BuildTextureStacks: []
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ff3d183ed9fe89044b0695522de0cf66
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 11500000, guid: 625f186215c104763be7675aa2d941aa, type: 3}
|
|
@ -0,0 +1,23 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using BITKit.FPS;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Net.Project.B.FPS
|
||||
{
|
||||
public class ScriptableSprint3 : ScriptableObject,ISprint3
|
||||
{
|
||||
[SerializeField] private Spring3 spring3;
|
||||
|
||||
public Vector3 Value
|
||||
{
|
||||
get => spring3.Value;
|
||||
set => spring3.Value = value;
|
||||
}
|
||||
public void Tick(float deltaTime, Vector3 target)
|
||||
{
|
||||
spring3.Tick(deltaTime, target);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9ba2d7b081cfd404b8ed6d3aa19e574f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -3,9 +3,14 @@ using System.Collections;
|
|||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
namespace BITKit.FPS
|
||||
{
|
||||
{
|
||||
public interface ISprint3
|
||||
{
|
||||
public Vector3 Value { get; set; }
|
||||
void Tick(float deltaTime, Vector3 target);
|
||||
}
|
||||
[Serializable]
|
||||
public class Spring3
|
||||
public class Spring3:ISprint3
|
||||
{
|
||||
public Vector3 value = Vector2.zero;
|
||||
[SerializeField] private Vector3 dampValue = Vector2.zero;
|
||||
|
@ -21,7 +26,14 @@ namespace BITKit.FPS
|
|||
this.damp = damp;
|
||||
this.frequence = frequence;
|
||||
}
|
||||
public void Update(float deltaTime, Vector3 target)
|
||||
|
||||
public Vector3 Value
|
||||
{
|
||||
get=>value;
|
||||
set=>this.value=value;
|
||||
}
|
||||
|
||||
public void Tick(float deltaTime, Vector3 target)
|
||||
{
|
||||
value -= dampValue * deltaTime * frequence;
|
||||
dampValue = Vector3.Lerp(dampValue, value - target, deltaTime * damp);
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b7ef755b09a647042bc8ba8802d98947
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,6 @@
|
|||
[InternetShortcut]
|
||||
URL=https://discord.gg/kinemation-1027338787958816860
|
||||
IDList=
|
||||
HotKey=0
|
||||
[{000214A0-0000-0000-C000-000000000046}]
|
||||
Prop3=19,11
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1c76f699feab13d48b502cea4355d361
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3369afc4214c1d14ebe43ac059cabf3f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2476cab887f4452997180c674b7b43cd
|
||||
timeCreated: 1688991425
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f6d9117845df4a049f092765c3987cfd
|
||||
timeCreated: 1705478497
|
|
@ -0,0 +1,343 @@
|
|||
// Designed by KINEMATION, 2024.
|
||||
|
||||
using KINEMATION.MotionWarping.Editor.Widgets;
|
||||
using Kinemation.MotionWarping.Runtime.Core;
|
||||
using Kinemation.MotionWarping.Runtime.Utility;
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Vector3 = UnityEngine.Vector3;
|
||||
|
||||
namespace KINEMATION.MotionWarping.Editor.Core
|
||||
{
|
||||
[CustomEditor(typeof(MotionWarpingAsset))]
|
||||
public class MotionWarpingAssetEditor : UnityEditor.Editor
|
||||
{
|
||||
private const BindingFlags PrivateFieldBindingFlags =
|
||||
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField;
|
||||
|
||||
private const BindingFlags PublicFieldBindingFlags =
|
||||
BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetField;
|
||||
|
||||
private const BindingFlags PublicPropertyBindingFlags =
|
||||
BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty;
|
||||
|
||||
private const BindingFlags PublicMethodBindingFlags =
|
||||
BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod;
|
||||
|
||||
private static Type _animationClipEditorType;
|
||||
private static Type _avatarPreviewType;
|
||||
private static Type _timeControlType;
|
||||
|
||||
private MotionWarpingAsset _asset;
|
||||
private UnityEditor.Editor _meshEditor;
|
||||
|
||||
private float _frameSlider = 0f;
|
||||
private float _length = 0f;
|
||||
private bool _manualPlaybackOverride;
|
||||
|
||||
private WarpWindowWidget _warpWindowWidget;
|
||||
private WarpPosePreviewWidget _posePreviewer;
|
||||
|
||||
private string[] _toolbarOptions = new string[] { "Motion Warping", "Pose Preview", "Animation Settings"};
|
||||
private int _selectedTab = 0;
|
||||
|
||||
public override bool HasPreviewGUI() => true;
|
||||
|
||||
private void OnAreaModified(int areaIndex)
|
||||
{
|
||||
float warpLength = _asset.GetLength();
|
||||
|
||||
var phase = _asset.warpPhases[areaIndex];
|
||||
var size = _warpWindowWidget.GetAreaSize(areaIndex);
|
||||
|
||||
phase.startTime = (float) Math.Round(size.Item1 * warpLength, 4);
|
||||
phase.endTime = (float) Math.Round(size.Item2 * warpLength, 4);
|
||||
_asset.warpPhases[areaIndex] = phase;
|
||||
}
|
||||
|
||||
private void StopLoop()
|
||||
{
|
||||
var avatarPreview = _animationClipEditorType.GetField("m_AvatarPreview", PrivateFieldBindingFlags)?.GetValue(_meshEditor);
|
||||
if (avatarPreview == null) return;
|
||||
|
||||
var timeControl = _avatarPreviewType.GetField("timeControl", PublicFieldBindingFlags)?.GetValue(avatarPreview);
|
||||
if (timeControl == null) return;
|
||||
|
||||
var stopTime = _timeControlType.GetProperty("playing", PublicPropertyBindingFlags);
|
||||
if (stopTime == null) return;
|
||||
|
||||
stopTime.SetValue(timeControl, false);
|
||||
}
|
||||
|
||||
private void UpdatePlayback()
|
||||
{
|
||||
if (!_manualPlaybackOverride) return;
|
||||
|
||||
var avatarPreview = _animationClipEditorType.GetField("m_AvatarPreview", PrivateFieldBindingFlags)
|
||||
?.GetValue(_meshEditor);
|
||||
if (avatarPreview == null) return;
|
||||
|
||||
var timeControl = _avatarPreviewType.GetField("timeControl", PublicFieldBindingFlags)
|
||||
?.GetValue(avatarPreview);
|
||||
if (timeControl == null) return;
|
||||
|
||||
var stopTime = _timeControlType.GetField("stopTime", PublicFieldBindingFlags);
|
||||
if (stopTime == null) return;
|
||||
|
||||
stopTime.SetValue(timeControl, _length);
|
||||
|
||||
var timeProperty = _timeControlType.GetField("currentTime", PublicFieldBindingFlags);
|
||||
if (timeProperty == null) return;
|
||||
|
||||
timeProperty.SetValue(timeControl, _frameSlider);
|
||||
}
|
||||
|
||||
private void GenerateAreas()
|
||||
{
|
||||
float totalTime = _asset.GetLength();
|
||||
|
||||
if (Mathf.Approximately(totalTime, 0f)) return;
|
||||
_warpWindowWidget.ClearPhases();
|
||||
|
||||
foreach (var phase in _asset.warpPhases)
|
||||
{
|
||||
_warpWindowWidget.AddWarpPhase(phase.startTime / totalTime, phase.endTime / totalTime);
|
||||
}
|
||||
}
|
||||
|
||||
private void GeneratePhases()
|
||||
{
|
||||
float totalTime = _asset.GetLength();
|
||||
if (Mathf.Approximately(totalTime, 0f)) return;
|
||||
|
||||
_asset.warpPhases.Clear();
|
||||
|
||||
float timeStep = totalTime / _asset.phasesAmount;
|
||||
|
||||
for (int i = 0; i < _asset.phasesAmount; i++)
|
||||
{
|
||||
WarpPhase phase = new WarpPhase()
|
||||
{
|
||||
minRate = 0f,
|
||||
maxRate = 1f,
|
||||
startTime = timeStep * i,
|
||||
endTime = timeStep * i + timeStep,
|
||||
};
|
||||
|
||||
_asset.warpPhases.Add(phase);
|
||||
}
|
||||
}
|
||||
|
||||
private void ExtractCurves()
|
||||
{
|
||||
if (_asset == null || _asset.animation == null)
|
||||
{
|
||||
Debug.LogError("WarpingAsset or AnimationClip is null!");
|
||||
return;
|
||||
}
|
||||
|
||||
EditorCurveBinding[] tBindings = new EditorCurveBinding[3];
|
||||
|
||||
var curveBindings = AnimationUtility.GetCurveBindings(_asset.animation);
|
||||
foreach (var binding in curveBindings)
|
||||
{
|
||||
if (_asset.animation.isHumanMotion)
|
||||
{
|
||||
if (binding.propertyName.ToLower().Contains("roott.x"))
|
||||
{
|
||||
tBindings[0] = binding;
|
||||
}
|
||||
else if (binding.propertyName.ToLower().Contains("roott.y"))
|
||||
{
|
||||
tBindings[1] = binding;
|
||||
}
|
||||
else if (binding.propertyName.ToLower().Contains("roott.z"))
|
||||
{
|
||||
tBindings[2] = binding;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!binding.path.ToLower().EndsWith("root")) continue;
|
||||
|
||||
if (binding.propertyName.ToLower().Contains("localposition.x"))
|
||||
{
|
||||
tBindings[0] = binding;
|
||||
}
|
||||
else if (binding.propertyName.ToLower().Contains("localposition.y"))
|
||||
{
|
||||
tBindings[1] = binding;
|
||||
}
|
||||
else if (binding.propertyName.ToLower().Contains("localposition.z"))
|
||||
{
|
||||
tBindings[2] = binding;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var curves = WarpingEditorUtility.ValidateCurves(_asset, 60f, tBindings);
|
||||
|
||||
_asset.rootX = curves.X;
|
||||
_asset.rootY = curves.Y;
|
||||
_asset.rootZ = curves.Z;
|
||||
|
||||
ComputeTotalRootMotion();
|
||||
}
|
||||
|
||||
private void RenderMotionWarpingTab()
|
||||
{
|
||||
base.OnInspectorGUI();
|
||||
|
||||
if (_asset.animation == null)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Specify the animation", MessageType.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
_length = _asset.animation.length;
|
||||
|
||||
_warpWindowWidget.Render();
|
||||
|
||||
var prevSlider = _frameSlider;
|
||||
_frameSlider = _length * _warpWindowWidget.GetPlayback();
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
if (GUILayout.Button("Generate Phases"))
|
||||
{
|
||||
GeneratePhases();
|
||||
GenerateAreas();
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Extract Curves"))
|
||||
{
|
||||
ExtractCurves();
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
if (!Mathf.Approximately(prevSlider, _frameSlider) && !_manualPlaybackOverride)
|
||||
{
|
||||
_manualPlaybackOverride = true;
|
||||
StopLoop();
|
||||
}
|
||||
else
|
||||
{
|
||||
_manualPlaybackOverride = false;
|
||||
}
|
||||
|
||||
UpdatePlayback();
|
||||
}
|
||||
|
||||
private void RenderAnimationSettingsTab()
|
||||
{
|
||||
if (_meshEditor == null) return;
|
||||
_meshEditor.OnInspectorGUI();
|
||||
}
|
||||
|
||||
private void ComputeTotalRootMotion()
|
||||
{
|
||||
if (_asset.animation == null) return;
|
||||
|
||||
float sampleRate = _asset.animation.frameRate;
|
||||
if (Mathf.Approximately(sampleRate, 0f)) return;
|
||||
|
||||
for (int i = 0; i < _asset.warpPhases.Count; i++)
|
||||
{
|
||||
var phase = _asset.warpPhases[i];
|
||||
|
||||
float playback = phase.startTime;
|
||||
Vector3 lastValue = _asset.GetVectorValue(playback);
|
||||
|
||||
phase.totalRootMotion = Vector3.zero;
|
||||
|
||||
while (playback <= phase.endTime)
|
||||
{
|
||||
// Accumulate the delta.
|
||||
Vector3 value = _asset.GetVectorValue(playback);
|
||||
Vector3 delta = value - lastValue;
|
||||
|
||||
phase.totalRootMotion.x += Mathf.Abs(delta.x);
|
||||
phase.totalRootMotion.y += Mathf.Abs(delta.y);
|
||||
phase.totalRootMotion.z += Mathf.Abs(delta.z);
|
||||
|
||||
lastValue = value;
|
||||
|
||||
playback += 1f / sampleRate;
|
||||
}
|
||||
|
||||
_asset.warpPhases[i] = phase;
|
||||
}
|
||||
|
||||
EditorUtility.SetDirty(_asset);
|
||||
AssetDatabase.SaveAssets();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_asset = (target) as MotionWarpingAsset;
|
||||
|
||||
if (_asset == null)
|
||||
{
|
||||
Debug.LogError("Target MotionWarpingAsset is null!");
|
||||
return;
|
||||
}
|
||||
|
||||
_meshEditor = CreateEditor(_asset.animation);
|
||||
|
||||
_animationClipEditorType = Type.GetType("UnityEditor.AnimationClipEditor,UnityEditor");
|
||||
_avatarPreviewType = Type.GetType("UnityEditor.AvatarPreview,UnityEditor");
|
||||
_timeControlType = Type.GetType("UnityEditor.TimeControl,UnityEditor");
|
||||
|
||||
_warpWindowWidget = new WarpWindowWidget();
|
||||
_warpWindowWidget.OnAreaModified += OnAreaModified;
|
||||
|
||||
_posePreviewer = new WarpPosePreviewWidget(_asset);
|
||||
|
||||
GenerateAreas();
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
ComputeTotalRootMotion();
|
||||
|
||||
_posePreviewer.RestorePose();
|
||||
_meshEditor = null;
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
_selectedTab = GUILayout.Toolbar(_selectedTab, _toolbarOptions);
|
||||
|
||||
if (_selectedTab == 0)
|
||||
{
|
||||
RenderMotionWarpingTab();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_selectedTab == 1)
|
||||
{
|
||||
_posePreviewer?.Render();
|
||||
return;
|
||||
}
|
||||
|
||||
RenderAnimationSettingsTab();
|
||||
}
|
||||
|
||||
public override void OnPreviewGUI(Rect r, GUIStyle background)
|
||||
{
|
||||
if (_meshEditor == null || !_meshEditor.HasPreviewGUI()) return;
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
GUILayout.FlexibleSpace();
|
||||
_meshEditor.OnPreviewSettings();
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
_meshEditor.OnInteractivePreviewGUI(r, GUIStyle.none);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d0d2c068e5aa4321893ea76aa6528f17
|
||||
timeCreated: 1698238712
|
|
@ -0,0 +1,20 @@
|
|||
// Designed by KINEMATION, 2024.
|
||||
|
||||
using Kinemation.MotionWarping.Runtime.Utility;
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace KINEMATION.MotionWarping.Editor.Core
|
||||
{
|
||||
[CustomPropertyDrawer(typeof(ReadOnlyAttribute))]
|
||||
public class ReadOnlyDrawer : PropertyDrawer
|
||||
{
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
GUI.enabled = false;
|
||||
EditorGUI.PropertyField(position, property, label, true);
|
||||
GUI.enabled = true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: db7fde80939c4b2e8ae89d39d25ecb82
|
||||
timeCreated: 1696662790
|
|
@ -0,0 +1,58 @@
|
|||
// Designed by KINEMATION, 2024.
|
||||
|
||||
using Kinemation.MotionWarping.Runtime.Core;
|
||||
using Kinemation.MotionWarping.Runtime.Utility;
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace KINEMATION.MotionWarping.Editor.Core
|
||||
{
|
||||
public class WarpingEditorUtility
|
||||
{
|
||||
public static Vector3 GetVectorValue(AnimationClip clip, EditorCurveBinding[] bindings, float time)
|
||||
{
|
||||
float tX = AnimationUtility.GetEditorCurve(clip, bindings[0]).Evaluate(time);
|
||||
float tY = AnimationUtility.GetEditorCurve(clip, bindings[1]).Evaluate(time);
|
||||
float tZ = AnimationUtility.GetEditorCurve(clip, bindings[2]).Evaluate(time);
|
||||
|
||||
return new Vector3(tX, tY, tZ);
|
||||
}
|
||||
|
||||
public static WarpingCurve ValidateCurves(MotionWarpingAsset motionWarpingAsset, float sampleRate = 30f,
|
||||
EditorCurveBinding[] tBindings = null)
|
||||
{
|
||||
WarpingCurve warpingCurve = new WarpingCurve();
|
||||
if (tBindings == null) return warpingCurve;
|
||||
|
||||
warpingCurve.X = new AnimationCurve();
|
||||
warpingCurve.Y = new AnimationCurve();
|
||||
warpingCurve.Z = new AnimationCurve();
|
||||
|
||||
float playback = 0f, length = motionWarpingAsset.GetLength();
|
||||
|
||||
Vector3 refVector3 = GetVectorValue(motionWarpingAsset.animation, tBindings, playback);
|
||||
|
||||
Vector3 refT = new Vector3()
|
||||
{
|
||||
x = refVector3.x,
|
||||
y = refVector3.y,
|
||||
z = refVector3.z
|
||||
};
|
||||
|
||||
while (playback <= length)
|
||||
{
|
||||
Vector3 root = GetVectorValue(motionWarpingAsset.animation, tBindings, playback);
|
||||
Vector3 delta = root - refT;
|
||||
|
||||
warpingCurve.X.AddKey(playback, delta.x);
|
||||
warpingCurve.Y.AddKey(playback, delta.y);
|
||||
warpingCurve.Z.AddKey(playback, delta.z);
|
||||
|
||||
playback += 1f / sampleRate;
|
||||
}
|
||||
|
||||
return warpingCurve;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 85fcb84c5a6c45f98c4c9202abcd7547
|
||||
timeCreated: 1698770974
|
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
"name": "MotionWarping.Editor",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:4c36dcf6d8eeb6d44ab73ef966534b46"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [
|
||||
"Android",
|
||||
"EmbeddedLinux",
|
||||
"GameCoreScarlett",
|
||||
"GameCoreXboxOne",
|
||||
"iOS",
|
||||
"LinuxStandalone64",
|
||||
"CloudRendering",
|
||||
"Lumin",
|
||||
"macOSStandalone",
|
||||
"PS4",
|
||||
"PS5",
|
||||
"Stadia",
|
||||
"Switch",
|
||||
"tvOS",
|
||||
"WSA",
|
||||
"WebGL",
|
||||
"WindowsStandalone32",
|
||||
"WindowsStandalone64",
|
||||
"XboxOne"
|
||||
],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6ac99bb1de1ddac4fbefd00ae5306a38
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6b6288be5f59459d8b3e249b1be7ee92
|
||||
timeCreated: 1705417126
|
|
@ -0,0 +1,221 @@
|
|||
// Designed by KINEMATION, 2024.
|
||||
|
||||
using Kinemation.MotionWarping.Runtime.Core;
|
||||
using Kinemation.MotionWarping.Runtime.Utility;
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
using UnityEditor;
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations;
|
||||
using UnityEngine.Playables;
|
||||
|
||||
namespace KINEMATION.MotionWarping.Editor.Widgets
|
||||
{
|
||||
public class WarpPosePreviewWidget : IWarpWidgetInterface
|
||||
{
|
||||
private GameObject _warpTracerObject;
|
||||
private Vector3 _basePos;
|
||||
private Quaternion _baseRot;
|
||||
|
||||
private GameObject _sceneCharacter;
|
||||
private AnimationClipPlayable _previewMotion;
|
||||
private int _phaseSlider = 0;
|
||||
private bool _preview = false;
|
||||
|
||||
private WarpPoint[] _warpPoints = null;
|
||||
private Dictionary<string, (Vector3, Quaternion)> _cachedTransforms
|
||||
= new Dictionary<string, (Vector3, Quaternion)>();
|
||||
|
||||
private PlayableGraph _playableGraph;
|
||||
private MotionWarpingAsset _motionWarpingAsset;
|
||||
|
||||
public WarpPosePreviewWidget(MotionWarpingAsset asset)
|
||||
{
|
||||
_motionWarpingAsset = asset;
|
||||
}
|
||||
|
||||
private void CacheTransforms()
|
||||
{
|
||||
_cachedTransforms.Clear();
|
||||
Transform[] allChildren = _sceneCharacter.GetComponentsInChildren<Transform>();
|
||||
|
||||
foreach (Transform child in allChildren)
|
||||
{
|
||||
(Vector3, Quaternion) data;
|
||||
data.Item1 = child.localPosition;
|
||||
data.Item2 = child.localRotation;
|
||||
|
||||
_cachedTransforms[child.name] = data;
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyCachedTransforms()
|
||||
{
|
||||
if (_sceneCharacter == null) return;
|
||||
|
||||
Transform[] allChildren = _sceneCharacter.GetComponentsInChildren<Transform>();
|
||||
|
||||
foreach (Transform child in allChildren)
|
||||
{
|
||||
if (_cachedTransforms.ContainsKey(child.name))
|
||||
{
|
||||
child.localPosition = _cachedTransforms[child.name].Item1;
|
||||
child.localRotation = _cachedTransforms[child.name].Item2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RestorePose()
|
||||
{
|
||||
if (_playableGraph.IsValid())
|
||||
{
|
||||
_playableGraph.Destroy();
|
||||
}
|
||||
|
||||
if (_previewMotion.IsValid())
|
||||
{
|
||||
_previewMotion.Destroy();
|
||||
}
|
||||
|
||||
if (_preview)
|
||||
{
|
||||
ApplyCachedTransforms();
|
||||
}
|
||||
|
||||
_cachedTransforms.Clear();
|
||||
}
|
||||
|
||||
public void Render()
|
||||
{
|
||||
_sceneCharacter = (GameObject) EditorGUILayout.ObjectField("Character", _sceneCharacter,
|
||||
typeof(GameObject), true);
|
||||
|
||||
if (_sceneCharacter == null)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Missing Character Reference!", MessageType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
Animator animator = _sceneCharacter.GetComponentInChildren<Animator>();
|
||||
|
||||
if (animator == null)
|
||||
{
|
||||
EditorGUILayout.HelpBox("No Animator Found!", MessageType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
_warpTracerObject = (GameObject) EditorGUILayout.ObjectField("Source", _warpTracerObject,
|
||||
typeof(GameObject), true);
|
||||
|
||||
if (_warpTracerObject == null)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Select Warp Tracer game object.", MessageType.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
AnimationPlayableOutput playableOutput;
|
||||
|
||||
if (GUILayout.Button("Play"))
|
||||
{
|
||||
CacheTransforms();
|
||||
|
||||
_playableGraph = PlayableGraph.Create("WarpPosePreviewGraph");
|
||||
|
||||
playableOutput = AnimationPlayableOutput.Create(_playableGraph, "Animation",
|
||||
animator);
|
||||
|
||||
_previewMotion = AnimationClipPlayable.Create(_playableGraph, _motionWarpingAsset.animation);
|
||||
playableOutput.SetSourcePlayable(_previewMotion);
|
||||
_preview = true;
|
||||
animator.fireEvents = false;
|
||||
animator.applyRootMotion = false;
|
||||
|
||||
if (_warpTracerObject.GetComponent<IWarpPointProvider>() is var tracer)
|
||||
{
|
||||
var result = tracer.Interact(_sceneCharacter);
|
||||
_warpPoints = result.points;
|
||||
}
|
||||
|
||||
_phaseSlider = -1;
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Stop"))
|
||||
{
|
||||
_preview = false;
|
||||
animator.Rebind();
|
||||
animator.fireEvents = true;
|
||||
animator.applyRootMotion = true;
|
||||
_phaseSlider = 0;
|
||||
|
||||
if (_playableGraph.IsValid())
|
||||
{
|
||||
_playableGraph.Stop();
|
||||
_playableGraph.Destroy();
|
||||
}
|
||||
|
||||
if (_previewMotion.IsValid())
|
||||
{
|
||||
_previewMotion.Destroy();
|
||||
}
|
||||
|
||||
ApplyCachedTransforms();
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
if (!_preview) return;
|
||||
|
||||
if (_warpPoints == null || _warpPoints.Length != _motionWarpingAsset.warpPhases.Count)
|
||||
{
|
||||
string msg = "MotionWarping: WarpObject points are null or size does not match!";
|
||||
EditorGUILayout.HelpBox(msg, MessageType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
int max = _motionWarpingAsset.warpPhases.Count - 1;
|
||||
|
||||
int prevSlider = _phaseSlider;
|
||||
_phaseSlider = EditorGUILayout.IntSlider("Phase", _phaseSlider, 0, max);
|
||||
|
||||
if (_previewMotion.IsValid())
|
||||
{
|
||||
float time = _motionWarpingAsset.warpPhases[_phaseSlider].endTime;
|
||||
_previewMotion.SetTime(time);
|
||||
}
|
||||
|
||||
var phase = _motionWarpingAsset.warpPhases[_phaseSlider];
|
||||
|
||||
if (prevSlider != _phaseSlider)
|
||||
{
|
||||
_playableGraph.Evaluate();
|
||||
|
||||
_sceneCharacter.transform.position = _warpPoints[_phaseSlider].GetPosition();
|
||||
_sceneCharacter.transform.rotation = _warpPoints[_phaseSlider].GetRotation();
|
||||
|
||||
_basePos = _sceneCharacter.transform.position;
|
||||
_baseRot = _sceneCharacter.transform.rotation;
|
||||
|
||||
var pos = _sceneCharacter.transform.TransformPoint(phase.tOffset);
|
||||
var rot = _sceneCharacter.transform.rotation * Quaternion.Euler(phase.rOffset);
|
||||
|
||||
_sceneCharacter.transform.position = pos;
|
||||
_sceneCharacter.transform.rotation = rot;
|
||||
}
|
||||
|
||||
var tDelta = _sceneCharacter.transform.position - _basePos;
|
||||
var tLocalDelta = Quaternion.Inverse(_baseRot) * tDelta;
|
||||
|
||||
var rLocalDelta = Quaternion.Inverse(_baseRot) * _sceneCharacter.transform.rotation;
|
||||
|
||||
phase.tOffset = tLocalDelta;
|
||||
phase.rOffset = rLocalDelta.eulerAngles;
|
||||
|
||||
_motionWarpingAsset.warpPhases[_phaseSlider] = phase;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a55d3fce016f48c4bb363262cf69bd3b
|
||||
timeCreated: 1699005765
|
|
@ -0,0 +1,9 @@
|
|||
// Designed by KINEMATION, 2024.
|
||||
|
||||
namespace KINEMATION.MotionWarping.Editor.Widgets
|
||||
{
|
||||
public interface IWarpWidgetInterface
|
||||
{
|
||||
public void Render();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 46f96b7c548b4e4199d76c2ee0f20d80
|
||||
timeCreated: 1699005897
|
|
@ -0,0 +1,388 @@
|
|||
// Designed by KINEMATION, 2024.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace KINEMATION.MotionWarping.Editor.Widgets
|
||||
{
|
||||
public class WarpWindowWidget : IWarpWidgetInterface
|
||||
{
|
||||
class DraggableArea
|
||||
{
|
||||
private const float MinAreaWidth = 10f;
|
||||
private const float BorderTolerance = 5f;
|
||||
private const float BorderWidth = 2f;
|
||||
|
||||
public Rect Parent;
|
||||
public float LocalStart;
|
||||
public float LocalEnd;
|
||||
|
||||
private Color _color;
|
||||
|
||||
// -2: not hovered, -1: left border, 0: body, 1: right border.
|
||||
public int GetHoveredPart(Vector2 mousePosition)
|
||||
{
|
||||
if (mousePosition.x >= GetRange().Item1 - BorderTolerance
|
||||
&& mousePosition.x <= GetRange().Item1 + BorderTolerance)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mousePosition.x >= GetRange().Item2 - BorderTolerance
|
||||
&& mousePosition.x <= GetRange().Item2 + BorderTolerance)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public DraggableArea(float start, float end, Rect parent)
|
||||
{
|
||||
LocalStart = start;
|
||||
LocalEnd = end;
|
||||
_color = new Color(0f,0.5f,0.5f);
|
||||
this.Parent = parent;
|
||||
}
|
||||
|
||||
public float GetThickness()
|
||||
{
|
||||
float worldStart = Mathf.Lerp(Parent.xMin, Parent.xMax, LocalStart);
|
||||
float worldEnd = Mathf.Lerp(Parent.xMin, Parent.xMax, LocalEnd);
|
||||
|
||||
return worldEnd - worldStart;
|
||||
}
|
||||
|
||||
public Rect GetRect()
|
||||
{
|
||||
Rect rect = Parent;
|
||||
|
||||
rect.x = GetRange().Item1;
|
||||
rect.width = GetThickness();
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
public (float, float) GetRange()
|
||||
{
|
||||
float worldStart = Mathf.LerpUnclamped(Parent.xMin, Parent.xMax, LocalStart);
|
||||
float worldEnd = Mathf.LerpUnclamped(Parent.xMin, Parent.xMax, LocalEnd);
|
||||
|
||||
return (worldStart, worldEnd);
|
||||
}
|
||||
|
||||
public float GetLocal(float value)
|
||||
{
|
||||
if (Mathf.Approximately(Parent.xMin, Parent.xMax)) return 0f;
|
||||
|
||||
return (value - Parent.xMin) / (Parent.xMax - Parent.xMin);
|
||||
}
|
||||
|
||||
public void RenderArea(float opacity)
|
||||
{
|
||||
// Draw body.
|
||||
Rect areaRect = Parent;
|
||||
areaRect.x = GetRange().Item1;
|
||||
areaRect.width = GetThickness();
|
||||
|
||||
_color.a = opacity;
|
||||
EditorGUI.DrawRect(areaRect, _color);
|
||||
|
||||
// Draw borders.
|
||||
areaRect.x -= BorderWidth / 2f;
|
||||
areaRect.width = BorderWidth;
|
||||
EditorGUI.DrawRect(areaRect, new Color(1f, 1f, 1f, opacity));
|
||||
|
||||
areaRect.x = GetRange().Item2 - BorderWidth / 2f;
|
||||
EditorGUI.DrawRect(areaRect, new Color(1f, 1f, 1f, opacity));
|
||||
}
|
||||
|
||||
public bool Contains(Vector2 checkPosition)
|
||||
{
|
||||
bool x = checkPosition.x >= GetRange().Item1 && checkPosition.x <= GetRange().Item2;
|
||||
bool y = checkPosition.y >= Parent.yMin && checkPosition.y <= Parent.yMax;
|
||||
|
||||
return x && y;
|
||||
}
|
||||
|
||||
public void Resize(float mouseDelta, int part)
|
||||
{
|
||||
// Cache the values
|
||||
float start = LocalStart;
|
||||
float end = LocalEnd;
|
||||
|
||||
float left = GetRange().Item1;
|
||||
float right = GetRange().Item2;
|
||||
|
||||
if (part == -1)
|
||||
{
|
||||
left -= part * mouseDelta;
|
||||
}
|
||||
|
||||
if (part == 0)
|
||||
{
|
||||
left += mouseDelta;
|
||||
right += mouseDelta;
|
||||
}
|
||||
|
||||
if (part == 1)
|
||||
{
|
||||
right += mouseDelta;
|
||||
}
|
||||
|
||||
LocalStart = GetLocal(left);
|
||||
LocalEnd = GetLocal(right);
|
||||
|
||||
if (GetThickness() - BorderTolerance * 2f < MinAreaWidth)
|
||||
{
|
||||
LocalStart = start;
|
||||
LocalEnd = end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public delegate void WarpWindowCallback(int modifiedArea);
|
||||
public WarpWindowCallback OnAreaModified;
|
||||
|
||||
private const float TimelineHeight = 20f;
|
||||
|
||||
private const float PlaybackTolerance = 8f;
|
||||
private const float PlaybackWidth = 2f;
|
||||
|
||||
private Rect _timelineRect;
|
||||
private List<DraggableArea> _draggableAreas = new List<DraggableArea>();
|
||||
|
||||
private DraggableArea _activeArea;
|
||||
private int _resizeAction;
|
||||
private bool _mousePressed;
|
||||
|
||||
private float _playbackPosition;
|
||||
private bool _movingPlayback;
|
||||
|
||||
private bool IsAreaColliding(float proposedPosition, int areaIndex)
|
||||
{
|
||||
int areasCount = _draggableAreas.Count;
|
||||
|
||||
if (areasCount == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int leftIndex = areaIndex - 1;
|
||||
int rightIndex = areaIndex + 1;
|
||||
|
||||
// Check left border
|
||||
var leftBorderCollision = proposedPosition <
|
||||
(leftIndex < 0 ? _timelineRect.xMin : _draggableAreas[leftIndex].GetRange().Item2);
|
||||
|
||||
// Check right border
|
||||
var rightBorderCollision = proposedPosition >
|
||||
(rightIndex > areasCount - 1
|
||||
? _timelineRect.xMax
|
||||
: _draggableAreas[rightIndex].GetRange().Item1);
|
||||
|
||||
return leftBorderCollision || rightBorderCollision;
|
||||
}
|
||||
|
||||
private void UpdateArea(int areaIndex, bool mouseAction)
|
||||
{
|
||||
Vector2 mousePosition = Event.current.mousePosition;
|
||||
Vector2 mouseDelta = Event.current.delta;
|
||||
DraggableArea area = _draggableAreas[areaIndex];
|
||||
|
||||
area.Parent = _timelineRect;
|
||||
|
||||
// Enable editing if the cursor is within the bounds.
|
||||
if (mouseAction && _mousePressed && area.Contains(mousePosition))
|
||||
{
|
||||
_activeArea = area;
|
||||
_resizeAction = area.GetHoveredPart(mousePosition);
|
||||
Event.current.Use();
|
||||
}
|
||||
|
||||
if (_activeArea != null && mouseAction && !_mousePressed)
|
||||
{
|
||||
_activeArea = null;
|
||||
_resizeAction = -2;
|
||||
Event.current.Use();
|
||||
}
|
||||
|
||||
if (_activeArea == null || area != _activeArea)
|
||||
{
|
||||
area.RenderArea(1f);
|
||||
return;
|
||||
}
|
||||
|
||||
RenderCursorIcon(area, _resizeAction);
|
||||
|
||||
if (Event.current.type == EventType.MouseDrag)
|
||||
{
|
||||
// Cache the area current size
|
||||
float areaStart = area.LocalStart;
|
||||
float areaEnd = area.LocalEnd;
|
||||
|
||||
// Resize the area
|
||||
area.Resize(mouseDelta.x, _resizeAction);
|
||||
|
||||
float start = area.GetRange().Item1;
|
||||
float end = area.GetRange().Item2;
|
||||
|
||||
bool collideLeft = IsAreaColliding(start, areaIndex);
|
||||
bool collideRight = IsAreaColliding(end, areaIndex);
|
||||
|
||||
// Check for any collisions
|
||||
if (collideLeft || collideRight)
|
||||
{
|
||||
area.LocalStart = areaStart;
|
||||
area.LocalEnd = areaEnd;
|
||||
}
|
||||
else
|
||||
{
|
||||
OnAreaModified?.Invoke(areaIndex);
|
||||
}
|
||||
|
||||
Event.current.Use();
|
||||
}
|
||||
|
||||
area.RenderArea(0.7f);
|
||||
}
|
||||
|
||||
private void RenderCursorIcon(DraggableArea area, int hoveredPart)
|
||||
{
|
||||
if (hoveredPart == 0)
|
||||
{
|
||||
EditorGUIUtility.AddCursorRect(area.GetRect(), MouseCursor.Pan);
|
||||
return;
|
||||
}
|
||||
|
||||
EditorGUIUtility.AddCursorRect(area.GetRect(), MouseCursor.SlideArrow);
|
||||
}
|
||||
|
||||
private void UpdateDraggableAreas()
|
||||
{
|
||||
bool prevMousePressed = _mousePressed;
|
||||
|
||||
if (Event.current.type == EventType.MouseDown)
|
||||
{
|
||||
_mousePressed = true;
|
||||
}
|
||||
|
||||
if (Event.current.type == EventType.MouseUp)
|
||||
{
|
||||
_mousePressed = false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _draggableAreas.Count; i++)
|
||||
{
|
||||
UpdateArea(i, prevMousePressed != _mousePressed);
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearPhases()
|
||||
{
|
||||
_draggableAreas.Clear();
|
||||
}
|
||||
|
||||
public void AddWarpPhase(float start, float end)
|
||||
{
|
||||
DraggableArea newArea = new DraggableArea(start, end, _timelineRect);
|
||||
_draggableAreas.Add(newArea);
|
||||
}
|
||||
|
||||
public (float, float) GetAreaSize(int areaIndex)
|
||||
{
|
||||
(float, float) size = (0f, 0f);
|
||||
|
||||
if (_draggableAreas.Count == 0 || areaIndex < 0 || areaIndex > _draggableAreas.Count - 1) return size;
|
||||
|
||||
var area = _draggableAreas[areaIndex];
|
||||
|
||||
size.Item1 = area.LocalStart;
|
||||
size.Item2 = area.LocalEnd;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
private void RenderPlayback(bool bAction = false)
|
||||
{
|
||||
float worldPlayback = Mathf.Lerp(_timelineRect.xMin, _timelineRect.xMax, _playbackPosition);
|
||||
var playbackRect = _timelineRect;
|
||||
playbackRect.y -= TimelineHeight;
|
||||
|
||||
Vector2 mousePosition = Event.current.mousePosition;
|
||||
|
||||
if (bAction && _mousePressed && playbackRect.Contains(mousePosition))
|
||||
{
|
||||
if (mousePosition.x >= worldPlayback - PlaybackTolerance
|
||||
&& mousePosition.x <= worldPlayback + PlaybackTolerance)
|
||||
{
|
||||
_movingPlayback = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (bAction && !_mousePressed)
|
||||
{
|
||||
_movingPlayback = false;
|
||||
}
|
||||
|
||||
if (_movingPlayback)
|
||||
{
|
||||
playbackRect.height *= 2f;
|
||||
EditorGUIUtility.AddCursorRect(playbackRect, MouseCursor.SlideArrow);
|
||||
playbackRect.height /= 2f;
|
||||
if (Event.current.type == EventType.MouseDrag)
|
||||
{
|
||||
worldPlayback += Event.current.delta.x;
|
||||
_playbackPosition = Mathf.InverseLerp(_timelineRect.xMin, _timelineRect.xMax, worldPlayback);
|
||||
Event.current.Use();
|
||||
}
|
||||
}
|
||||
|
||||
if(_activeArea != null && Event.current.shift)
|
||||
{
|
||||
if (_resizeAction is 0 or -1)
|
||||
{
|
||||
_playbackPosition = _activeArea.LocalStart;
|
||||
}
|
||||
|
||||
if (_resizeAction == 1)
|
||||
{
|
||||
_playbackPosition = _activeArea.LocalEnd;
|
||||
}
|
||||
}
|
||||
|
||||
playbackRect.x = Mathf.Lerp(_timelineRect.xMin, _timelineRect.xMax, _playbackPosition);
|
||||
playbackRect.x -= PlaybackWidth / 2f;
|
||||
playbackRect.width = PlaybackWidth;
|
||||
playbackRect.height = _timelineRect.yMax - playbackRect.y;
|
||||
|
||||
EditorGUI.DrawRect(playbackRect, Color.red);
|
||||
}
|
||||
|
||||
public float GetPlayback()
|
||||
{
|
||||
return _playbackPosition;
|
||||
}
|
||||
|
||||
public void Render()
|
||||
{
|
||||
float width = EditorGUIUtility.currentViewWidth;
|
||||
|
||||
EditorGUI.DrawRect(GUILayoutUtility.GetRect(width, TimelineHeight), new Color(0.15f, 0.15f, 0.15f));
|
||||
|
||||
var cacheRect = _timelineRect;
|
||||
_timelineRect = GUILayoutUtility.GetRect(width, TimelineHeight);
|
||||
|
||||
if (Mathf.Approximately(_timelineRect.width, 1f))
|
||||
{
|
||||
_timelineRect = cacheRect;
|
||||
}
|
||||
|
||||
EditorGUI.DrawRect(_timelineRect, new Color(0.15f, 0.15f, 0.15f));
|
||||
bool action = _mousePressed;
|
||||
UpdateDraggableAreas();
|
||||
RenderPlayback(action != _mousePressed);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fc18a424cded448f88f5c3f619a1ffe6
|
||||
timeCreated: 1698053326
|
|
@ -0,0 +1,2 @@
|
|||
[InternetShortcut]
|
||||
URL=https://github.com/kinemation/motion-warping
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9b1840bd7279c834dbf54d353cb90aea
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Binary file not shown.
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0ec45b3c964658a4d89fae90225ba634
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,2 @@
|
|||
[InternetShortcut]
|
||||
URL=https://kinemation.gitbook.io/motion-warping-for-unity
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7dbcfd4331e397f4d936c904252f120a
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8bcffe28623a91242a8a0c9aafa18e51
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1c7d9229e5994163a5595aaa1d7ee59c
|
||||
timeCreated: 1695198318
|
|
@ -0,0 +1,427 @@
|
|||
// Designed by KINEMATION, 2024.
|
||||
|
||||
using KINEMATION.MotionWarping.Runtime.Core;
|
||||
using Kinemation.MotionWarping.Runtime.Utility;
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using Debug = UnityEngine.Debug;
|
||||
using Quaternion = UnityEngine.Quaternion;
|
||||
using Vector3 = UnityEngine.Vector3;
|
||||
|
||||
namespace Kinemation.MotionWarping.Runtime.Core
|
||||
{
|
||||
public class MotionWarping : MonoBehaviour
|
||||
{
|
||||
[Header("Warping")]
|
||||
[SerializeField] private bool scalePlayRate = true;
|
||||
|
||||
[Header("Animator")]
|
||||
[SerializeField, Tooltip("Will try to play the animation.")] private bool playAnimator;
|
||||
[SerializeField, Range(0f, 1f)] private float blendTime;
|
||||
|
||||
[Header("Events")]
|
||||
public UnityEvent onWarpStarted;
|
||||
public UnityEvent onWarpEnded;
|
||||
|
||||
[SerializeField]
|
||||
private Animator animator;
|
||||
public WarpPhase[] warpPhases;
|
||||
|
||||
private Vector3 _endCurveValue;
|
||||
private Vector3 _startCurveValue;
|
||||
|
||||
private int _phaseIndex;
|
||||
|
||||
private MotionWarpingAsset _asset;
|
||||
private WarpPhase _warpPhase;
|
||||
private float _nextPhaseTime;
|
||||
|
||||
private Vector3 _originPosition;
|
||||
private Quaternion _originRotation;
|
||||
|
||||
private bool _bUpdateWarping;
|
||||
private float _warpPlayback;
|
||||
|
||||
private float _rateScale = 1f;
|
||||
private float _warpLength;
|
||||
|
||||
private Vector3 _accumRootMotion;
|
||||
private Vector3 _rootMotion;
|
||||
|
||||
private bool _hasActivePhase;
|
||||
private static readonly int WarpRate = Animator.StringToHash("WarpRate");
|
||||
|
||||
private MotionWarpingIk _motionWarpingIk;
|
||||
|
||||
|
||||
private void Start()
|
||||
{
|
||||
animator = GetComponentInChildren<Animator>();
|
||||
_motionWarpingIk = GetComponent<MotionWarpingIk>();
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
onWarpEnded = onWarpStarted = null;
|
||||
}
|
||||
|
||||
private float InvLerp(float startValue, float targetValue, float curveValue)
|
||||
{
|
||||
if (Mathf.Approximately(startValue, targetValue)) return 0f;
|
||||
|
||||
float numerator = curveValue - startValue;
|
||||
float denominator = targetValue - startValue;
|
||||
|
||||
return Mathf.Approximately(denominator, 0f) ? 0f : numerator / denominator;
|
||||
}
|
||||
|
||||
private float SafeDivide(float a, float b)
|
||||
{
|
||||
if (Mathf.Approximately(b, 0f)) return 0f;
|
||||
return a / b;
|
||||
}
|
||||
|
||||
private float GetNormalizedPlayback()
|
||||
{
|
||||
return _warpPlayback / _warpLength;
|
||||
}
|
||||
|
||||
private float GetPhaseProgress()
|
||||
{
|
||||
float alpha = InvLerp(_warpPhase.startTime, _warpPhase.endTime, _warpPlayback);
|
||||
return Mathf.Clamp01(alpha);
|
||||
}
|
||||
|
||||
private void EnterNewPhase()
|
||||
{
|
||||
_originPosition = transform.position;
|
||||
_originRotation = transform.rotation;
|
||||
|
||||
_accumRootMotion = _rootMotion = Vector3.zero;
|
||||
|
||||
_warpPhase = warpPhases[_phaseIndex];
|
||||
_nextPhaseTime = _phaseIndex == warpPhases.Length - 1 ? _warpLength : warpPhases[_phaseIndex + 1].startTime;
|
||||
_hasActivePhase = true;
|
||||
|
||||
_startCurveValue = _asset.GetVectorValue(_warpPhase.startTime);
|
||||
_endCurveValue = _asset.GetVectorValue(_warpPhase.endTime);
|
||||
|
||||
_phaseIndex++;
|
||||
|
||||
if (scalePlayRate && animator != null)
|
||||
{
|
||||
float curveVec = (_endCurveValue - _startCurveValue).magnitude;
|
||||
float realVec = (_warpPhase.Target.GetPosition() - _originPosition).magnitude;
|
||||
realVec = Mathf.Max(0.001f, realVec);
|
||||
|
||||
_rateScale = Mathf.Clamp(curveVec / realVec, _warpPhase.minRate, _warpPhase.maxRate);
|
||||
_rateScale *= _asset.playRateBasis;
|
||||
|
||||
animator.SetFloat(WarpRate, _rateScale);
|
||||
}
|
||||
else
|
||||
{
|
||||
_rateScale = 1f;
|
||||
}
|
||||
|
||||
if (_warpPhase.Target.transform != null)
|
||||
{
|
||||
_originPosition = _warpPhase.Target.transform.InverseTransformPoint(transform.position);
|
||||
_originRotation = Quaternion.Inverse(_warpPhase.Target.transform.rotation) * transform.rotation;
|
||||
}
|
||||
}
|
||||
|
||||
private void ExitCurrentPhase()
|
||||
{
|
||||
_hasActivePhase = false;
|
||||
|
||||
if (_warpPhase.Target.transform == null)
|
||||
{
|
||||
_originPosition = transform.position;
|
||||
_originRotation = transform.rotation;
|
||||
}
|
||||
else
|
||||
{
|
||||
_originPosition = _warpPhase.Target.transform.InverseTransformPoint(transform.position);
|
||||
_originRotation = Quaternion.Inverse(_warpPhase.Target.transform.rotation) * transform.rotation;
|
||||
}
|
||||
|
||||
_startCurveValue = _endCurveValue = _asset.GetVectorValue(_warpPlayback);
|
||||
}
|
||||
|
||||
private Quaternion WarpRotation()
|
||||
{
|
||||
float alpha = _hasActivePhase ? GetPhaseProgress() : 0f;
|
||||
return Quaternion.Slerp(transform.rotation, _warpPhase.Target.GetRotation(), alpha);
|
||||
}
|
||||
|
||||
private Vector3 WarpTranslation()
|
||||
{
|
||||
// 1. Compute the original additive curve value
|
||||
Vector3 prevRootMotion = _rootMotion;
|
||||
_rootMotion = _asset.GetVectorValue(_warpPlayback) - _startCurveValue;
|
||||
|
||||
if (!_hasActivePhase)
|
||||
{
|
||||
// 2. If not in the segment - play the animation itself.
|
||||
|
||||
Vector3 modifiedRootMotion = _rootMotion;
|
||||
modifiedRootMotion.x = _asset.useAnimation.x ? modifiedRootMotion.x : 0f;
|
||||
modifiedRootMotion.y = _asset.useAnimation.y ? modifiedRootMotion.y : 0f;
|
||||
modifiedRootMotion.z = _asset.useAnimation.z ? modifiedRootMotion.z : 0f;
|
||||
return modifiedRootMotion;
|
||||
}
|
||||
|
||||
// 3. Compute the target in the origin space
|
||||
Vector3 localTarget = transform.InverseTransformPoint(_warpPhase.Target.GetPosition());
|
||||
|
||||
// 4. Compute the deltas.
|
||||
Vector3 animationTarget = _endCurveValue - _startCurveValue;
|
||||
animationTarget.x = _asset.useAnimation.x ? animationTarget.x : 0f;
|
||||
animationTarget.y = _asset.useAnimation.y ? animationTarget.y : 0f;
|
||||
animationTarget.z = _asset.useAnimation.z ? animationTarget.z : 0f;
|
||||
|
||||
Vector3 targetDelta = localTarget - animationTarget;
|
||||
|
||||
Vector3 rootMotionDelta = _rootMotion - prevRootMotion;
|
||||
_accumRootMotion.x += Mathf.Abs(rootMotionDelta.x);
|
||||
_accumRootMotion.y += Mathf.Abs(rootMotionDelta.y);
|
||||
_accumRootMotion.z += Mathf.Abs(rootMotionDelta.z);
|
||||
|
||||
// 5. Finally warp the motion.
|
||||
targetDelta.x *= _asset.useLinear.x
|
||||
? GetPhaseProgress()
|
||||
: Mathf.Clamp01(SafeDivide(_accumRootMotion.x, _warpPhase.totalRootMotion.x));
|
||||
|
||||
targetDelta.y *= _asset.useLinear.y
|
||||
? GetPhaseProgress()
|
||||
: Mathf.Clamp01(SafeDivide(_accumRootMotion.y, _warpPhase.totalRootMotion.y));
|
||||
|
||||
targetDelta.z *= _asset.useLinear.z
|
||||
? GetPhaseProgress()
|
||||
: Mathf.Clamp01(SafeDivide(_accumRootMotion.z, _warpPhase.totalRootMotion.z));
|
||||
|
||||
Vector3 rootAnimation = Vector3.zero;
|
||||
rootAnimation.x = _asset.useAnimation.x ? _rootMotion.x : 0f;
|
||||
rootAnimation.y = _asset.useAnimation.y ? _rootMotion.y : 0f;
|
||||
rootAnimation.z = _asset.useAnimation.z ? _rootMotion.z : 0f;
|
||||
|
||||
return rootAnimation + targetDelta;
|
||||
}
|
||||
|
||||
private void WarpAnimation()
|
||||
{
|
||||
Vector3 cachedPosition = transform.position;
|
||||
|
||||
if (_warpPhase.Target.transform == null)
|
||||
{
|
||||
transform.position = _originPosition;
|
||||
transform.rotation = _originRotation;
|
||||
}
|
||||
else
|
||||
{
|
||||
transform.position = _warpPhase.Target.transform.TransformPoint(_originPosition);
|
||||
transform.rotation = _warpPhase.Target.transform.rotation * _originRotation;
|
||||
}
|
||||
|
||||
Vector3 warpedTranslation = WarpTranslation();
|
||||
Quaternion warpedRotation = WarpRotation();
|
||||
|
||||
warpedTranslation = transform.TransformPoint(warpedTranslation);
|
||||
|
||||
if (_asset.useCollision)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
transform.position = warpedTranslation;
|
||||
}
|
||||
|
||||
transform.rotation = warpedRotation;
|
||||
}
|
||||
|
||||
private void UpdateWarping()
|
||||
{
|
||||
if (_warpPlayback > _warpPhase.endTime && _hasActivePhase)
|
||||
{
|
||||
ExitCurrentPhase();
|
||||
}
|
||||
|
||||
if (!_hasActivePhase && _warpPlayback > _nextPhaseTime)
|
||||
{
|
||||
EnterNewPhase();
|
||||
}
|
||||
|
||||
WarpAnimation();
|
||||
|
||||
// Update playback
|
||||
_warpPlayback += Time.deltaTime * _rateScale;
|
||||
_warpPlayback = Mathf.Clamp(_warpPlayback, 0f, _warpLength);
|
||||
|
||||
if (Mathf.Approximately(GetNormalizedPlayback(), 1f))
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
if (!_bUpdateWarping) return;
|
||||
|
||||
UpdateWarping();
|
||||
|
||||
if (_motionWarpingIk == null) return;
|
||||
_motionWarpingIk.ApplyIK();
|
||||
}
|
||||
|
||||
private void Play_Internal(MotionWarpingAsset motionWarpingAsset)
|
||||
{
|
||||
if (playAnimator && animator != null)
|
||||
{
|
||||
animator.CrossFade(motionWarpingAsset.animation.name, blendTime);
|
||||
}
|
||||
|
||||
_startCurveValue = _endCurveValue = _accumRootMotion = _rootMotion = Vector3.zero;
|
||||
|
||||
_warpPhase.Target.transform = null;
|
||||
_originPosition = transform.position;
|
||||
_originRotation = transform.rotation;
|
||||
|
||||
_asset = motionWarpingAsset;
|
||||
|
||||
_phaseIndex = 0;
|
||||
_nextPhaseTime = warpPhases[0].startTime;
|
||||
|
||||
_bUpdateWarping = true;
|
||||
_hasActivePhase = false;
|
||||
|
||||
_rateScale = 1f;
|
||||
_warpLength = motionWarpingAsset.GetLength();
|
||||
|
||||
onWarpStarted.Invoke();
|
||||
}
|
||||
|
||||
public bool Interact(GameObject target)
|
||||
{
|
||||
if (target == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Interact(target.GetComponent<IWarpPointProvider>());
|
||||
}
|
||||
|
||||
public bool Interact(IWarpPointProvider target)
|
||||
{
|
||||
if (target == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var result = target.Interact(gameObject);
|
||||
if (!result.IsValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Play(result.asset, result.points);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Play(MotionWarpingAsset motionWarpingAsset, WarpPoint[] warpPoints)
|
||||
{
|
||||
if (motionWarpingAsset == null)
|
||||
{
|
||||
Debug.LogError("MotionWarping: WarpPoint[] warpPoints is null!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (warpPoints == null)
|
||||
{
|
||||
Debug.LogError("MotionWarping: Warp Points array is null!");
|
||||
return;
|
||||
}
|
||||
|
||||
warpPhases = motionWarpingAsset.warpPhases.ToArray();
|
||||
|
||||
if (warpPhases.Length != warpPoints.Length)
|
||||
{
|
||||
Debug.LogError("MotionWarping: Warp Phases and Warp Points array do not match!");
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < warpPhases.Length; i++)
|
||||
{
|
||||
WarpPhase phase = warpPhases[i];
|
||||
WarpPoint target = warpPoints[i];
|
||||
|
||||
if (target.transform == null)
|
||||
{
|
||||
phase.Target.position = WarpingUtility.ToWorld(target.position, target.rotation,
|
||||
phase.tOffset);
|
||||
phase.Target.rotation = target.rotation * Quaternion.Euler(phase.rOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
phase.Target.transform = target.transform;
|
||||
|
||||
phase.Target.position = target.position;
|
||||
phase.Target.rotation = target.rotation;
|
||||
|
||||
phase.Target.localPosition = phase.tOffset;
|
||||
phase.Target.localRotation = phase.rOffset;
|
||||
}
|
||||
|
||||
warpPhases[i] = phase;
|
||||
}
|
||||
|
||||
Play_Internal(motionWarpingAsset);
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
_bUpdateWarping = false;
|
||||
_warpPlayback = 0f;
|
||||
onWarpEnded.Invoke();
|
||||
}
|
||||
|
||||
public bool IsActive()
|
||||
{
|
||||
return _bUpdateWarping;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private List<WarpDebugData> _warpDebugData = new List<WarpDebugData>();
|
||||
|
||||
public static void AddWarpDebugData(MotionWarping target, WarpDebugData warpDebugData)
|
||||
{
|
||||
if (target == null) return;
|
||||
target._warpDebugData.Add(warpDebugData);
|
||||
}
|
||||
|
||||
private void OnDrawGizmos()
|
||||
{
|
||||
for (int i = 0; i < _warpDebugData.Count; i++)
|
||||
{
|
||||
var debugData = _warpDebugData[i];
|
||||
debugData.onDrawGizmos?.Invoke();
|
||||
if(debugData.duration < 0f) continue;
|
||||
|
||||
// Progress the timer.
|
||||
debugData.timer = Mathf.Clamp(debugData.timer + Time.deltaTime, 0f, debugData.duration);
|
||||
_warpDebugData[i] = debugData;
|
||||
|
||||
if (Mathf.Approximately(debugData.timer, debugData.duration))
|
||||
{
|
||||
_warpDebugData.RemoveAt(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a3164a26014538e45b7dbfa103dabef0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 100
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,53 @@
|
|||
// Designed by KINEMATION, 2024.
|
||||
|
||||
using Kinemation.MotionWarping.Runtime.Utility;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Kinemation.MotionWarping.Runtime.Core
|
||||
{
|
||||
[CreateAssetMenu(menuName = "KINEMATION/MotionWarping/WarpingAsset", fileName = "NewWarpingAsset", order = 0)]
|
||||
public class MotionWarpingAsset : ScriptableObject
|
||||
{
|
||||
[Header("Animation")]
|
||||
public AnimationClip animation;
|
||||
|
||||
public AnimationCurve rootX;
|
||||
public AnimationCurve rootY;
|
||||
public AnimationCurve rootZ;
|
||||
|
||||
public VectorBool useLinear = VectorBool.Enabled;
|
||||
public VectorBool useAnimation = VectorBool.Enabled;
|
||||
public VectorBool useWarping = VectorBool.Enabled;
|
||||
|
||||
[Tooltip("If true, CharacterController or a RigidBody will be moved with physics enabled.")]
|
||||
public bool useCollision = false;
|
||||
|
||||
[Range(0f, 2f)] public float playRateBasis = 1f;
|
||||
|
||||
[Range(1, 10)] public int phasesAmount = 1;
|
||||
public List<WarpPhase> warpPhases = new List<WarpPhase>();
|
||||
|
||||
public Vector3 GetVectorValue(float time)
|
||||
{
|
||||
if (rootX == null || rootY == null || rootZ == null)
|
||||
{
|
||||
Debug.LogError(name + ": null reference curve!");
|
||||
return Vector3.zero;
|
||||
}
|
||||
|
||||
return new Vector3(rootX.Evaluate(time), rootY.Evaluate(time), rootZ.Evaluate(time));
|
||||
}
|
||||
|
||||
public float GetLength()
|
||||
{
|
||||
if (animation == null)
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
|
||||
return animation.length;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 928e2ecfbd1ec0f469e1838b49a4dda9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,96 @@
|
|||
// Designed by KINEMATION, 2024.
|
||||
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace KINEMATION.MotionWarping.Runtime.Core
|
||||
{
|
||||
[Serializable]
|
||||
public struct LockState
|
||||
{
|
||||
public string controlCurveName;
|
||||
public Transform boneReference;
|
||||
[Min(0f)] public float interpSpeed;
|
||||
[NonSerialized] public float Weight;
|
||||
[NonSerialized] public Quaternion LockRotation;
|
||||
[NonSerialized] public Vector3 LockPosition;
|
||||
[NonSerialized] public bool IsLocked;
|
||||
[NonSerialized] public bool Interpolate;
|
||||
}
|
||||
|
||||
public class MotionWarpingIk : MonoBehaviour
|
||||
{
|
||||
[SerializeField] [Range(0f, 1f)] private float componentWeight = 1f;
|
||||
|
||||
[SerializeField] private LockState rightHandLockState;
|
||||
[SerializeField] private LockState leftHandLockState;
|
||||
[SerializeField] private LockState rightFootLockState;
|
||||
[SerializeField] private LockState leftFootLockState;
|
||||
|
||||
private Animator _animator;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
_animator = GetComponent<Animator>();
|
||||
}
|
||||
|
||||
// Updated the current bone lock state.
|
||||
private void UpdateBoneLock(ref LockState lockState)
|
||||
{
|
||||
Transform boneReference = lockState.boneReference;
|
||||
if (boneReference == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float weight = _animator.GetFloat(lockState.controlCurveName);
|
||||
|
||||
if (!lockState.IsLocked && Mathf.Approximately(weight, 1f))
|
||||
{
|
||||
lockState.LockPosition = boneReference.position;
|
||||
lockState.LockRotation = boneReference.rotation;
|
||||
lockState.IsLocked = true;
|
||||
lockState.Interpolate = false;
|
||||
lockState.Weight = 1f;
|
||||
return;
|
||||
}
|
||||
|
||||
if (lockState.IsLocked && Mathf.Approximately(weight, 0f))
|
||||
{
|
||||
lockState.IsLocked = false;
|
||||
lockState.Interpolate = true;
|
||||
}
|
||||
|
||||
if (!lockState.Interpolate)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float alpha = 1f - Mathf.Exp(-lockState.interpSpeed * Time.deltaTime);
|
||||
lockState.Weight = Mathf.Lerp(lockState.Weight, 0f, alpha);
|
||||
}
|
||||
|
||||
private void ApplyLock(ref LockState lockState)
|
||||
{
|
||||
Transform tip = lockState.boneReference;
|
||||
if (tip == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Transform mid = tip.parent;
|
||||
TwoBoneIk.SolveTwoBoneIK(mid.parent, mid, tip, (lockState.LockPosition, lockState.LockRotation),
|
||||
mid, lockState.Weight * componentWeight, 1f);
|
||||
|
||||
UpdateBoneLock(ref lockState);
|
||||
}
|
||||
|
||||
public void ApplyIK()
|
||||
{
|
||||
ApplyLock(ref rightHandLockState);
|
||||
ApplyLock(ref leftHandLockState);
|
||||
ApplyLock(ref rightFootLockState);
|
||||
ApplyLock(ref leftFootLockState);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f2c56b0df3354ea4a3ab76ef0923d868
|
||||
timeCreated: 1708838078
|
|
@ -0,0 +1,142 @@
|
|||
// Designed by KINEMATION, 2024.
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace KINEMATION.MotionWarping.Runtime.Core
|
||||
{
|
||||
public class TwoBoneIk
|
||||
{
|
||||
private const float FloatMin = 1e-10f;
|
||||
private const float SqrEpsilon = 1e-8f;
|
||||
|
||||
public static float TriangleAngle(float aLen, float aLen1, float aLen2)
|
||||
{
|
||||
float c = Mathf.Clamp((aLen1 * aLen1 + aLen2 * aLen2 - aLen * aLen) / (aLen1 * aLen2) / 2.0f, -1.0f, 1.0f);
|
||||
return Mathf.Acos(c);
|
||||
}
|
||||
|
||||
public static Quaternion FromToRotation(Vector3 from, Vector3 to)
|
||||
{
|
||||
float theta = Vector3.Dot(from.normalized, to.normalized);
|
||||
if (theta >= 1f)
|
||||
return Quaternion.identity;
|
||||
|
||||
if (theta <= -1f)
|
||||
{
|
||||
Vector3 axis = Vector3.Cross(from, Vector3.right);
|
||||
if (axis.sqrMagnitude == 0f)
|
||||
axis = Vector3.Cross(from, Vector3.up);
|
||||
|
||||
return Quaternion.AngleAxis(180f, axis);
|
||||
}
|
||||
|
||||
return Quaternion.AngleAxis(Mathf.Acos(theta) * Mathf.Rad2Deg, Vector3.Cross(from, to).normalized);
|
||||
}
|
||||
|
||||
public static Quaternion NormalizeSafe(Quaternion q)
|
||||
{
|
||||
float dot = Quaternion.Dot(q, q);
|
||||
if (dot > FloatMin)
|
||||
{
|
||||
float rsqrt = 1.0f / Mathf.Sqrt(dot);
|
||||
return new Quaternion(q.x * rsqrt, q.y * rsqrt, q.z * rsqrt, q.w * rsqrt);
|
||||
}
|
||||
|
||||
return Quaternion.identity;
|
||||
}
|
||||
|
||||
public static void SolveTwoBoneIK(
|
||||
Transform root,
|
||||
Transform mid,
|
||||
Transform tip,
|
||||
(Vector3, Quaternion) target,
|
||||
Transform hint,
|
||||
float targetWeight,
|
||||
float hintWeight
|
||||
)
|
||||
{
|
||||
if (Mathf.Approximately(targetWeight, 0f))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3 aPosition = root.position;
|
||||
Vector3 bPosition = mid.position;
|
||||
Vector3 cPosition = tip.position;
|
||||
Vector3 tPosition = Vector3.Lerp(cPosition, target.Item1, targetWeight);
|
||||
Quaternion tRotation = Quaternion.Lerp(tip.rotation, target.Item2, targetWeight);
|
||||
bool hasHint = hint != null && hintWeight > 0f;
|
||||
|
||||
Vector3 ab = bPosition - aPosition;
|
||||
Vector3 bc = cPosition - bPosition;
|
||||
Vector3 ac = cPosition - aPosition;
|
||||
Vector3 at = tPosition - aPosition;
|
||||
|
||||
float abLen = ab.magnitude;
|
||||
float bcLen = bc.magnitude;
|
||||
float acLen = ac.magnitude;
|
||||
float atLen = at.magnitude;
|
||||
|
||||
float oldAbcAngle = TriangleAngle(acLen, abLen, bcLen);
|
||||
float newAbcAngle = TriangleAngle(atLen, abLen, bcLen);
|
||||
|
||||
// Bend normal strategy is to take whatever has been provided in the animation
|
||||
// stream to minimize configuration changes, however if this is collinear
|
||||
// try computing a bend normal given the desired target position.
|
||||
// If this also fails, try resolving axis using hint if provided.
|
||||
Vector3 axis = Vector3.Cross(ab, bc);
|
||||
if (axis.sqrMagnitude < SqrEpsilon)
|
||||
{
|
||||
axis = hasHint ? Vector3.Cross(hint.position - aPosition, bc) : Vector3.zero;
|
||||
|
||||
if (axis.sqrMagnitude < SqrEpsilon)
|
||||
axis = Vector3.Cross(at, bc);
|
||||
|
||||
if (axis.sqrMagnitude < SqrEpsilon)
|
||||
axis = Vector3.up;
|
||||
}
|
||||
|
||||
axis = Vector3.Normalize(axis);
|
||||
|
||||
float a = 0.5f * (oldAbcAngle - newAbcAngle);
|
||||
float sin = Mathf.Sin(a);
|
||||
float cos = Mathf.Cos(a);
|
||||
Quaternion deltaR = new Quaternion(axis.x * sin, axis.y * sin, axis.z * sin, cos);
|
||||
mid.rotation = deltaR * mid.rotation;
|
||||
|
||||
cPosition = tip.position;
|
||||
ac = cPosition - aPosition;
|
||||
root.rotation = FromToRotation(ac, at) * root.rotation;
|
||||
|
||||
if (hasHint)
|
||||
{
|
||||
float acSqrMag = ac.sqrMagnitude;
|
||||
if (acSqrMag > 0f)
|
||||
{
|
||||
bPosition = mid.position;
|
||||
cPosition = tip.position;
|
||||
ab = bPosition - aPosition;
|
||||
ac = cPosition - aPosition;
|
||||
|
||||
Vector3 acNorm = ac / Mathf.Sqrt(acSqrMag);
|
||||
Vector3 ah = hint.position - aPosition;
|
||||
Vector3 abProj = ab - acNorm * Vector3.Dot(ab, acNorm);
|
||||
Vector3 ahProj = ah - acNorm * Vector3.Dot(ah, acNorm);
|
||||
|
||||
float maxReach = abLen + bcLen;
|
||||
if (abProj.sqrMagnitude > (maxReach * maxReach * 0.001f) && ahProj.sqrMagnitude > 0f)
|
||||
{
|
||||
Quaternion hintR = FromToRotation(abProj, ahProj);
|
||||
hintR.x *= hintWeight;
|
||||
hintR.y *= hintWeight;
|
||||
hintR.z *= hintWeight;
|
||||
hintR = NormalizeSafe(hintR);
|
||||
root.rotation = hintR * root.rotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tip.rotation = tRotation;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9637a7f6138e4e12a4db8b42a5c0738a
|
||||
timeCreated: 1708838183
|
|
@ -0,0 +1,62 @@
|
|||
// Designed by KINEMATION, 2024.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Kinemation.MotionWarping.Runtime.Utility;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Kinemation.MotionWarping.Runtime.Core
|
||||
{
|
||||
// Obstacle with pre-defined Warp Points
|
||||
public class WarpObstacle : MonoBehaviour, IWarpPointProvider
|
||||
{
|
||||
[SerializeField] private MotionWarpingAsset motionWarpingAsset;
|
||||
[SerializeField] private List<Transform> points = new List<Transform>();
|
||||
[SerializeField] private bool useTransforms = false;
|
||||
[SerializeField] private bool drawDebugPoints = false;
|
||||
|
||||
private void OnDrawGizmos()
|
||||
{
|
||||
if (!drawDebugPoints) return;
|
||||
|
||||
var color = Gizmos.color;
|
||||
Gizmos.color = Color.green;
|
||||
|
||||
foreach (var point in points)
|
||||
{
|
||||
if(point == null) continue;
|
||||
Gizmos.DrawWireSphere(point.position, 0.07f);
|
||||
}
|
||||
|
||||
Gizmos.color = color;
|
||||
}
|
||||
|
||||
public WarpInteractionResult Interact(GameObject instigator)
|
||||
{
|
||||
WarpInteractionResult result;
|
||||
result.points = new WarpPoint[points.Count];
|
||||
result.asset = motionWarpingAsset;
|
||||
result.success = points.Count > 0;
|
||||
|
||||
for (int i = 0; i < result.points.Length; i++)
|
||||
{
|
||||
if (useTransforms)
|
||||
{
|
||||
result.points[i] = new WarpPoint()
|
||||
{
|
||||
transform = points[i]
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
result.points[i] = new WarpPoint()
|
||||
{
|
||||
position = points[i].position,
|
||||
rotation = points[i].rotation
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ceff3fd151a844759bf3cc1490295ef7
|
||||
timeCreated: 1694707273
|
|
@ -0,0 +1,24 @@
|
|||
// Designed by KINEMATION, 2024.
|
||||
|
||||
using Kinemation.MotionWarping.Runtime.Utility;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Kinemation.MotionWarping.Runtime.Core
|
||||
{
|
||||
public struct WarpInteractionResult
|
||||
{
|
||||
public WarpPoint[] points;
|
||||
public MotionWarpingAsset asset;
|
||||
public bool success;
|
||||
|
||||
public bool IsValid()
|
||||
{
|
||||
return success && points != null && asset != null;
|
||||
}
|
||||
}
|
||||
|
||||
public interface IWarpPointProvider
|
||||
{
|
||||
public WarpInteractionResult Interact(GameObject instigator);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: af4b4f93ff874248959946ba0a83a8ea
|
||||
timeCreated: 1699699303
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5f330a55deff4a9e9e9ff0379a74eb82
|
||||
timeCreated: 1695198325
|
|
@ -0,0 +1,94 @@
|
|||
// Designed by KINEMATION, 2024.
|
||||
|
||||
using Kinemation.MotionWarping.Runtime.Core;
|
||||
using Kinemation.MotionWarping.Runtime.Utility;
|
||||
|
||||
using UnityEngine;
|
||||
using Quaternion = UnityEngine.Quaternion;
|
||||
using Vector3 = UnityEngine.Vector3;
|
||||
|
||||
namespace Kinemation.MotionWarping.Runtime.Examples
|
||||
{
|
||||
public class AlignComponent : MonoBehaviour, IWarpPointProvider
|
||||
{
|
||||
[SerializeField] [Range(0f, 180f)] private float interactionAngle = 0f;
|
||||
[SerializeField] [Range(-180f, 180f)] private float offsetAngle = 0f;
|
||||
[SerializeField] [Min(0f)] private float distance = 0f;
|
||||
[SerializeField] private MotionWarpingAsset motionWarpingAsset;
|
||||
[SerializeField] private string targetAnimName;
|
||||
|
||||
private Animator _animator;
|
||||
|
||||
private void OnDrawGizmos()
|
||||
{
|
||||
Gizmos.color = Color.red;
|
||||
|
||||
Vector3 position = transform.position;
|
||||
Vector3 forward = Quaternion.Euler(0f, offsetAngle, 0f) * transform.forward;
|
||||
float debugRadius = 0.05f;
|
||||
|
||||
Vector3 left = Quaternion.Euler(0f, interactionAngle, 0f) * forward;
|
||||
Vector3 right = Quaternion.Euler(0f, -interactionAngle, 0f) * forward;
|
||||
|
||||
Gizmos.DrawLine(position, position + left * distance);
|
||||
Gizmos.DrawLine(position, position + right * distance);
|
||||
|
||||
Gizmos.DrawWireSphere(position, debugRadius);
|
||||
Gizmos.DrawWireSphere(position + left * distance, debugRadius);
|
||||
Gizmos.DrawWireSphere(position + right * distance, debugRadius);
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
_animator = GetComponent<Animator>();
|
||||
}
|
||||
|
||||
public WarpInteractionResult Interact(GameObject instigator)
|
||||
{
|
||||
WarpInteractionResult result = new WarpInteractionResult()
|
||||
{
|
||||
success = false,
|
||||
points = null,
|
||||
asset = null,
|
||||
};
|
||||
|
||||
if (instigator == null || motionWarpingAsset == null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if ((instigator.transform.position - transform.position).magnitude > distance)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
Vector3 forward = Quaternion.Euler(0f, offsetAngle, 0f) * transform.forward;
|
||||
float angle = Mathf.Acos(Vector3.Dot(-instigator.transform.forward, forward)) * Mathf.Rad2Deg;
|
||||
|
||||
if (angle > interactionAngle)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
result.asset = motionWarpingAsset;
|
||||
result.points = new[]
|
||||
{
|
||||
new WarpPoint()
|
||||
{
|
||||
transform = this.transform,
|
||||
position = Vector3.zero,
|
||||
rotation = Quaternion.identity
|
||||
}
|
||||
};
|
||||
|
||||
result.success = true;
|
||||
|
||||
if (_animator != null)
|
||||
{
|
||||
_animator.CrossFade(targetAnimName, 0.15f);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cce7418bf5c1f1f4b85e97a5470f0bd5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,137 @@
|
|||
// Designed by KINEMATION, 2024.
|
||||
|
||||
using Kinemation.MotionWarping.Runtime.Core;
|
||||
using Kinemation.MotionWarping.Runtime.Utility;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Kinemation.MotionWarping.Runtime.Examples
|
||||
{
|
||||
public class HangComponent : MonoBehaviour, IWarpPointProvider
|
||||
{
|
||||
[SerializeField] private MotionWarpingAsset hangAsset;
|
||||
[SerializeField] private MotionWarpingAsset jumpDownAsset;
|
||||
|
||||
[Header("Trace Settings")]
|
||||
[SerializeField] [Min(0f)] private float capsuleRadius;
|
||||
[SerializeField] [Min(0f)] private float sphereCheckRadius;
|
||||
[SerializeField] [Min(0f)] private float minLedgeLength;
|
||||
[SerializeField] [Min(0f)] private LayerMask layerMask;
|
||||
|
||||
[Header("Hanging")]
|
||||
[SerializeField] [Min(0f)] private float maxAllowedDistance;
|
||||
[SerializeField] [Min(0f)] private float maxAllowedHeight;
|
||||
[SerializeField] [Min(0f)] private float minAllowedHeight;
|
||||
|
||||
private bool _isHanging;
|
||||
|
||||
private WarpInteractionResult TryToJumpDown()
|
||||
{
|
||||
WarpInteractionResult result = new WarpInteractionResult()
|
||||
{
|
||||
success = false,
|
||||
points = null,
|
||||
asset = null,
|
||||
};
|
||||
|
||||
Vector3 start = transform.position;
|
||||
bool bHit = Physics.SphereCast(start, sphereCheckRadius, -transform.up, out var hit,
|
||||
maxAllowedHeight, layerMask);
|
||||
|
||||
if (!bHit)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
Quaternion resultRotation = transform.rotation;
|
||||
Vector3 resultPosition = hit.point;
|
||||
|
||||
result.points = new[]
|
||||
{
|
||||
new WarpPoint()
|
||||
{
|
||||
position = resultPosition,
|
||||
rotation = resultRotation
|
||||
}
|
||||
};
|
||||
result.asset = jumpDownAsset;
|
||||
result.success = true;
|
||||
|
||||
_isHanging = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
private WarpInteractionResult TryToHang()
|
||||
{
|
||||
WarpInteractionResult result = new WarpInteractionResult()
|
||||
{
|
||||
success = false,
|
||||
points = null,
|
||||
asset = null,
|
||||
};
|
||||
|
||||
Vector3 start = transform.position;
|
||||
Vector3 end = start;
|
||||
|
||||
start.y += minAllowedHeight;
|
||||
end.y += minAllowedHeight + maxAllowedHeight;
|
||||
|
||||
Vector3 direction = transform.forward;
|
||||
float distance = maxAllowedDistance;
|
||||
|
||||
bool bHit = Physics.CapsuleCast(start, end, capsuleRadius, direction,
|
||||
out var hit, distance, layerMask);
|
||||
|
||||
if (!bHit)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
Quaternion targetRotation = Quaternion.LookRotation(-hit.normal, transform.up);
|
||||
|
||||
distance = (end - start).magnitude;
|
||||
|
||||
start = hit.point;
|
||||
start.y = end.y;
|
||||
|
||||
bHit = Physics.SphereCast(start, sphereCheckRadius, -transform.up, out hit, distance,
|
||||
layerMask);
|
||||
|
||||
if (!bHit)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
start = hit.point;
|
||||
start.y += sphereCheckRadius + 0.01f;
|
||||
|
||||
Vector3 targetPosition = hit.point;
|
||||
|
||||
bHit = Physics.SphereCast(start, sphereCheckRadius, targetRotation * Vector3.forward, out hit,
|
||||
minLedgeLength, layerMask);
|
||||
|
||||
if (bHit)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
result.success = true;
|
||||
result.asset = hangAsset;
|
||||
result.points = new[]
|
||||
{
|
||||
new WarpPoint()
|
||||
{
|
||||
position = targetPosition,
|
||||
rotation = targetRotation
|
||||
}
|
||||
};
|
||||
|
||||
_isHanging = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
public WarpInteractionResult Interact(GameObject instigator)
|
||||
{
|
||||
return _isHanging ? TryToJumpDown() : TryToHang();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 18c8d51c4bfa48c69c050aa993b9b441
|
||||
timeCreated: 1705657565
|
|
@ -0,0 +1,131 @@
|
|||
// Designed by KINEMATION, 2024.
|
||||
|
||||
using Kinemation.MotionWarping.Runtime.Core;
|
||||
using Kinemation.MotionWarping.Runtime.Utility;
|
||||
using UnityEngine;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
namespace Kinemation.MotionWarping.Runtime.Examples
|
||||
{
|
||||
public class MantleComponent : MonoBehaviour, IWarpPointProvider
|
||||
{
|
||||
[SerializeField] private MotionWarpingAsset mantleHigh;
|
||||
[SerializeField] private MotionWarpingAsset mantleLow;
|
||||
[SerializeField] private MantleSettings settings;
|
||||
|
||||
private Vector3 _targetPosition;
|
||||
private Quaternion _targetRotation;
|
||||
|
||||
public WarpInteractionResult Interact(GameObject instigator)
|
||||
{
|
||||
WarpInteractionResult result = new WarpInteractionResult()
|
||||
{
|
||||
points = null,
|
||||
asset = null,
|
||||
success = false
|
||||
};
|
||||
|
||||
if (settings == null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
var motionWarping = instigator.GetComponent<Core.MotionWarping>();
|
||||
|
||||
Vector3 start = transform.position;
|
||||
Vector3 end = start;
|
||||
|
||||
start.y += settings.minHeight + settings.characterCapsuleRadius;
|
||||
end.y += settings.maxHeight;
|
||||
|
||||
Vector3 direction = transform.forward;
|
||||
float distance = settings.maxDistance;
|
||||
|
||||
bool bHit = Physics.CapsuleCast(start, end, settings.characterCapsuleRadius, direction,
|
||||
out var hit, distance, settings.layerMask);
|
||||
|
||||
if (!bHit)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
_targetRotation = Quaternion.LookRotation(-hit.normal, transform.up);
|
||||
|
||||
distance = (end - start).magnitude;
|
||||
|
||||
start = hit.point;
|
||||
start += (_targetRotation * Vector3.forward) * settings.forwardOffset;
|
||||
|
||||
start.y = end.y;
|
||||
|
||||
bHit = Physics.SphereCast(start, settings.sphereEdgeCheckRadius, -transform.up, out hit,
|
||||
distance, settings.layerMask);
|
||||
|
||||
start = hit.point;
|
||||
|
||||
if (!bHit)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
Vector3 surfaceNormal = hit.normal;
|
||||
|
||||
start += surfaceNormal * (0.02f + settings.characterCapsuleRadius);
|
||||
end = start + surfaceNormal * settings.characterCapsuleHeight;
|
||||
|
||||
bHit = Physics.CheckCapsule(start, end, settings.characterCapsuleRadius, settings.layerMask);
|
||||
|
||||
if (bHit)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
float surfaceIncline = Mathf.Clamp(Vector3.Dot(transform.up, surfaceNormal), -1f, 1f);
|
||||
surfaceIncline = Mathf.Acos(surfaceIncline) * Mathf.Rad2Deg;
|
||||
|
||||
if (surfaceIncline > settings.maxSurfaceInclineAngle)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
Vector3 forwardVector = _targetRotation * Vector3.forward;
|
||||
_targetRotation = Quaternion.LookRotation(forwardVector);
|
||||
_targetPosition = hit.point;
|
||||
|
||||
result.points = new[]
|
||||
{
|
||||
new WarpPoint()
|
||||
{
|
||||
transform = hit.transform,
|
||||
position = hit.transform.InverseTransformPoint(_targetPosition),
|
||||
rotation = Quaternion.Inverse(hit.transform.rotation) * _targetRotation
|
||||
}
|
||||
};
|
||||
|
||||
float height = _targetPosition.y - transform.position.y;
|
||||
|
||||
result.asset = height > settings.lowHeight ? mantleHigh : mantleLow;
|
||||
result.success = true;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
Core.MotionWarping.AddWarpDebugData(motionWarping, new WarpDebugData()
|
||||
{
|
||||
duration = 5f,
|
||||
onDrawGizmos = () =>
|
||||
{
|
||||
var color = Gizmos.color;
|
||||
Gizmos.color = Color.green;
|
||||
Gizmos.DrawWireSphere(_targetPosition, 0.1f);
|
||||
Handles.Label(_targetPosition, "Mantle Target Point");
|
||||
Gizmos.color = color;
|
||||
}
|
||||
});
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue