添加插件
@@ -1,7 +1,8 @@
|
||||
|
||||
This directories are splitted into different categories for Assembly Definitions.
|
||||
(All directories mentioned below will appear when importing fimpossible assembly definitions)
|
||||
You can use Assembly Definitions to speed up compilation time.
|
||||
Import .unitypackage FImpossible Assembly Definitions to have them prepared automatically.
|
||||
Import .unitypackage "FImpossible Assembly Definitions to have them prepared automatically.
|
||||
|
||||
|
||||
/Editor - Scripts responsible for drawing inspector windows and other gui for plugins
|
||||
@@ -12,4 +13,4 @@ and also additional editor menus
|
||||
/Plugins - Level Design - All plugins related to level design grouped in one directory
|
||||
/Plugins - Other - All plugins related to other things like optimization grouped in one directory
|
||||
/Plugins - Shared - Demos plugins or my other free packages used in shared way for rest of the packages
|
||||
/Shared Tools - Shared tools for inspector windows or shared math logics
|
||||
/Shared Tools - Shared tools for inspector windows or shared math logics, this directory is used by all other plugins
|
||||
@@ -115,7 +115,7 @@ namespace FIMSpace.FEditor
|
||||
|
||||
[MenuItem("Assets/Utilities/Sub-Assets/Destroy Sub Asset", true)]
|
||||
private static bool DestroySubAssetCheck(MenuCommand menuCommand)
|
||||
{ if( Selection.objects.Length == 0 ) return false; return AssetDatabase.IsSubAsset(Selection.objects[0]); }
|
||||
{ return AssetDatabase.IsSubAsset(Selection.objects[0]); }
|
||||
|
||||
[MenuItem("Assets/Utilities/Sub-Assets/Destroy Sub Asset", false)]
|
||||
private static void DestroySubAsset(MenuCommand menuCommand)
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 511704c08bd35394ea37e60b93d63513
|
||||
folderAsset: yes
|
||||
timeCreated: 1603290412
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8504e6f0ad3ec1040b6c91b589b00907
|
||||
folderAsset: yes
|
||||
timeCreated: 1532351210
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7df895321e8326c49996143255a443cd
|
||||
folderAsset: yes
|
||||
timeCreated: 1553950449
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1,116 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2d136b24af83be649b68f39b1e0ce67d
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 11
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -100
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: -1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
applyGammaDecoding: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: 4
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 1
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: WebGL
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 3.5 KiB |
@@ -0,0 +1,74 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6e4e9af30ed1bf944be42dfa1b3842e3
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 4
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 0
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -1
|
||||
wrapMode: -1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
platformSettings:
|
||||
- buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
- buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
textureFormat: 4
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 1
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 870 B |
@@ -0,0 +1,104 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e8206fdb058138940aeb32c519d84281
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 11
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -100
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: -1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
applyGammaDecoding: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: 4
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 1
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 855 B |
@@ -0,0 +1,86 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1be512d4fc0d19d4b957fa92fe767f3e
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 0
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -1
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: -1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
platformSettings:
|
||||
- buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
- buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: 4
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 1
|
||||
androidETC2FallbackOverride: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 3.7 KiB |
@@ -0,0 +1,116 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 73e848e8b105ad4419739438d540ff07
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 11
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -100
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: -1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
applyGammaDecoding: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: 4
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 1
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: WebGL
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 17 KiB |
@@ -0,0 +1,116 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a05a4f2884a2af44eaeedea1ea5ca396
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 11
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -100
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: -1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
applyGammaDecoding: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: 4
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 1
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: WebGL
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
@@ -0,0 +1,86 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 10dc66ee21c31144882ddd7d2f13ae77
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 0
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -1
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: -1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
platformSettings:
|
||||
- buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
- buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: 4
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 1
|
||||
androidETC2FallbackOverride: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 17 KiB |
@@ -0,0 +1,86 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2e215648cc15ce04297817f7407c4e7b
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 0
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -1
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: -1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
platformSettings:
|
||||
- buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
- buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: 4
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 1
|
||||
androidETC2FallbackOverride: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 3.7 KiB |
@@ -0,0 +1,116 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f1f543bbb761e234cbb384a09c3482cc
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 11
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -100
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: -1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
applyGammaDecoding: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: 4
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 1
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: WebGL
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 6.5 KiB |
@@ -0,0 +1,116 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7958d01c62579034fa1ffbb911dd6b59
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 11
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -100
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: -1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
applyGammaDecoding: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: 4
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 1
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: WebGL
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,76 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2364e2c6718af0c4aaf6d3b166d5bb6e
|
||||
timeCreated: 1600109893
|
||||
licenseType: Store
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 4
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 0
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: -1
|
||||
mipBias: -1
|
||||
wrapMode: -1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
platformSettings:
|
||||
- buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
- buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
textureFormat: 4
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 1
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,192 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Languages>
|
||||
|
||||
<English>
|
||||
<string name="Main Setup">Main Setup</string>
|
||||
<string name="Tail Chain">Tail Chain</string>
|
||||
<string name="Optimization And More">Optimization & More</string>
|
||||
|
||||
<string name="Setup">Setup</string>
|
||||
<string name="Tweak">Tweak</string>
|
||||
<string name="Features">Features</string>
|
||||
<string name="Shaping">Shaping</string>
|
||||
|
||||
<string name="Tweak Animation">Tweak Animation</string>
|
||||
<string name="Limiting Motion">Limiting Motion</string>
|
||||
<string name="Smoothing Motion">Smoothing Motion</string>
|
||||
<string name="Additional Parameters">Additional Parameters</string>
|
||||
|
||||
<string name="Additional Modules">Additional Modules</string>
|
||||
<string name="Auto Waving">Auto Waving</string>
|
||||
<string name="Collisions">Collisions</string>
|
||||
<string name="Colliders Setup">Colliders Setup</string>
|
||||
|
||||
<string name="Partial Blend">Partial Blend</string>
|
||||
<string name="Inverse Kinematics">Inverse Kinematics (IK)</string>
|
||||
<string name="Deflection">Deflection</string>
|
||||
<string name="Disable when Far">Disable when Far</string>
|
||||
|
||||
<string name="Additional Shaping">Additional Shaping</string>
|
||||
|
||||
<string name="Physical Effectors">Physical Effectors</string>
|
||||
<string name="Wind">Wind Effect</string>
|
||||
</English>
|
||||
|
||||
<Polski>
|
||||
<string name="Main Setup">Konfiguracja</string>
|
||||
<string name="Tail Chain">Łańcuch</string>
|
||||
<string name="Optimization And More">Optymalizacja i Inne</string>
|
||||
|
||||
<string name="Setup">Przygotuj</string>
|
||||
<string name="Tweak">Dostosuj</string>
|
||||
<string name="Features">Dodatki</string>
|
||||
<string name="Shaping">Kształt</string>
|
||||
|
||||
<string name="Tweak Animation">Przystosowanie Animacji</string>
|
||||
<string name="Limiting Motion">Limitowanie</string>
|
||||
<string name="Smoothing Motion">Wygładzanie Ruchu</string>
|
||||
<string name="Additional Parameters">Parametry Dodatkowe</string>
|
||||
|
||||
<string name="Additional Modules">Dodatkowe Moduły</string>
|
||||
<string name="Auto Waving">Machanie</string>
|
||||
<string name="Collisions">Kolizje</string>
|
||||
<string name="Colliders Setup">Konfiguracja Koliderów</string>
|
||||
|
||||
<string name="Partial Blend">Częściowy Wpływ Animatora</string>
|
||||
<string name="Inverse Kinematics">Odwrócona Kinematyka (IK)</string>
|
||||
<string name="Deflection">Odgięcia</string>
|
||||
<string name="Disable when Far">Wyłącz gdy zbyt daleko</string>
|
||||
|
||||
<string name="Additional Shaping">Dodatkowe Kształtowanie</string>
|
||||
|
||||
<string name="Physical Effectors">Efekty Fizyczne</string>
|
||||
<string name="Wind">Efekt Wiatru</string>
|
||||
</Polski>
|
||||
|
||||
<русский>
|
||||
<string name="Main Setup">Основная настройка</string>
|
||||
<string name="Tail Chain">хвост цепи</string>
|
||||
<string name="Optimization And More">Оптимизация и многое другое</string>
|
||||
|
||||
<string name="Setup">Настройка</string>
|
||||
<string name="Tweak">Настройки</string>
|
||||
<string name="Features">Возможности</string>
|
||||
<string name="Shaping">Формирование</string>
|
||||
|
||||
<string name="Tweak Animation">Настроить анимацию</string>
|
||||
<string name="Limiting Motion">Ограничение движения</string>
|
||||
<string name="Smoothing Motion">Сглаживание движения</string>
|
||||
<string name="Additional Parameters">Дополнительные параметры</string>
|
||||
|
||||
<string name="Additional Modules">Дополнительные модули</string>
|
||||
<string name="Auto Waving">Авто Размахивая</string>
|
||||
<string name="Collisions">Столкновения</string>
|
||||
<string name="Colliders Setup">Коллайдеры Настройка</string>
|
||||
|
||||
<string name="Partial Blend">Частичная смесь</string>
|
||||
<string name="Inverse Kinematics">Обратная кинематика (IK)</string>
|
||||
<string name="Deflection">Отражение</string>
|
||||
<string name="Disable when Far">Выключите, когда далеко</string>
|
||||
|
||||
<string name="Additional Shaping">Дополнительные формы</string>
|
||||
|
||||
<string name="Physical Effectors">Физические эффекторы</string>
|
||||
<string name="Wind">Воздействие ветра</string>
|
||||
</русский>
|
||||
|
||||
<中文>
|
||||
<string name="Main Setup">主设置</string>
|
||||
<string name="Tail Chain">尾链</string>
|
||||
<string name="Optimization And More">优化和更多</string>
|
||||
|
||||
<string name="Setup">设置</string>
|
||||
<string name="Tweak">调整</string>
|
||||
<string name="Features">功能</string>
|
||||
<string name="Shaping">形状</string>
|
||||
|
||||
<string name="Tweak Animation">调整动画</string>
|
||||
<string name="Limiting Motion">限制运动</string>
|
||||
<string name="Smoothing Motion">平滑运动</string>
|
||||
<string name="Additional Parameters">附加参数</string>
|
||||
|
||||
<string name="Additional Modules">附加模块</string>
|
||||
<string name="Auto Waving">自动挥动</string>
|
||||
<string name="Collisions">碰撞</string>
|
||||
<string name="Colliders Setup">碰撞器设置</string>
|
||||
|
||||
<string name="Partial Blend">部分混合</string>
|
||||
<string name="Inverse Kinematics">反向运动 (IK)</string>
|
||||
<string name="Deflection">偏转</string>
|
||||
<string name="Disable when Far">远方时关闭</string>
|
||||
|
||||
<string name="Additional Shaping">附加整形</string>
|
||||
|
||||
<string name="Physical Effectors">物理效应器</string>
|
||||
<string name="Wind">风效应</string>
|
||||
</中文>
|
||||
|
||||
|
||||
<日本語>
|
||||
<string name="Main Setup">メインセットアップ</string>
|
||||
<string name="Tail Chain">テールチェーン</string>
|
||||
<string name="Optimization And More">最適化と、モーションを制限するアニメーション</string>
|
||||
|
||||
<string name="Setup">セットアップ</string>
|
||||
<string name="Tweak">微調整</string>
|
||||
<string name="Features">機能</string>
|
||||
<string name="Shaping">シェーピング</string>
|
||||
|
||||
<string name="Tweak Animation">スムージングモーション</string>
|
||||
<string name="Limiting Motion">を制限するアニメーションを</string>
|
||||
<string name="Smoothing Motion">ツイークする追加パラメータ</string>
|
||||
<string name="Additional Parameters">追加のパラメータ</string>
|
||||
|
||||
<string name="Additional Modules">コライダの自動</string>
|
||||
<string name="Auto Waving">ウェーブ</string>
|
||||
<string name="Collisions">コライダ設定</string>
|
||||
<string name="Colliders Setup">コライダ設定</string>
|
||||
|
||||
<string name="Partial Blend">部分ブレンド</string>
|
||||
<string name="Inverse Kinematics">インバースキネマティクス (IK)</string>
|
||||
<string name="Deflection">偏向</string>
|
||||
<string name="Disable when Far">遠く離れたときにオフにする</string>
|
||||
|
||||
<string name="Additional Shaping">追加シェーピング</string>
|
||||
|
||||
<string name="Physical Effectors">フィジカルエフェクター</string>
|
||||
<string name="Wind">風の効果</string>
|
||||
</日本語>
|
||||
|
||||
|
||||
<한국어>
|
||||
<string name="Main Setup">메인 설정</string>
|
||||
<string name="Tail Chain">테일 체인</string>
|
||||
<string name="Optimization And More">최적화 및 더 많은</string>
|
||||
|
||||
<string name="Setup">설정</string>
|
||||
<string name="Tweak">조정</string>
|
||||
<string name="Features">기능</string>
|
||||
<string name="Shaping">모양</string>
|
||||
|
||||
<string name="Tweak Animation">애니메이션 조정</string>
|
||||
<string name="Limiting Motion">모션 제한</string>
|
||||
<string name="Smoothing Motion">스무딩 모션</string>
|
||||
<string name="Additional Parameters">추가 매개 변수</string>
|
||||
|
||||
<string name="Additional Modules">추가 모듈</string>
|
||||
<string name="Auto Waving">자동 흔들기</string>
|
||||
<string name="Collisions">충돌</string>
|
||||
<string name="Colliders Setup">콜라이더 설정</string>
|
||||
|
||||
<string name="Partial Blend">부분 혼합</string>
|
||||
<string name="Inverse Kinematics">역 역학 (IK)</string>
|
||||
<string name="Deflection">편향</string>
|
||||
<string name="Disable when Far">멀리 떨어져 있을 때 끄기</string>
|
||||
|
||||
<string name="Additional Shaping">추가 성형</string>
|
||||
|
||||
<string name="Physical Effectors">물리 효과</string>
|
||||
<string name="Wind">바람 효과</string>
|
||||
</한국어>
|
||||
|
||||
</Languages>
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a7eb67ced331ec24b845911cd4ae82d1
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 780 B |
@@ -0,0 +1,86 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3b86ed89e09bbe5428b182b3ca650663
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 0
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -1
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: -1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
platformSettings:
|
||||
- buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
- buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: 4
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 1
|
||||
androidETC2FallbackOverride: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
After Width: | Height: | Size: 790 B |
@@ -0,0 +1,116 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bedb2c7a06ea4464b949cc2c4a4ef4fa
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 11
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapsPreserveCoverage: 0
|
||||
alphaTestReferenceValue: 0.5
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: -1
|
||||
aniso: 1
|
||||
mipBias: -100
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: -1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 2
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
applyGammaDecoding: 0
|
||||
platformSettings:
|
||||
- serializedVersion: 3
|
||||
buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: Standalone
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: 4
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 1
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
- serializedVersion: 3
|
||||
buildTarget: WebGL
|
||||
maxTextureSize: 2048
|
||||
resizeAlgorithm: 0
|
||||
textureFormat: -1
|
||||
textureCompression: 1
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
androidETC2FallbackOverride: 0
|
||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID:
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
secondaryTextures: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
pSDShowRemoveMatteOption: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,779 @@
|
||||
using FIMSpace.FEditor;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FIMSpace.FTail
|
||||
{
|
||||
public partial class FTailAnimator2_Editor
|
||||
{
|
||||
private bool drawHeaderFoldout = false;
|
||||
private void HeaderBoxMain(string title, ref bool drawGizmos, ref bool defaultInspector, Texture2D scrIcon, MonoBehaviour target, int height = 22)
|
||||
{
|
||||
EditorGUILayout.BeginVertical(FGUI_Resources.HeaderBoxStyle);
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
if (GUILayout.Button(new GUIContent(scrIcon), EditorStyles.label, new GUILayoutOption[2] { GUILayout.Width(height - 2), GUILayout.Height(height - 2) }))
|
||||
{
|
||||
MonoScript script = MonoScript.FromMonoBehaviour(target);
|
||||
if (script) EditorGUIUtility.PingObject(script);
|
||||
drawHeaderFoldout = !drawHeaderFoldout;
|
||||
}
|
||||
|
||||
if (GUILayout.Button(title, FGUI_Resources.GetTextStyle(14, true, TextAnchor.MiddleLeft), GUILayout.Height(height)))
|
||||
{
|
||||
MonoScript script = MonoScript.FromMonoBehaviour(target);
|
||||
if (script) EditorGUIUtility.PingObject(script);
|
||||
drawHeaderFoldout = !drawHeaderFoldout;
|
||||
}
|
||||
|
||||
if (EditorGUIUtility.currentViewWidth > 326)
|
||||
// Youtube channel button
|
||||
if (GUILayout.Button(new GUIContent(FGUI_Resources.Tex_Tutorials, "Open FImpossible Creations Channel with tutorial videos in your web browser"), FGUI_Resources.ButtonStyle, new GUILayoutOption[2] { GUILayout.Width(height), GUILayout.Height(height) }))
|
||||
{
|
||||
Application.OpenURL("https://www.youtube.com/c/FImpossibleCreations");
|
||||
}
|
||||
|
||||
if (EditorGUIUtility.currentViewWidth > 292)
|
||||
// Store site button
|
||||
if (GUILayout.Button(new GUIContent(FGUI_Resources.Tex_Website, "Open FImpossible Creations Asset Store Page inside your web browser"), FGUI_Resources.ButtonStyle, new GUILayoutOption[2] { GUILayout.Width(height), GUILayout.Height(height) }))
|
||||
{
|
||||
Application.OpenURL("https://assetstore.unity.com/publishers/37262");
|
||||
}
|
||||
|
||||
// Manual file button
|
||||
if (_manualFile == null) _manualFile = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(System.IO.Path.GetDirectoryName(AssetDatabase.GetAssetPath(MonoScript.FromMonoBehaviour(target))) + "/Tail Animator - User Manual.pdf");
|
||||
if (_manualFile)
|
||||
if (GUILayout.Button(new GUIContent(FGUI_Resources.Tex_Manual, "Open .PDF user manual file for Tail Animator"), FGUI_Resources.ButtonStyle, new GUILayoutOption[2] { GUILayout.Width(height), GUILayout.Height(height) }))
|
||||
{
|
||||
EditorGUIUtility.PingObject(_manualFile);
|
||||
Application.OpenURL(Application.dataPath + "/" + AssetDatabase.GetAssetPath(_manualFile).Replace("Assets/", ""));
|
||||
}
|
||||
|
||||
FGUI_Inspector.DrawSwitchButton(ref drawGizmos, FGUI_Resources.Tex_GizmosOff, FGUI_Resources.Tex_Gizmos, "Toggle drawing gizmos on character in scene window", height, height, true);
|
||||
FGUI_Inspector.DrawSwitchButton(ref drawHeaderFoldout, FGUI_Resources.Tex_LeftFold, FGUI_Resources.Tex_DownFold, "Toggle to view additional options for foldouts", height, height);
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
if (drawHeaderFoldout)
|
||||
{
|
||||
FGUI_Inspector.DrawUILine(0.07f, 0.1f, 1, 4, 0.99f);
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
choosedLang = (ELangs)EditorGUILayout.EnumPopup(choosedLang, new GUIStyle(EditorStyles.layerMaskField) { fixedHeight = 0 }, new GUILayoutOption[2] { GUILayout.Width(80), GUILayout.Height(22) });
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
PlayerPrefs.SetInt("FimposLang", (int)choosedLang);
|
||||
SetupLangs();
|
||||
}
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
|
||||
bool hierSwitchOn = PlayerPrefs.GetInt("AnimsH", 1) == 1;
|
||||
FGUI_Inspector.DrawSwitchButton(ref hierSwitchOn, FGUI_Resources.Tex_HierSwitch, null, "Switch drawing small icons in hierarchy", height, height, true);
|
||||
PlayerPrefs.SetInt("AnimsH", hierSwitchOn ? 1 : 0);
|
||||
|
||||
|
||||
if (GUILayout.Button(new GUIContent(FGUI_Resources.Tex_Rename, "Change component title to yours (current: '" + Get._editor_Title + "'"), FGUI_Resources.ButtonStyle, new GUILayoutOption[2] { GUILayout.Width(height), GUILayout.Height(height) }))
|
||||
{
|
||||
string filename = EditorUtility.SaveFilePanelInProject("Type your title (no file will be created)", Get._editor_Title, "", "Type your title (no file will be created)");
|
||||
if (!string.IsNullOrEmpty(filename))
|
||||
{
|
||||
filename = System.IO.Path.GetFileNameWithoutExtension(filename);
|
||||
if (!string.IsNullOrEmpty(filename))
|
||||
{ Get._editor_Title = filename; serializedObject.ApplyModifiedProperties(); }
|
||||
}
|
||||
}
|
||||
|
||||
// Old new UI Button
|
||||
//FGUI_Inspector.DrawSwitchButton(ref drawNewInspector, FGUI_Resources.Tex_AB, null, "Switch GUI Style to old / new", height, height, true);
|
||||
//if (!drawNewInspector && drawDefaultInspector) drawDefaultInspector = false;
|
||||
|
||||
// Default inspector switch
|
||||
FGUI_Inspector.DrawSwitchButton(ref defaultInspector, FGUI_Resources.Tex_Default, null, "Toggle inspector view to default inspector.\n\nIf you ever edit source code of Look Animator and add custom variables, you can see them by entering this mode, also sometimes there can be additional/experimental variables to play with.", height, height);
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
|
||||
public bool hideSkin = false;
|
||||
void El_DrawOptimizeWithMesh()
|
||||
{
|
||||
// Drawing box informing if spine animator is working by mesh visibility factor
|
||||
if (Get.OptimizeWithMesh)
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
GUI.color = new Color(1f, 1f, 1f, .5f);
|
||||
EditorGUILayout.BeginHorizontal(EditorStyles.helpBox);
|
||||
|
||||
if (!Get.DisabledByInvisibility())
|
||||
EditorGUILayout.LabelField("Spine Animator Is Active", FGUI_Resources.HeaderStyle);
|
||||
else
|
||||
{
|
||||
GUI.enabled = false;
|
||||
EditorGUILayout.LabelField("Spine Animator Is Inactive", FGUI_Resources.HeaderStyle);
|
||||
GUI.enabled = true;
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
GUI.color = c;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
EditorGUIUtility.labelWidth = 144;
|
||||
EditorGUILayout.PropertyField(sp_OptimizeWithMesh);
|
||||
EditorGUIUtility.labelWidth = 0;
|
||||
|
||||
if (Get.OptimizeWithMesh == null)
|
||||
{
|
||||
if (GUILayout.Button("Find", new GUILayoutOption[1] { GUILayout.Width(44) }))
|
||||
{
|
||||
if (Get.OptimizeWithMesh == null)
|
||||
{
|
||||
Get.OptimizeWithMesh = Get.transform.GetComponent<Renderer>();
|
||||
if (!Get.OptimizeWithMesh) Get.OptimizeWithMesh = Get.transform.GetComponentInChildren<Renderer>();
|
||||
if (!Get.OptimizeWithMesh) if (Get.transform.parent != null) Get.OptimizeWithMesh = Get.transform.parent.GetComponentInChildren<Renderer>();
|
||||
if (!Get.OptimizeWithMesh) if (Get.transform.parent != null) if (Get.transform.parent.parent != null) Get.OptimizeWithMesh = Get.transform.parent.parent.GetComponentInChildren<Renderer>();
|
||||
if (!Get.OptimizeWithMesh) if (Get.transform.parent != null) if (Get.transform.parent.parent != null) if (Get.transform.parent.parent.parent != null) Get.OptimizeWithMesh = Get.transform.parent.parent.parent.GetComponentInChildren<Renderer>();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GUILayout.Button(hideSkin ? "Show" : "Hide", new GUILayoutOption[1] { GUILayout.Width(44) }))
|
||||
{
|
||||
hideSkin = !hideSkin;
|
||||
|
||||
if (hideSkin)
|
||||
for (int i = 0; i < skins.Count; i++) skins[i].shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.ShadowsOnly;
|
||||
else
|
||||
for (int i = 0; i < skins.Count; i++) skins[i].shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.On;
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
if ( Get.OptimizeWithMesh)
|
||||
{
|
||||
SerializedProperty spc = sp_OptimizeWithMesh.Copy();
|
||||
spc.Next(false);
|
||||
EditorGUILayout.PropertyField(spc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void El_DrawSpringiness()
|
||||
{
|
||||
GUI.color = new Color(1f, 1f, 1f, 0.7f);
|
||||
EditorGUILayout.BeginVertical();
|
||||
|
||||
string balAdd = "";
|
||||
string balTip = "";
|
||||
|
||||
if (!Get.UseCurlingCurve && !Get.UseSpringCurve && !Get.UseSlitheryCurve)
|
||||
if (Get.Curling > 0.3f)
|
||||
{
|
||||
if (Get.Springiness > Mathf.Epsilon)
|
||||
{
|
||||
float treshold = Mathf.Lerp(0.3f, 0.08f, Get.Slithery);
|
||||
|
||||
if (Get.Springiness + treshold < Get.Curling)
|
||||
{
|
||||
balAdd = " ► ";
|
||||
balTip = "Springiness should be set higher to notice bouncy motion";
|
||||
}
|
||||
else
|
||||
if (Get.Springiness - treshold * 0.7f > Get.Curling)
|
||||
{
|
||||
balAdd = " ◄ ";
|
||||
balTip = "Springiness should be set lower to avoid too rapid bounces";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Tooltip texts
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
if (Get.UseSpringCurve)
|
||||
GUILayout.Label(" Tail Start", smallStyle);
|
||||
else
|
||||
GUILayout.Label(new GUIContent(" Balanced" + " " + balAdd, balTip), smallStyle);
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
if (Get.UseSpringCurve)
|
||||
GUILayout.Label("Tail End ", smallStyle);
|
||||
else
|
||||
GUILayout.Label(new GUIContent(balAdd + " " + "Bouncy ", balTip), smallStyle);
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
if (Get.UseSpringCurve)
|
||||
GUILayout.Space(-0f);
|
||||
else
|
||||
GUILayout.Space(-4f);
|
||||
|
||||
//if (Get.Springiness == 0.0f) GUI.color = defaultValC; else
|
||||
GUI.color = c;
|
||||
|
||||
if (Get.UseSpringCurve)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.PropertyField(sp_SpringCurve, new GUIContent(sp_Springiness.displayName, sp_Springiness.tooltip), GUILayout.MaxHeight(18)); GUILayout.Space(3f);
|
||||
EditorGUI.BeginChangeCheck();
|
||||
SwitchButton(ref Get.UseSpringCurve, "Spread springiness speed parameter weight over tail segments", curveIcon);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
GetSelectedTailAnimators(); for (int i = 0; i < lastSelected.Count; i++)
|
||||
{
|
||||
lastSelected[i].UseSpringCurve = Get.UseSpringCurve; new SerializedObject(lastSelected[i]).ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
GUILayout.Space(2f);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal(); EditorGUIUtility.fieldWidth = 38;
|
||||
EditorGUILayout.PropertyField(sp_Springiness); EditorGUIUtility.fieldWidth = 0;
|
||||
EditorGUI.BeginChangeCheck();
|
||||
SwitchButton(ref Get.UseSpringCurve, "Spread springiness speed parameter weight over tail segments", curveIcon);
|
||||
if (EditorGUI.EndChangeCheck()) { GetSelectedTailAnimators(); for (int i = 0; i < lastSelected.Count; i++) { lastSelected[i].UseSpringCurve = Get.UseSpringCurve; new SerializedObject(lastSelected[i]).ApplyModifiedProperties(); } }
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
|
||||
GUI.color = c;
|
||||
EditorGUILayout.EndVertical();
|
||||
|
||||
EditorGUILayout.BeginVertical();
|
||||
}
|
||||
|
||||
|
||||
void El_DrawSlippery()
|
||||
{
|
||||
EditorGUILayout.BeginVertical();
|
||||
|
||||
if (Get.UseSlipperyCurve)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
GUI.color = new Color(1f, 1f, 1f, 0.7f);
|
||||
|
||||
GUILayout.Label(" Tail Start", smallStyle);
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
GUILayout.Label("Tail End ", smallStyle);
|
||||
GUI.color = c;
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.PropertyField(sp_SlipperyCurve, new GUIContent("Collision Slippery", sp_SlipperyCurve.tooltip), GUILayout.MaxHeight(18)); GUILayout.Space(3f);
|
||||
EditorGUI.BeginChangeCheck();
|
||||
SwitchButton(ref Get.UseSlipperyCurve, "Spread collision slippery parameter over tail segments", curveIcon);
|
||||
if (EditorGUI.EndChangeCheck()) { GetSelectedTailAnimators(); for (int i = 0; i < lastSelected.Count; i++) { lastSelected[i].UseSlipperyCurve = Get.UseSlipperyCurve; new SerializedObject(lastSelected[i]).ApplyModifiedProperties(); } }
|
||||
EditorGUILayout.EndHorizontal();
|
||||
GUILayout.Space(2f);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal(); EditorGUIUtility.fieldWidth = 38;
|
||||
EditorGUILayout.PropertyField(sp_CollisionSlippery); EditorGUIUtility.fieldWidth = 0;
|
||||
EditorGUI.BeginChangeCheck();
|
||||
SwitchButton(ref Get.UseSlipperyCurve, "Spread collision slippery parameter over tail segments", curveIcon);
|
||||
if (EditorGUI.EndChangeCheck()) { GetSelectedTailAnimators(); for (int i = 0; i < lastSelected.Count; i++) { lastSelected[i].UseSlipperyCurve = Get.UseSlipperyCurve; new SerializedObject(lastSelected[i]).ApplyModifiedProperties(); } }
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
//EditorGUILayout.BeginVertical();
|
||||
}
|
||||
|
||||
|
||||
void El_DrawSlithery()
|
||||
{
|
||||
GUI.color = new Color(1f, 1f, 1f, 0.7f);
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
if (Get.UseSlitheryCurve)
|
||||
GUILayout.Label(" Tail Start", smallStyle);
|
||||
else
|
||||
GUILayout.Label(" Stiff", smallStyle);
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
if (Get.UseSlitheryCurve)
|
||||
GUILayout.Label("Tail End ", smallStyle);
|
||||
else
|
||||
GUILayout.Label("Smooth ", smallStyle);
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
GUI.color = c;
|
||||
|
||||
if (Get.UseSlitheryCurve)
|
||||
GUILayout.Space(0f);
|
||||
else
|
||||
GUILayout.Space(-3f);
|
||||
|
||||
|
||||
if (Get.UseSlitheryCurve)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.PropertyField(sp_SlitCurve, new GUIContent(sp_Slithery.displayName, sp_Slithery.tooltip), GUILayout.MaxHeight(18)); GUILayout.Space(3f);
|
||||
EditorGUI.BeginChangeCheck();
|
||||
SwitchButton(ref Get.UseSlitheryCurve, "Spread sensitivity speed parameter weight over tail segments", curveIcon);
|
||||
if (EditorGUI.EndChangeCheck()) { GetSelectedTailAnimators(); for (int i = 0; i < lastSelected.Count; i++) { lastSelected[i].UseSlitheryCurve = Get.UseSlitheryCurve; new SerializedObject(lastSelected[i]).ApplyModifiedProperties(); } }
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal(); EditorGUIUtility.fieldWidth = 38;
|
||||
EditorGUILayout.PropertyField(sp_Slithery); EditorGUIUtility.fieldWidth = 0;
|
||||
EditorGUI.BeginChangeCheck();
|
||||
SwitchButton(ref Get.UseSlitheryCurve, "Spread sensitivity speed parameter weight over tail segments", curveIcon);
|
||||
if (EditorGUI.EndChangeCheck()) { GetSelectedTailAnimators(); for (int i = 0; i < lastSelected.Count; i++) { lastSelected[i].UseSlitheryCurve = Get.UseSlitheryCurve; new SerializedObject(lastSelected[i]).ApplyModifiedProperties(); } }
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
GUI.color = c;
|
||||
}
|
||||
|
||||
|
||||
void El_DrawCurling()
|
||||
{
|
||||
|
||||
GUI.color = new Color(1f, 1f, 1f, 0.7f);
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
|
||||
|
||||
string straiAdd = "";
|
||||
string straiTip = "";
|
||||
|
||||
if (!Get.UseCurlingCurve && !Get.UseSpringCurve && !Get.UseSlitheryCurve)
|
||||
if (Get.Springiness > Mathf.Epsilon)
|
||||
{
|
||||
//float treshold = Mathf.Lerp(0.3f, 0.08f, Get.Slithery);
|
||||
|
||||
if (Get.Curling < Get.Springiness)
|
||||
{
|
||||
straiAdd = " ► ";
|
||||
straiTip = "Feel free to boost curling high when you're using springiness";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (Get.UseCurlingCurve)
|
||||
GUILayout.Label(" Tail Start", smallStyle);
|
||||
else
|
||||
GUILayout.Label(new GUIContent(" Straightened " + straiAdd, straiTip), smallStyle);
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
if (Get.UseCurlingCurve)
|
||||
GUILayout.Label("Tail End ", smallStyle);
|
||||
else
|
||||
GUILayout.Label("Tangled ", smallStyle);
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
GUI.color = c;
|
||||
|
||||
if (Get.UseCurlingCurve)
|
||||
GUILayout.Space(0f);
|
||||
else
|
||||
GUILayout.Space(-2f);
|
||||
|
||||
|
||||
//if (Get.Curling == 0.5f) GUI.color = defaultValC; else
|
||||
GUI.color = c;
|
||||
|
||||
|
||||
if (Get.UseCurlingCurve)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.PropertyField(sp_CurlingCurve, new GUIContent(sp_Curling.displayName, sp_Curling.tooltip), GUILayout.MaxHeight(18)); GUILayout.Space(3f);
|
||||
EditorGUI.BeginChangeCheck();
|
||||
SwitchButton(ref Get.UseCurlingCurve, "Spread curling over tail segments", curveIcon);
|
||||
if (EditorGUI.EndChangeCheck()) { GetSelectedTailAnimators(); for (int i = 0; i < lastSelected.Count; i++) { lastSelected[i].UseCurlingCurve = Get.UseCurlingCurve; new SerializedObject(lastSelected[i]).ApplyModifiedProperties(); } }
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal(); EditorGUIUtility.fieldWidth = 38;
|
||||
EditorGUILayout.PropertyField(sp_Curling); EditorGUIUtility.fieldWidth = 0;
|
||||
EditorGUI.BeginChangeCheck();
|
||||
SwitchButton(ref Get.UseCurlingCurve, "Spread curling parameter over tail segments", curveIcon);
|
||||
if (EditorGUI.EndChangeCheck()) { GetSelectedTailAnimators(); for (int i = 0; i < lastSelected.Count; i++) { lastSelected[i].UseCurlingCurve = Get.UseCurlingCurve; new SerializedObject(lastSelected[i]).ApplyModifiedProperties(); } }
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
GUI.color = c;
|
||||
}
|
||||
|
||||
|
||||
void El_DrawLimitingAngle()
|
||||
{
|
||||
if (Get.AngleLimit > 180) GUI.color = defaultValC;
|
||||
EditorGUILayout.PropertyField(sp_AngleLimit);
|
||||
GUI.color = c;
|
||||
|
||||
if (Get.AngleLimit < 181)
|
||||
{
|
||||
if (Get.AngleLimitAxis == Vector3.zero) GUI.color = c * new Color(1f, 1f, 1f, 0.6f);
|
||||
EditorGUILayout.PropertyField(sp_AngleLimitAxis);
|
||||
GUI.color = c;
|
||||
|
||||
if (Get.AngleLimitAxis != Vector3.zero)
|
||||
{
|
||||
if (Get.LimitAxisRange.x == Get.LimitAxisRange.y) GUI.color = c * new Color(1f, 1f, 1f, 0.6f);
|
||||
EditorGUILayout.MinMaxSlider(new GUIContent("Range", "If you want limit axes symmetrically leave this parameter unchanged, if you want limit one direction of axis more than reversed, tweak this parameter"),
|
||||
ref Get.LimitAxisRange.x, ref Get.LimitAxisRange.y, -90f, 90f);
|
||||
GUI.color = c;
|
||||
}
|
||||
|
||||
EditorGUILayout.PropertyField(sp_LimitSmoothing);
|
||||
|
||||
GUILayout.Space(5f);
|
||||
}
|
||||
|
||||
GUI.color = c;
|
||||
}
|
||||
|
||||
|
||||
static bool drawInclud = true;
|
||||
void El_DrawSelectiveCollisionBox()
|
||||
{
|
||||
if (Get.IncludedColliders == null) Get.IncludedColliders = new System.Collections.Generic.List<Collider>();
|
||||
Get._editor_IsInspectorViewingIncludedColliders = drawInclud;
|
||||
|
||||
GUILayout.Space(1f);
|
||||
GUI.color = new Color(0.85f, 1f, 0.85f, 1f);
|
||||
EditorGUILayout.BeginHorizontal(FGUI_Resources.HeaderBoxStyleH);
|
||||
string f = FGUI_Resources.GetFoldSimbol(drawInclud); int inclC = Get.IncludedColliders.Count;
|
||||
GUI.color = c;
|
||||
|
||||
GUILayout.Label(new GUIContent(" "), GUILayout.Width(1));
|
||||
string inclColFoldTitle = "";
|
||||
|
||||
if (Get.DynamicWorldCollidersInclusion)
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
inclColFoldTitle = Lang("Collide With") + " (Dynamic" + " : " + inclC + ")";
|
||||
else
|
||||
inclColFoldTitle = "Always Include (" + inclC + ")";
|
||||
}
|
||||
else
|
||||
inclColFoldTitle = Lang("Collide With") + " (" + (inclC == 0 ? "0 !!!" : inclC.ToString()) + ")";
|
||||
|
||||
if (GUILayout.Button(new GUIContent(" " + f + " " + inclColFoldTitle, FGUI_Resources.TexBehaviourIcon), FGUI_Resources.FoldStyle, GUILayout.Height(24))) drawInclud = !drawInclud;
|
||||
|
||||
//if (!Application.isPlaying)
|
||||
// if (Get.DynamicWorldCollidersInclusion) drawInclud = false;
|
||||
|
||||
//bool checkNullIncludColls = true;
|
||||
if (drawInclud)
|
||||
{
|
||||
//if (GUILayout.Button("+", new GUILayoutOption[2] { GUILayout.MaxWidth(24), GUILayout.MaxHeight(22) }))
|
||||
//{
|
||||
// Get.IncludedColliders.Add(null);
|
||||
// //Get._editor_checkInclCollidersForNulls = -10;
|
||||
// //checkNullIncludColls = false;
|
||||
// serializedObject.Update();
|
||||
// serializedObject.ApplyModifiedProperties();
|
||||
//}
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
if (drawInclud)
|
||||
{
|
||||
FGUI_Inspector.VSpace(-3, -5);
|
||||
GUI.color = new Color(0.6f, .9f, 0.6f, 1f);
|
||||
EditorGUILayout.BeginVertical(FGUI_Resources.BGInBoxStyleH);
|
||||
GUI.color = c;
|
||||
GUILayout.Space(5f);
|
||||
|
||||
|
||||
// Drawing colliders from list
|
||||
if (Get.IncludedColliders.Count == 0)
|
||||
{
|
||||
EditorGUILayout.LabelField("Please add here colliders", FGUI_Resources.HeaderStyle);
|
||||
GUILayout.Space(2f);
|
||||
}
|
||||
else
|
||||
{
|
||||
Get.CheckForColliderDuplicatesAndNulls();
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
for (int i = 0; i < Get.IncludedColliders.Count; i++)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
if (Get.IncludedColliders[i] != null)
|
||||
{
|
||||
if (!Get.IncludedColliders[i].gameObject.activeInHierarchy) GUI.color = new Color(1f, 1f, 1f, 0.5f);
|
||||
Get.IncludedColliders[i] = (Collider)EditorGUILayout.ObjectField(Get.IncludedColliders[i], typeof(Collider), true);
|
||||
if (!Get.IncludedColliders[i].gameObject.activeInHierarchy) GUI.color = c;
|
||||
}
|
||||
|
||||
if (GUILayout.Button("X", new GUILayoutOption[2] { GUILayout.MaxWidth(22), GUILayout.MaxHeight(16) }))
|
||||
{
|
||||
Get.IncludedColliders.RemoveAt(i);
|
||||
serializedObject.Update();
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
return;
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
Get.CheckForColliderDuplicatesAndNulls();
|
||||
serializedObject.Update();
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.Space(6f);
|
||||
|
||||
// Lock button
|
||||
GUILayout.BeginVertical();
|
||||
if (ActiveEditorTracker.sharedTracker.isLocked) GUI.color = new Color(0.44f, 0.44f, 0.44f, 0.8f); else GUI.color = new Color(0.95f, 0.95f, 0.99f, 0.9f);
|
||||
if (GUILayout.Button(new GUIContent("Lock Inspector for Drag & Drop Colliders", "Drag & drop colliders to 'Included Colliders' List from the hierarchy"), FGUI_Resources.ButtonStyle, GUILayout.Height(18))) ActiveEditorTracker.sharedTracker.isLocked = !ActiveEditorTracker.sharedTracker.isLocked;
|
||||
GUI.color = c;
|
||||
GUILayout.EndVertical();
|
||||
|
||||
// Drag and drop box
|
||||
El_DrawDragAndDropCollidersBox();
|
||||
|
||||
GUILayout.Space(3f);
|
||||
|
||||
if (Get.IncludedColliders.Count > 0)
|
||||
{
|
||||
EditorGUILayout.HelpBox("You can disable collider components on the objects - tail animator will still detect collision. If you deactivate the Game Object with collider - tail animator will not detect collision with it.", MessageType.Info);
|
||||
}
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void El_DrawSelectiveCollisionBox2D()
|
||||
{
|
||||
GUILayout.Space(1f);
|
||||
GUI.color = new Color(0.85f, 1f, 0.85f, 1f);
|
||||
EditorGUILayout.BeginHorizontal(FGUI_Resources.HeaderBoxStyleH);
|
||||
string f = FGUI_Resources.GetFoldSimbol(drawInclud); int inclC = Get.IncludedColliders2D.Count;
|
||||
GUI.color = c;
|
||||
|
||||
GUILayout.Label(new GUIContent(" "), GUILayout.Width(1));
|
||||
string inclColFoldTitle = "";
|
||||
|
||||
inclColFoldTitle = "2D " + Lang("Collide With") + " (" + (inclC == 0 ? "None" : inclC.ToString()) + ")";
|
||||
|
||||
if (GUILayout.Button(new GUIContent(" " + f + " " + inclColFoldTitle, FGUI_Resources.TexBehaviourIcon), FGUI_Resources.FoldStyle, GUILayout.Height(24))) drawInclud = !drawInclud;
|
||||
|
||||
if (drawInclud)
|
||||
if (GUILayout.Button("+", new GUILayoutOption[2] { GUILayout.MaxWidth(24), GUILayout.MaxHeight(22) }))
|
||||
{
|
||||
Get.IncludedColliders2D.Add(null);
|
||||
serializedObject.Update();
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
if (drawInclud)
|
||||
{
|
||||
FGUI_Inspector.VSpace(-3, -5);
|
||||
GUI.color = new Color(0.6f, .9f, 0.6f, 1f);
|
||||
EditorGUILayout.BeginVertical(FGUI_Resources.BGInBoxStyleH);
|
||||
GUI.color = c;
|
||||
GUILayout.Space(5f);
|
||||
|
||||
EditorGUILayout.HelpBox("2D Collision is supported ONLY FOR CIRCLE, CAPSULE, BOX and POLYGON colliders for now!", MessageType.None);
|
||||
|
||||
// Drawing colliders from list
|
||||
if (Get.IncludedColliders2D.Count == 0)
|
||||
{
|
||||
EditorGUILayout.LabelField("Please add here 2D colliders", FGUI_Resources.HeaderStyle);
|
||||
GUILayout.Space(2f);
|
||||
}
|
||||
else
|
||||
{
|
||||
Get.CheckForColliderDuplicatesAndNulls2D();
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
for (int i = 0; i < Get.IncludedColliders2D.Count; i++)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
if (Get.IncludedColliders2D[i] != null)
|
||||
{
|
||||
if (!Get.IncludedColliders2D[i].gameObject.activeInHierarchy) GUI.color = new Color(1f, 1f, 1f, 0.5f);
|
||||
Get.IncludedColliders2D[i] = (Collider2D)EditorGUILayout.ObjectField(Get.IncludedColliders2D[i], typeof(Collider2D), true);
|
||||
if (!Get.IncludedColliders2D[i].gameObject.activeInHierarchy) GUI.color = c;
|
||||
}
|
||||
else
|
||||
{
|
||||
Get.IncludedColliders2D[i] = (Collider2D)EditorGUILayout.ObjectField(Get.IncludedColliders2D[i], typeof(Collider2D), true);
|
||||
}
|
||||
|
||||
if (GUILayout.Button("X", new GUILayoutOption[2] { GUILayout.MaxWidth(22), GUILayout.MaxHeight(16) }))
|
||||
{
|
||||
Get.IncludedColliders2D.RemoveAt(i);
|
||||
serializedObject.Update();
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
return;
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
Get.CheckForColliderDuplicatesAndNulls();
|
||||
serializedObject.Update();
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.Space(3f);
|
||||
|
||||
// Lock button
|
||||
GUILayout.BeginVertical();
|
||||
if (ActiveEditorTracker.sharedTracker.isLocked) GUI.color = new Color(0.44f, 0.44f, 0.44f, 0.8f); else GUI.color = new Color(0.95f, 0.95f, 0.99f, 0.9f);
|
||||
if (GUILayout.Button(new GUIContent("Lock Inspector for Drag & Drop Colliders", "Drag & drop colliders to 'Included Colliders' List from the hierarchy"), FGUI_Resources.ButtonStyle, GUILayout.Height(18))) ActiveEditorTracker.sharedTracker.isLocked = !ActiveEditorTracker.sharedTracker.isLocked;
|
||||
GUI.color = c;
|
||||
GUILayout.EndVertical();
|
||||
|
||||
// Drag and drop box
|
||||
El_DrawDragAndDropCollidersBox();
|
||||
|
||||
GUILayout.Space(3f);
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void El_DrawCollidersDynamicInclusion()
|
||||
{
|
||||
if (Get.DynamicWorldCollidersInclusion)
|
||||
{
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
GUILayout.Space(5f);
|
||||
EditorGUILayout.HelpBox("Using trigger colliders to automatically fill 'Collide With' list", MessageType.Info);
|
||||
GUILayout.Space(3f);
|
||||
|
||||
EditorGUILayout.PropertyField(sp_InclusionRadius);
|
||||
if (Get.CollisionMode == TailAnimator2.ECollisionMode.m_3DCollision) EditorGUILayout.PropertyField(sp_IgnoreMeshColliders);
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.PropertyField(sp_colSameLayer, new GUIContent("Trigger Layer", sp_colSameLayer.tooltip));
|
||||
if (Get.CollidersSameLayer)
|
||||
{
|
||||
EditorGUILayout.LabelField(" ", GUILayout.Width(2));
|
||||
GUI.enabled = false; EditorGUILayout.LayerField(Get.gameObject.layer); GUI.enabled = true; EditorGUIUtility.labelWidth = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.LabelField(" ", GUILayout.Width(2));
|
||||
EditorGUILayout.PropertyField(sp_colCustomLayer, new GUIContent(""));
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
}
|
||||
|
||||
GUILayout.Space(4f);
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
if (Get.CollisionMode == TailAnimator2.ECollisionMode.m_3DCollision)
|
||||
EditorGUILayout.PropertyField(sp_colIgnored, true);
|
||||
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
}
|
||||
|
||||
void El_DrawDragAndDropCollidersBox()
|
||||
{
|
||||
GUILayout.Space(3);
|
||||
|
||||
var drop = GUILayoutUtility.GetRect(0f, 38f, new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
|
||||
GUI.color = new Color(0.5f, 1f, 0.5f, 0.9f);
|
||||
GUI.Box(drop, "Drag & Drop New Colliders Here", new GUIStyle(EditorStyles.helpBox) { alignment = TextAnchor.MiddleCenter, fixedHeight = 38 });
|
||||
GUI.color = c;
|
||||
var dropEvent = Event.current;
|
||||
|
||||
switch (dropEvent.type)
|
||||
{
|
||||
case EventType.DragUpdated:
|
||||
case EventType.DragPerform:
|
||||
if (!drop.Contains(dropEvent.mousePosition)) break;
|
||||
|
||||
DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
|
||||
|
||||
if (dropEvent.type == EventType.DragPerform)
|
||||
{
|
||||
DragAndDrop.AcceptDrag();
|
||||
|
||||
var tails = GetSelectedTailAnimators();
|
||||
if (tails.Contains(Get) == false) tails.Add(Get);
|
||||
|
||||
foreach (var dragged in DragAndDrop.objectReferences)
|
||||
{
|
||||
GameObject draggedObject = dragged as GameObject;
|
||||
|
||||
if (draggedObject)
|
||||
{
|
||||
|
||||
for (int t = 0; t < tails.Count; t++)
|
||||
{
|
||||
var tail = tails[t];
|
||||
if (tail.CollisionMode == TailAnimator2.ECollisionMode.m_3DCollision)
|
||||
{
|
||||
Collider[] coll = draggedObject.GetComponents<Collider>();
|
||||
for (int ci = 0; ci < coll.Length; ci++)
|
||||
{
|
||||
tail.AddCollider(coll[ci]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Collider2D[] coll = draggedObject.GetComponents<Collider2D>();
|
||||
for (int ci = 0; ci < coll.Length; ci++)
|
||||
{
|
||||
//if (coll[ci] is CharacterController) continue;
|
||||
tail.AddCollider(coll[ci]);
|
||||
}
|
||||
}
|
||||
|
||||
EditorUtility.SetDirty(tail);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Event.current.Use();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bcf1a74f343e94f4d83b39f22572bd73
|
||||
timeCreated: 1532131583
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 25475a529738d084d8d042e096cb2fe1
|
||||
timeCreated: 1532131583
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,156 @@
|
||||
using FIMSpace.FEditor;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FIMSpace.FTail
|
||||
{
|
||||
public partial class FTailAnimator2_Editor
|
||||
{
|
||||
// RESOURCES ----------------------------------------
|
||||
|
||||
public static Texture2D _TexTailAnimIcon { get { if (__texTailAnimIcon != null) return __texTailAnimIcon; __texTailAnimIcon = Resources.Load<Texture2D>("Tail Animator/Tail Animator Icon Small"); return __texTailAnimIcon; } }
|
||||
private static Texture2D __texTailAnimIcon = null;
|
||||
public static Texture2D _TexWavingIcon { get { if (__texWaving != null) return __texWaving; __texWaving = Resources.Load<Texture2D>("Tail Animator/WavingIcon"); return __texWaving; } }
|
||||
private static Texture2D __texWaving = null;
|
||||
public static Texture2D _TexPartialBlendIcon { get { if (__texPartBlendIcon != null) return __texPartBlendIcon; __texPartBlendIcon = Resources.Load<Texture2D>("Tail Animator/PartialBlendIcon"); return __texPartBlendIcon; } }
|
||||
private static Texture2D __texPartBlendIcon = null;
|
||||
public static Texture2D _TexIKIcon { get { if (__texIKIcon != null) return __texIKIcon; __texIKIcon = Resources.Load<Texture2D>("Tail Animator/IKIcon"); return __texIKIcon; } }
|
||||
private static Texture2D __texIKIcon = null;
|
||||
public static Texture2D _TexDeflIcon { get { if (__texDeflIcon != null) return __texDeflIcon; __texDeflIcon = Resources.Load<Texture2D>("Tail Animator/Deflection"); return __texDeflIcon; } }
|
||||
private static Texture2D __texDeflIcon = null;
|
||||
private static Texture curveIcon { get { if (_curveIcon == null) _curveIcon = FGUI_Resources.Tex_Curve; /*EditorGUIUtility.IconContent("AudioLowPassFilter Icon").image;*/ return _curveIcon; } }
|
||||
private static Texture _curveIcon;
|
||||
private static Texture _TexWindIcon { get { if (_windIcon == null) _windIcon = Resources.Load<Texture2D>("Tail Animator/Wind"); return _windIcon; } }
|
||||
private static Texture _windIcon;
|
||||
|
||||
private static UnityEngine.Object _manualFile;
|
||||
|
||||
private static GUIStyle smallStyle { get { if (_smallStyle == null) _smallStyle = new GUIStyle(EditorStyles.miniLabel) { fontStyle = FontStyle.Italic }; return _smallStyle; } }
|
||||
private static GUIStyle _smallStyle;
|
||||
|
||||
// HELPER VARIABLES ----------------------------------------
|
||||
|
||||
private TailAnimator2 Get { get { if (_get == null) _get = target as TailAnimator2; return _get; } }
|
||||
private TailAnimator2 _get;
|
||||
|
||||
private string topWarning = "";
|
||||
private float topWarningAlpha = 0f;
|
||||
|
||||
static bool drawDefaultInspector = false;
|
||||
//private Color limitsC = new Color(1f, 1f, 1f, 0.88f);
|
||||
private Color c;
|
||||
private Color bc;
|
||||
private Color defaultValC = new Color(1f, 1f, 1f, 0.825f);
|
||||
|
||||
|
||||
public List<SkinnedMeshRenderer> skins;
|
||||
SkinnedMeshRenderer largestSkin;
|
||||
Animator animator;
|
||||
Animation animation;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Trying to deep find skinned mesh renderer
|
||||
/// </summary>
|
||||
private void FindComponents()
|
||||
{
|
||||
if (skins == null) skins = new List<SkinnedMeshRenderer>();
|
||||
|
||||
foreach (var t in Get.transform.GetComponentsInChildren<Transform>())
|
||||
{
|
||||
SkinnedMeshRenderer s = t.GetComponent<SkinnedMeshRenderer>(); if (s) skins.Add(s);
|
||||
if (!animator) animator = t.GetComponent<Animator>();
|
||||
if (!animator) if (!animation) animation = t.GetComponent<Animation>();
|
||||
}
|
||||
|
||||
if ((skins != null && largestSkin != null) && (animator != null || animation != null)) return;
|
||||
|
||||
if (Get.transform != Get.transform)
|
||||
{
|
||||
foreach (var t in Get.transform.GetComponentsInChildren<Transform>())
|
||||
{
|
||||
SkinnedMeshRenderer s = t.GetComponent<SkinnedMeshRenderer>(); if (!skins.Contains(s)) if (s) skins.Add(s);
|
||||
if (!animator) animator = t.GetComponent<Animator>();
|
||||
if (!animator) if (!animation) animation = t.GetComponent<Animation>();
|
||||
}
|
||||
}
|
||||
|
||||
// Searching in parent
|
||||
if (skins.Count == 0)
|
||||
{
|
||||
Transform lastParent = Get.transform;
|
||||
|
||||
while (lastParent != null)
|
||||
{
|
||||
if (lastParent.parent == null) break;
|
||||
lastParent = lastParent.parent;
|
||||
}
|
||||
|
||||
foreach (var t in lastParent.GetComponentsInChildren<Transform>())
|
||||
{
|
||||
SkinnedMeshRenderer s = t.GetComponent<SkinnedMeshRenderer>(); if (!skins.Contains(s)) if (s) skins.Add(s);
|
||||
if (!animator) animator = t.GetComponent<Animator>();
|
||||
if (!animator) if (!animation) animation = t.GetComponent<Animation>();
|
||||
}
|
||||
}
|
||||
|
||||
if (skins.Count > 1)
|
||||
{
|
||||
largestSkin = skins[0];
|
||||
for (int i = 1; i < skins.Count; i++)
|
||||
if (skins[i].bones.Length > largestSkin.bones.Length)
|
||||
largestSkin = skins[i];
|
||||
}
|
||||
else
|
||||
if (skins.Count > 0) largestSkin = skins[0];
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Checking if transform is child of choosed root bone parent transform
|
||||
/// </summary>
|
||||
bool IsChildOf(Transform child, Transform rootParent)
|
||||
{
|
||||
Transform tParent = child;
|
||||
while (tParent != null && tParent != rootParent)
|
||||
{
|
||||
tParent = tParent.parent;
|
||||
}
|
||||
|
||||
if (tParent == null) return false; else return true;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Checking if transform is child of choosed root bone parent transform
|
||||
/// </summary>
|
||||
Transform GetLastChild(Transform rootParent)
|
||||
{
|
||||
Transform tChild = rootParent;
|
||||
while (tChild.childCount > 0) tChild = tChild.GetChild(0);
|
||||
return tChild;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Getting editor selected objects with tail animators to apply changes to multiple tail animator objects
|
||||
/// </summary>
|
||||
private List<TailAnimator2> GetSelectedTailAnimators()
|
||||
{
|
||||
List<TailAnimator2> anims = new List<TailAnimator2>();
|
||||
|
||||
for (int i = 0; i < Selection.gameObjects.Length; i++)
|
||||
{
|
||||
TailAnimator2 t = Selection.gameObjects[i].GetComponent<TailAnimator2>();
|
||||
if (t) if (!anims.Contains(t)) anims.Add(t);
|
||||
}
|
||||
|
||||
lastSelected = anims;
|
||||
return anims;
|
||||
}
|
||||
List<TailAnimator2> lastSelected;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0e79d23b98435d54d93ae9b83395b629
|
||||
timeCreated: 1532131583
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,85 @@
|
||||
using System.Collections;
|
||||
using System.Xml;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FIMSpace.FTail
|
||||
{
|
||||
public partial class FTailAnimator2_Editor
|
||||
{
|
||||
private TextAsset langFile { get { if (_langFile == null) _langFile = Resources.Load("Tail Animator/TailAnimator_Langs") as TextAsset; return _langFile; } }
|
||||
private TextAsset _langFile;
|
||||
|
||||
/// <summary> Readed langs from file </summary>
|
||||
private Hashtable langTexts;
|
||||
|
||||
public enum ELangs { English, Polski, русский, 中文, 日本語, 한국어 }
|
||||
private static ELangs choosedLang = 0;
|
||||
|
||||
|
||||
// Setup langs ----------------------------------------
|
||||
private void SetupLangs()
|
||||
{
|
||||
// Checking if lang was setted through player prefs
|
||||
choosedLang = (ELangs)PlayerPrefs.GetInt("FimposLang", 0);
|
||||
|
||||
if (langFile == null)
|
||||
{
|
||||
Debug.LogError("No lang file! You moved it from Editor/Resources/Tail Animator/ ???");
|
||||
return;
|
||||
}
|
||||
|
||||
#region Generating lang hashtable
|
||||
|
||||
var xml = new XmlDocument();
|
||||
xml.LoadXml(langFile.text);
|
||||
|
||||
|
||||
langTexts = new Hashtable();
|
||||
var element = xml.DocumentElement[choosedLang.ToString()];
|
||||
if (element != null)
|
||||
{
|
||||
|
||||
var elemEnum = element.GetEnumerator();
|
||||
while (elemEnum.MoveNext())
|
||||
{
|
||||
var xmlItem = (XmlElement)elemEnum.Current;
|
||||
langTexts.Add(xmlItem.GetAttribute("name"), xmlItem.InnerText);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("The specified language does not exist: " + choosedLang.ToString());
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
private string Lang(string title)
|
||||
{
|
||||
if (langTexts == null)
|
||||
{
|
||||
//Debug.Log("No Lang: [" + title + "]");
|
||||
return title;
|
||||
}
|
||||
|
||||
if (!langTexts.ContainsKey(title))
|
||||
{
|
||||
return title;
|
||||
}
|
||||
|
||||
string target = (string)langTexts[title];
|
||||
|
||||
if (string.IsNullOrEmpty(target)) return title;
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
|
||||
private bool LangBig()
|
||||
{
|
||||
if (choosedLang == ELangs.中文 || choosedLang == ELangs.日本語) return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9b613e7438d9e79458f122cd8fa5236b
|
||||
timeCreated: 1532131583
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,39 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FIMSpace.FTail
|
||||
{
|
||||
public partial class FTailAnimator2_Editor
|
||||
{
|
||||
protected virtual void OnSceneGUI()
|
||||
{
|
||||
if (Application.isPlaying) return;
|
||||
if (!Get.DrawGizmos) return;
|
||||
|
||||
if (Get._Editor_Category == TailAnimator2.ETailCategory.Setup)
|
||||
if (Get.BaseTransform)
|
||||
if (!FEngineering.VIsZero(Get.EndBoneJointOffset))
|
||||
{
|
||||
Get.RefreshTransformsList();
|
||||
|
||||
if (Get._TransformsGhostChain.Count > 0)
|
||||
{
|
||||
Undo.RecordObject(Get, "Changing position of tail joint offset");
|
||||
Transform root = Get._TransformsGhostChain[Get._TransformsGhostChain.Count - 1];
|
||||
|
||||
Vector3 off = root.TransformVector(Get.EndBoneJointOffset);
|
||||
Vector3 pos = root.position + off;
|
||||
Vector3 transformed = FEditor_TransformHandles.PositionHandle(pos, Get.BaseTransform.rotation, .3f, true, false);
|
||||
|
||||
if (Vector3.Distance(transformed, pos) > 0.00001f)
|
||||
{
|
||||
Vector3 diff = transformed - pos;
|
||||
Get.EndBoneJointOffset = root.InverseTransformVector(off + diff);
|
||||
SerializedObject obj = new SerializedObject(Get);
|
||||
if (obj != null) { obj.ApplyModifiedProperties(); obj.Update(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a05f6e8e06329674a85c95a70ca37780
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,339 @@
|
||||
using FIMSpace.FEditor;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FIMSpace.FTail
|
||||
{
|
||||
public partial class FTailAnimator2_Editor
|
||||
{
|
||||
|
||||
#region GUI Helpers
|
||||
|
||||
int[] setp_includeParent = new int[2] { 0, 1 };
|
||||
GUIContent[] setp_includeParentNames = new GUIContent[2] { new GUIContent("Exclude", "Excluding first bone from tail animator motion - it will be anchor for rest of the bones"), new GUIContent("Include", "Including first bone for tail animator motion - ghost point will be generated to simulate parent of this bone") };
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
private void Tab_DrawSetup()
|
||||
{
|
||||
|
||||
FGUI_Inspector.VSpace(-2, -4);
|
||||
GUILayout.BeginVertical(FGUI_Resources.ViewBoxStyle);
|
||||
GUILayout.BeginVertical(FGUI_Resources.BGInBoxBlankStyle);
|
||||
GUILayout.Space(7f);
|
||||
|
||||
Transform startField = Get.StartBone;
|
||||
if (Get.StartBone == null) { startField = Get.transform; GUI.color = new Color(1f, 1f, 1f, 0.7f); }
|
||||
|
||||
|
||||
if (topWarningAlpha > 0f)
|
||||
if (topWarning != "")
|
||||
{
|
||||
GUI.color = new Color(c.r, c.g, c.b, c.a * Mathf.Min(1f, topWarningAlpha));
|
||||
//EditorGUILayout.HelpBox(topWarning, MessageType.Info);
|
||||
if (GUILayout.Button(topWarning, FGUI_Inspector.Style(new Color(0.8f, 0.8f, 0f, 0.1f), 0), GUILayout.ExpandWidth(true))) { topWarningAlpha = 0f; }
|
||||
GUI.color = c;
|
||||
topWarningAlpha -= 0.05f;
|
||||
}
|
||||
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
EditorGUIUtility.labelWidth = 82;
|
||||
|
||||
Transform preStart = Get.StartBone;
|
||||
|
||||
if (Application.isPlaying) GUI.enabled = false;
|
||||
|
||||
try
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
}
|
||||
catch (System.Exception)
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
}
|
||||
|
||||
Transform startB = (Transform)EditorGUILayout.ObjectField(new GUIContent(sp_StartBone.displayName), startField, typeof(Transform), true);
|
||||
|
||||
if (startB != preStart)
|
||||
{
|
||||
Get.EndBone = null;
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
if (Application.isPlaying) GUI.enabled = true;
|
||||
|
||||
//bool canInclude = false;
|
||||
//if (startB) if (startB.parent) canInclude = true;
|
||||
|
||||
bool boneInSkin = true; if (skins.Count != 0) { boneInSkin = false; for (int s = 0; s < skins.Count; s++) { if (boneInSkin) break; for (int i = 0; i < skins[s].bones.Length; i++) { if (startB == skins[s].bones[i]) { boneInSkin = true; break; } } } }
|
||||
|
||||
if (!boneInSkin)
|
||||
{
|
||||
GUILayout.Space(4);
|
||||
EditorGUILayout.LabelField(new GUIContent(FGUI_Resources.Tex_Warning, "'Start Bone' was not found in mesh renderer of this object, are you sure you assigned correct 'Start Bone'?"), new GUILayoutOption[] { GUILayout.Height(18), GUILayout.Width(20) });
|
||||
}
|
||||
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
Get.IncludeParent = EditorGUILayout.IntPopup(new GUIContent("", "If start bone should be included in tail motion or just be anchor for rest of the bones"), Get.IncludeParent ? 1 : 0, setp_includeParentNames, setp_includeParent, GUILayout.Width(64)) == 1;
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
GetSelectedTailAnimators();
|
||||
for (int i = 0; i < lastSelected.Count; i++) { lastSelected[i].IncludeParent = Get.IncludeParent; new SerializedObject(lastSelected[i]).ApplyModifiedProperties(); }
|
||||
}
|
||||
|
||||
//if (Get.IncludeParent)
|
||||
// if (!canInclude)
|
||||
// {
|
||||
// GUILayout.Space(4);
|
||||
// EditorGUILayout.LabelField(new GUIContent(FGUI_Resources.Tex_Info, "Start bone need to have parent in order to be included in chain.\nAfter entering playmode this parameter will be set to 'Excluded'"), new GUILayoutOption[] { GUILayout.Height(18), GUILayout.Width(20) });
|
||||
// }
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
|
||||
EditorGUIUtility.labelWidth = 0;
|
||||
if (EditorGUI.EndChangeCheck()) { Get.StartBone = startB; serializedObject.ApplyModifiedProperties(); Get.GetGhostChain(); serializedObject.Update(); }
|
||||
|
||||
GUI.color = c;
|
||||
|
||||
GUILayout.Space(4f);
|
||||
GUILayout.EndVertical();
|
||||
|
||||
GUILayout.BeginVertical(FGUI_Resources.BGInBoxStyle);
|
||||
Fold_TailChainSetup();
|
||||
|
||||
GUILayout.Space(-5f);
|
||||
|
||||
GUILayout.EndVertical();
|
||||
|
||||
//Fold_DrawCoreAnimatorSetup();
|
||||
Fold_DrawAdditionalSetup();
|
||||
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void Tab_DrawTweaking()
|
||||
{
|
||||
FGUI_Inspector.VSpace(-2, -4);
|
||||
GUILayout.BeginVertical(FGUI_Resources.ViewBoxStyle);
|
||||
|
||||
GUILayout.Space(4);
|
||||
EditorGUIUtility.labelWidth = 160f;
|
||||
EditorGUILayout.BeginVertical(FGUI_Resources.BGInBoxBlankStyle);
|
||||
EditorGUILayout.PropertyField(sp_TailAnimatorAmount); EditorGUIUtility.labelWidth = 0f;
|
||||
EditorGUILayout.EndVertical();
|
||||
GUI.color = c;
|
||||
GUILayout.Space(-1f);
|
||||
|
||||
Fold_TweakingBending();
|
||||
Fold_TweakingLimiting();
|
||||
Fold_TweakingSmoothing();
|
||||
Fold_TweakingAdditional();
|
||||
|
||||
GUILayout.Space(-5f);
|
||||
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
|
||||
|
||||
private void Tab_DrawAdditionalFeatures()
|
||||
{
|
||||
FGUI_Inspector.VSpace(-2, -3);
|
||||
EditorGUILayout.BeginHorizontal(FGUI_Resources.HeaderBoxStyle);
|
||||
|
||||
DrawCategoryButton(TailAnimator2.ETailFeaturesCategory.Main, FGUI_Resources.Tex_Movement, "Main");
|
||||
DrawCategoryButton(TailAnimator2.ETailFeaturesCategory.Collisions, FGUI_Resources.Tex_Collider, "Collisions");
|
||||
DrawCategoryButton(TailAnimator2.ETailFeaturesCategory.IK, _TexIKIcon, "IK");
|
||||
DrawCategoryButton(TailAnimator2.ETailFeaturesCategory.Experimental, _TexDeflIcon, "Experimental");
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
GUILayout.Space(3);
|
||||
|
||||
GUILayout.BeginVertical(FGUI_Resources.ViewBoxStyle);
|
||||
|
||||
if (Get._Editor_FeaturesCategory == TailAnimator2.ETailFeaturesCategory.Main)
|
||||
{
|
||||
// Waving
|
||||
GUILayout.BeginVertical(FGUI_Resources.BGInBoxLightStyle); GUILayout.Space(5f);
|
||||
Fold_ModuleWaving();
|
||||
|
||||
GUILayout.Space(3f);
|
||||
GUILayout.EndVertical();
|
||||
|
||||
// Partial Blend
|
||||
GUILayout.BeginVertical(FGUI_Resources.BGInBoxLightStyle); GUILayout.Space(2f);
|
||||
Fold_ModulePartialBlend();
|
||||
|
||||
GUILayout.Space(2f);
|
||||
GUILayout.EndVertical();
|
||||
|
||||
// Max Distance
|
||||
GUILayout.BeginVertical(FGUI_Resources.BGInBoxStyle); GUILayout.Space(2f);
|
||||
Fold_ModuleMaxDistance();
|
||||
|
||||
GUILayout.Space(2f);
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
else if (Get._Editor_FeaturesCategory == TailAnimator2.ETailFeaturesCategory.Collisions)
|
||||
{
|
||||
// Module Collision
|
||||
GUILayout.BeginVertical(FGUI_Resources.BGInBoxStyle); GUILayout.Space(2f);
|
||||
Fold_ModuleCollisions();
|
||||
|
||||
GUILayout.Space(2f);
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
else if (Get._Editor_FeaturesCategory == TailAnimator2.ETailFeaturesCategory.IK)
|
||||
{
|
||||
// IK
|
||||
GUILayout.BeginVertical(FGUI_Resources.BGInBoxStyle); GUILayout.Space(2f);
|
||||
Fold_ModuleIK();
|
||||
|
||||
GUILayout.Space(2f);
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
else if (Get._Editor_FeaturesCategory == TailAnimator2.ETailFeaturesCategory.Experimental)
|
||||
{
|
||||
// Deflection Module
|
||||
GUILayout.BeginVertical(FGUI_Resources.BGInBoxLightStyle); GUILayout.Space(2f);
|
||||
Fold_ModuleDeflection();
|
||||
|
||||
GUILayout.Space(2f);
|
||||
GUILayout.EndVertical();
|
||||
|
||||
// Physical effectors
|
||||
GUILayout.BeginVertical(FGUI_Resources.BGInBoxLightStyle); GUILayout.Space(2f);
|
||||
Fold_ModulePhysEffectors();
|
||||
|
||||
GUILayout.Space(2f);
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
|
||||
GUILayout.Space(-5f);
|
||||
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private void Tab_DrawShaping()
|
||||
{
|
||||
FGUI_Inspector.VSpace(-2, -4);
|
||||
GUILayout.BeginVertical(FGUI_Resources.ViewBoxStyle);
|
||||
GUILayout.BeginVertical(FGUI_Resources.BGInBoxBlankStyle);
|
||||
|
||||
GUILayout.Space(2f);
|
||||
EditorGUIUtility.labelWidth = 120;
|
||||
|
||||
if (FEngineering.QIsZero(Get.RotationOffset)) GUI.color = defaultValC; else GUI.color = c;
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
Get.RotationOffset = Quaternion.Euler(EditorGUILayout.Vector3Field(new GUIContent(sp_tailRotOff.displayName, sp_tailRotOff.tooltip), FEngineering.WrapVector(Get.RotationOffset.eulerAngles)));
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
GetSelectedTailAnimators();
|
||||
for (int i = 0; i < lastSelected.Count; i++) { lastSelected[i].RotationOffset = Get.RotationOffset; new SerializedObject(lastSelected[i]).ApplyModifiedProperties(); }
|
||||
}
|
||||
|
||||
// Curving Tail
|
||||
GUILayout.Space(2f);
|
||||
if (FEngineering.QIsZero(Get.Curving) && !Get.UseCurlingCurve) GUI.color = defaultValC; else GUI.color = c;
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
Get.Curving = Quaternion.Euler(EditorGUILayout.Vector3Field(new GUIContent(sp_curving.displayName, sp_curving.tooltip), FEngineering.WrapVector(Get.Curving.eulerAngles)));
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
GetSelectedTailAnimators();
|
||||
for (int i = 0; i < lastSelected.Count; i++) { lastSelected[i].Curving = Get.Curving; new SerializedObject(lastSelected[i]).ApplyModifiedProperties(); }
|
||||
}
|
||||
|
||||
if (Get.UseCurvingCurve)
|
||||
{
|
||||
EditorGUILayout.LabelField(new GUIContent("*", "Curving offset value weight for tail segments multiplied by curve"), GUILayout.Width(9));
|
||||
EditorGUILayout.PropertyField(sp_CurvCurve, new GUIContent("", sp_curving.tooltip), GUILayout.MaxWidth(32));
|
||||
}
|
||||
else
|
||||
GUILayout.Space(4f);
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
SwitchButton(ref Get.UseCurvingCurve, "Spread curving rotation offset weight over tail segments", curveIcon);
|
||||
if (EditorGUI.EndChangeCheck()) { GetSelectedTailAnimators(); for (int i = 0; i < lastSelected.Count; i++) { lastSelected[i].UseCurvingCurve = Get.UseCurvingCurve; new SerializedObject(lastSelected[i]).ApplyModifiedProperties(); } }
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.Space(3f);
|
||||
|
||||
// Length Stretch
|
||||
if (Get.LengthMultiplier == 1f && !Get.UseLengthMulCurve) GUI.color = defaultValC; else GUI.color = c;
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
if (!Get.UseLengthMulCurve)
|
||||
{
|
||||
EditorGUILayout.PropertyField(sp_LengthMultiplier);
|
||||
GUILayout.Space(4f); EditorGUI.BeginChangeCheck();
|
||||
SwitchButton(ref Get.UseLengthMulCurve, "Spread length multiplier weight over tail segments", curveIcon);
|
||||
if (EditorGUI.EndChangeCheck()) { GetSelectedTailAnimators(); for (int i = 0; i < lastSelected.Count; i++) { lastSelected[i].UseLengthMulCurve = Get.UseLengthMulCurve; new SerializedObject(lastSelected[i]).ApplyModifiedProperties(); } }
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.PropertyField(sp_LengthMulCurve, new GUIContent(sp_LengthMultiplier.displayName, sp_LengthMultiplier.tooltip));
|
||||
GUILayout.Space(4f); EditorGUI.BeginChangeCheck();
|
||||
SwitchButton(ref Get.UseLengthMulCurve, "Spread length multiplier weight over tail segments", curveIcon);
|
||||
if (EditorGUI.EndChangeCheck()) { GetSelectedTailAnimators(); for (int i = 0; i < lastSelected.Count; i++) { lastSelected[i].UseLengthMulCurve = Get.UseLengthMulCurve; new SerializedObject(lastSelected[i]).ApplyModifiedProperties(); } }
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.Space(4);
|
||||
if (Get.OverrideKeyframeAnimation > 0f)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUIUtility.labelWidth = 180;
|
||||
EditorGUILayout.PropertyField(sp_OverrideKeyframeAnimation);
|
||||
EditorGUIUtility.labelWidth = 0;
|
||||
EditorGUILayout.LabelField(new GUIContent(FGUI_Resources.Tex_Info, "You must know what you're doing with this parameter! You making bones being not affected by keyframed animation"), GUILayout.Width(16), GUILayout.Height(16));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.color = new Color(1f, 1f, 1f, 0.7f);
|
||||
EditorGUIUtility.labelWidth = 210;
|
||||
EditorGUILayout.PropertyField(sp_OverrideKeyframeAnimation, new GUIContent(sp_OverrideKeyframeAnimation.displayName+ " (Off)", sp_OverrideKeyframeAnimation.tooltip));
|
||||
EditorGUIUtility.labelWidth = 0;
|
||||
GUI.color = c;
|
||||
}
|
||||
|
||||
GUILayout.Space(1);
|
||||
|
||||
EditorGUIUtility.labelWidth = 0;
|
||||
GUILayout.EndVertical();
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
|
||||
|
||||
private void SwitchButton(ref bool enable, string tooltip, Texture icon)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
GUI.color = enable ? new Color(0.9f, 0.9f, 0.9f, 1f) : c;
|
||||
|
||||
if (GUILayout.Button(new GUIContent(icon, tooltip), EditorStyles.miniButtonRight, new GUILayoutOption[2] { GUILayout.Width(20), GUILayout.Height(16) })) enable = !enable;
|
||||
|
||||
GUI.color = c;
|
||||
if (EditorGUI.EndChangeCheck()) { serializedObject.ApplyModifiedProperties(); }
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 34cebb73f9f145b4b90276859fe48429
|
||||
timeCreated: 1532131583
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,381 @@
|
||||
using FIMSpace.FEditor;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FIMSpace.FTail
|
||||
{
|
||||
public partial class FTailAnimator2_Editor
|
||||
{
|
||||
Transform startBone { get { return Get.StartBone; } set { Get.StartBone = value; } }
|
||||
|
||||
|
||||
protected SerializedProperty sp_SmoothingStyle;
|
||||
protected SerializedProperty sp_ReactSpeed;
|
||||
protected SerializedProperty sp_RotRelev;
|
||||
protected SerializedProperty sp_MaxStretching;
|
||||
protected SerializedProperty sp_Springiness;
|
||||
protected SerializedProperty sp_SpringinessCurling;
|
||||
protected SerializedProperty sp_Slithery;
|
||||
protected SerializedProperty sp_UpdateRate;
|
||||
protected SerializedProperty sp_StartBone;
|
||||
protected SerializedProperty sp_Sustain;
|
||||
protected SerializedProperty sp_UseWind;
|
||||
protected SerializedProperty sp_WindEffectPower;
|
||||
protected SerializedProperty sp_WindTurbulencePower;
|
||||
protected SerializedProperty sp_WindWorldNoisePower;
|
||||
protected SerializedProperty sp_Boost;
|
||||
|
||||
protected SerializedProperty sp_UpdateAsLast;
|
||||
protected SerializedProperty sp_SyncWithAnimator;
|
||||
protected SerializedProperty sp_DetectZeroKeyframes;
|
||||
protected SerializedProperty sp_StartAfterTPose;
|
||||
protected SerializedProperty sp_EndBoneJointOffset;
|
||||
|
||||
protected SerializedProperty sp_LengthMultiplier;
|
||||
protected SerializedProperty sp_Unify;
|
||||
protected SerializedProperty sp_AnimateRoll;
|
||||
protected SerializedProperty sp_Axis2D;
|
||||
protected SerializedProperty sp_smoothdelta;
|
||||
protected SerializedProperty sp_useCollision;
|
||||
protected SerializedProperty sp_collMode;
|
||||
protected SerializedProperty sp_curving;
|
||||
protected SerializedProperty sp_DynamicWorldCollidersInclusion;
|
||||
protected SerializedProperty sp_gravity;
|
||||
protected SerializedProperty sp_colScale;
|
||||
protected SerializedProperty sp_colScaleMul;
|
||||
protected SerializedProperty sp_colBoxDim;
|
||||
protected SerializedProperty sp_colDiffFact;
|
||||
protected SerializedProperty sp_colWithOther;
|
||||
protected SerializedProperty sp_colIgnored;
|
||||
protected SerializedProperty sp_colIgnored2D;
|
||||
protected SerializedProperty sp_colSameLayer;
|
||||
protected SerializedProperty sp_colCustomLayer;
|
||||
protected SerializedProperty sp_colAddRigs;
|
||||
protected SerializedProperty sp_RootRotationOffset;
|
||||
protected SerializedProperty sp_RootPositionOffset;
|
||||
protected SerializedProperty sp_CollisionSpace;
|
||||
protected SerializedProperty sp_ReflectCollision;
|
||||
protected SerializedProperty sp_DetailedCollision;
|
||||
protected SerializedProperty sp_IncludedColliders;
|
||||
protected SerializedProperty sp_RigidbodyMass;
|
||||
|
||||
protected SerializedProperty sp_AngleLimit;
|
||||
protected SerializedProperty sp_TailAnimatorAmount;
|
||||
protected SerializedProperty sp_AngleLimitAxis;
|
||||
protected SerializedProperty sp_LimitSmoothing;
|
||||
protected SerializedProperty sp_MotionInfluence;
|
||||
protected SerializedProperty sp_CollidersType;
|
||||
protected SerializedProperty sp_OptimizeWithMesh;
|
||||
|
||||
protected SerializedProperty sp_wavType;
|
||||
protected SerializedProperty sp_useWav;
|
||||
protected SerializedProperty sp_cosAd;
|
||||
protected SerializedProperty sp_wavSp;
|
||||
protected SerializedProperty sp_wavRa;
|
||||
protected SerializedProperty sp_wavAx;
|
||||
protected SerializedProperty sp_tailRotOff;
|
||||
protected SerializedProperty sp_altWave;
|
||||
protected SerializedProperty sp_AnimatePhysics;
|
||||
protected SerializedProperty sp_FixedCycle;
|
||||
protected SerializedProperty sp_CollisionSlippery;
|
||||
|
||||
protected SerializedProperty sp_UsePosSpeedCurve;
|
||||
protected SerializedProperty sp_UseRotSpeedCurve;
|
||||
protected SerializedProperty sp_UseSlitCurve;
|
||||
protected SerializedProperty sp_UseCurvingCurve;
|
||||
protected SerializedProperty sp_UseLengthMulCurve;
|
||||
protected SerializedProperty sp_UseGravCurv;
|
||||
protected SerializedProperty sp_PosCurve;
|
||||
protected SerializedProperty sp_RotCurve;
|
||||
protected SerializedProperty sp_SlitCurve;
|
||||
protected SerializedProperty sp_CurvCurve;
|
||||
protected SerializedProperty sp_LengthMulCurve;
|
||||
protected SerializedProperty sp_GravityCurve;
|
||||
protected SerializedProperty sp_InclusionRadius;
|
||||
protected SerializedProperty sp_SpringCurve;
|
||||
protected SerializedProperty sp_UseSpringCurve;
|
||||
protected SerializedProperty sp_SlipperyCurve;
|
||||
protected SerializedProperty sp_UseSlipperyCurve;
|
||||
protected SerializedProperty sp_Curling;
|
||||
protected SerializedProperty sp_CurlingCurve;
|
||||
protected SerializedProperty sp_UseCurlingCurve;
|
||||
protected SerializedProperty sp_IgnoreMeshColliders;
|
||||
protected SerializedProperty sp_CollideWithDisabledColliders;
|
||||
|
||||
protected SerializedProperty sp_BlendCurve;
|
||||
private SerializedProperty sp_DeltaType;
|
||||
|
||||
//private SerializedProperty sp_SimulationSpeed;
|
||||
private SerializedProperty sp_Optim;
|
||||
private SerializedProperty sp_Prewarm;
|
||||
|
||||
|
||||
private SerializedProperty sp_IKTarget;
|
||||
private SerializedProperty sp_IKBlend;
|
||||
private SerializedProperty sp_IKAnimatorBlend;
|
||||
private SerializedProperty sp_IKAutoWeights;
|
||||
private SerializedProperty sp_IKweightCurve;
|
||||
private SerializedProperty sp_IKAutoAngleLimit;
|
||||
private SerializedProperty sp_IKAutoAngleLimits;
|
||||
private SerializedProperty sp_IKReactionQuality;
|
||||
private SerializedProperty sp_IKSmoothing;
|
||||
private SerializedProperty sp_IKBaseReactionWeight;
|
||||
private SerializedProperty sp_IKContinous;
|
||||
private SerializedProperty sp_IKLimitSettings;
|
||||
private SerializedProperty sp_IKMaxStretching;
|
||||
private SerializedProperty sp_UseIK;
|
||||
private SerializedProperty sp_usePartialBlend;
|
||||
private SerializedProperty sp_Detach;
|
||||
|
||||
private SerializedProperty sp_Deflection;
|
||||
private SerializedProperty sp_DeflectionStartAngle;
|
||||
private SerializedProperty sp_DeflectOnlyCollisions;
|
||||
private SerializedProperty sp_DeflectionSmooth;
|
||||
private SerializedProperty sp_DeflectionFalloff;
|
||||
|
||||
private SerializedProperty sp_UseMaxDistance;
|
||||
private SerializedProperty sp_DistanceFrom;
|
||||
private SerializedProperty sp_MaximumDistance;
|
||||
private SerializedProperty sp_MaxOutDistanceFactor;
|
||||
private SerializedProperty sp_DistanceWithoutY;
|
||||
private SerializedProperty sp_DistanceMeasurePoint;
|
||||
private SerializedProperty sp_FadeDuration;
|
||||
private SerializedProperty sp_OverrideKeyframeAnimation;
|
||||
|
||||
|
||||
//private SerializedProperty sp_IKMaxStretching;
|
||||
//private SerializedProperty sp_IKStretchCurve;
|
||||
|
||||
protected virtual void OnEnable()
|
||||
{
|
||||
FGUI_Finders.ResetFinders();
|
||||
|
||||
sp_StartBone = serializedObject.FindProperty("StartBone");
|
||||
sp_SmoothingStyle = serializedObject.FindProperty("SmoothingStyle");
|
||||
sp_ReactSpeed = serializedObject.FindProperty("ReactionSpeed");
|
||||
sp_RotRelev = serializedObject.FindProperty("RotationRelevancy");
|
||||
sp_Sustain = serializedObject.FindProperty("Sustain");
|
||||
sp_MaxStretching = serializedObject.FindProperty("MaxStretching");
|
||||
sp_Springiness = serializedObject.FindProperty("Springiness");
|
||||
sp_SpringinessCurling = serializedObject.FindProperty("SpringyCurling");
|
||||
sp_Slithery = serializedObject.FindProperty("Slithery");
|
||||
sp_UpdateRate = serializedObject.FindProperty("UpdateRate");
|
||||
sp_DeltaType = serializedObject.FindProperty("DeltaType");
|
||||
sp_TailAnimatorAmount = serializedObject.FindProperty("TailAnimatorAmount");
|
||||
sp_DetectZeroKeyframes = serializedObject.FindProperty("DetectZeroKeyframes");
|
||||
sp_UpdateAsLast = serializedObject.FindProperty("UpdateAsLast");
|
||||
sp_SyncWithAnimator = serializedObject.FindProperty("SyncWithAnimator");
|
||||
sp_StartAfterTPose = serializedObject.FindProperty("StartAfterTPose");
|
||||
sp_EndBoneJointOffset = serializedObject.FindProperty("EndBoneJointOffset");
|
||||
sp_Boost = serializedObject.FindProperty("Tangle");
|
||||
sp_collMode = serializedObject.FindProperty("CollisionMode");
|
||||
|
||||
sp_AnimatePhysics = serializedObject.FindProperty("AnimatePhysics");
|
||||
sp_FixedCycle = serializedObject.FindProperty("FixedCycle");
|
||||
sp_LengthMultiplier = serializedObject.FindProperty("LengthMultiplier");
|
||||
sp_smoothdelta = serializedObject.FindProperty("SafeDeltaTime");
|
||||
sp_useCollision = serializedObject.FindProperty("UseCollision");
|
||||
sp_curving = serializedObject.FindProperty("Curving");
|
||||
sp_DynamicWorldCollidersInclusion = serializedObject.FindProperty("DynamicWorldCollidersInclusion");
|
||||
sp_gravity = serializedObject.FindProperty("Gravity");
|
||||
sp_InclusionRadius = serializedObject.FindProperty("InclusionRadius");
|
||||
sp_colScale = serializedObject.FindProperty("CollidersScaleCurve");
|
||||
sp_colScaleMul = serializedObject.FindProperty("CollidersScaleMul");
|
||||
sp_colBoxDim = serializedObject.FindProperty("BoxesDimensionsMul");
|
||||
sp_colDiffFact = serializedObject.FindProperty("CollisionsAutoCurve");
|
||||
sp_colWithOther = serializedObject.FindProperty("CollideWithOtherTails");
|
||||
sp_RigidbodyMass = serializedObject.FindProperty("RigidbodyMass");
|
||||
sp_Detach = serializedObject.FindProperty("DetachChildren");
|
||||
|
||||
|
||||
sp_colIgnored = serializedObject.FindProperty("IgnoredColliders");
|
||||
sp_colIgnored2D = serializedObject.FindProperty("IgnoredColliders2D");
|
||||
sp_Unify = serializedObject.FindProperty("UnifyBendiness");
|
||||
sp_AnimateRoll = serializedObject.FindProperty("AnimateRoll");
|
||||
sp_Axis2D = serializedObject.FindProperty("Axis2D");
|
||||
sp_colSameLayer = serializedObject.FindProperty("CollidersSameLayer");
|
||||
sp_colCustomLayer = serializedObject.FindProperty("CollidersLayer");
|
||||
sp_colAddRigs = serializedObject.FindProperty("CollidersAddRigidbody");
|
||||
sp_RootRotationOffset = serializedObject.FindProperty("RootRotationOffset");
|
||||
sp_RootPositionOffset = serializedObject.FindProperty("RootPositionOffset");
|
||||
sp_CollisionSpace = serializedObject.FindProperty("CollisionSpace");
|
||||
sp_ReflectCollision = serializedObject.FindProperty("ReflectCollision");
|
||||
sp_IncludedColliders = serializedObject.FindProperty("IncludedColliders");
|
||||
sp_DetailedCollision = serializedObject.FindProperty("CheapCollision");
|
||||
sp_IncludedColliders = serializedObject.FindProperty("IncludedColliders");
|
||||
|
||||
sp_AngleLimit = serializedObject.FindProperty("AngleLimit");
|
||||
sp_AngleLimitAxis = serializedObject.FindProperty("AngleLimitAxis");
|
||||
//sp_AngleLimitAxisTo = serializedObject.FindProperty("LimitAxisRange");
|
||||
sp_LimitSmoothing = serializedObject.FindProperty("LimitSmoothing");
|
||||
sp_MotionInfluence = serializedObject.FindProperty("MotionInfluence");
|
||||
sp_CollidersType = serializedObject.FindProperty("CollidersType");
|
||||
sp_OptimizeWithMesh = serializedObject.FindProperty("OptimizeWithMesh");
|
||||
|
||||
sp_altWave = serializedObject.FindProperty("AlternateWave");
|
||||
sp_wavType = serializedObject.FindProperty("WavingType");
|
||||
sp_useWav = serializedObject.FindProperty("UseWaving");
|
||||
sp_cosAd = serializedObject.FindProperty("CosinusAdd");
|
||||
sp_wavSp = serializedObject.FindProperty("WavingSpeed");
|
||||
sp_wavRa = serializedObject.FindProperty("WavingRange");
|
||||
sp_wavAx = serializedObject.FindProperty("WavingAxis");
|
||||
sp_tailRotOff = serializedObject.FindProperty("RotationOffset");
|
||||
sp_BlendCurve = serializedObject.FindProperty("BlendCurve");
|
||||
sp_CollisionSlippery = serializedObject.FindProperty("CollisionSlippery");
|
||||
//sp_BlendChainValue = serializedObject.FindProperty("BlendChainValue");
|
||||
//sp_BlendChainFaloff = serializedObject.FindProperty("BlendChainFaloff");
|
||||
|
||||
sp_UsePosSpeedCurve = serializedObject.FindProperty("UsePosSpeedCurve");
|
||||
sp_UseRotSpeedCurve = serializedObject.FindProperty("UseRotSpeedCurve");
|
||||
sp_UseSlitCurve = serializedObject.FindProperty("UseSlitheryCurve");
|
||||
sp_UseCurvingCurve = serializedObject.FindProperty("UseCurvingCurve");
|
||||
sp_UseLengthMulCurve = serializedObject.FindProperty("UseLengthMulCurve");
|
||||
sp_UseGravCurv = serializedObject.FindProperty("UseGravityCurve");
|
||||
sp_PosCurve = serializedObject.FindProperty("PosCurve");
|
||||
sp_RotCurve = serializedObject.FindProperty("RotCurve");
|
||||
sp_SlitCurve = serializedObject.FindProperty("SlitheryCurve");
|
||||
sp_CurvCurve = serializedObject.FindProperty("CurvCurve");
|
||||
sp_LengthMulCurve = serializedObject.FindProperty("LengthMulCurve");
|
||||
sp_InclusionRadius = serializedObject.FindProperty("InclusionRadius");
|
||||
sp_GravityCurve = serializedObject.FindProperty("GravityCurve");
|
||||
sp_SpringCurve = serializedObject.FindProperty("SpringCurve");
|
||||
sp_UseSpringCurve = serializedObject.FindProperty("UseSpringCurve");
|
||||
sp_UseSlipperyCurve = serializedObject.FindProperty("UseSlipperyCurve");
|
||||
sp_SlipperyCurve = serializedObject.FindProperty("SlipperyCurve");
|
||||
sp_UseCurlingCurve = serializedObject.FindProperty("UseCurlingCurve");
|
||||
sp_IgnoreMeshColliders = serializedObject.FindProperty("IgnoreMeshColliders");
|
||||
sp_CollideWithDisabledColliders = serializedObject.FindProperty("CollideWithDisabledColliders");
|
||||
sp_Curling = serializedObject.FindProperty("Curling");
|
||||
sp_CurlingCurve = serializedObject.FindProperty("CurlingCurve");
|
||||
sp_UseWind = serializedObject.FindProperty("UseWind");
|
||||
sp_WindEffectPower = serializedObject.FindProperty("WindEffectPower");
|
||||
sp_WindTurbulencePower = serializedObject.FindProperty("WindTurbulencePower");
|
||||
sp_WindWorldNoisePower = serializedObject.FindProperty("WindWorldNoisePower");
|
||||
//sp_SimulationSpeed = serializedObject.FindProperty("SimulationSpeed");
|
||||
sp_Optim = serializedObject.FindProperty("InterpolateRate");
|
||||
sp_Prewarm = serializedObject.FindProperty("Prewarm");
|
||||
|
||||
sp_UseIK = serializedObject.FindProperty("UseIK");
|
||||
sp_usePartialBlend = serializedObject.FindProperty("UsePartialBlend");
|
||||
sp_IKTarget = serializedObject.FindProperty("IKTarget");
|
||||
sp_IKAutoWeights = serializedObject.FindProperty("IKAutoWeights");
|
||||
sp_IKweightCurve = serializedObject.FindProperty("IKReactionWeightCurve");
|
||||
sp_IKAutoAngleLimit = serializedObject.FindProperty("IKAutoAngleLimit");
|
||||
sp_IKAutoAngleLimits = serializedObject.FindProperty("IKAutoAngleLimits");
|
||||
sp_IKReactionQuality = serializedObject.FindProperty("IKReactionQuality");
|
||||
sp_IKSmoothing = serializedObject.FindProperty("IKSmoothing");
|
||||
sp_IKMaxStretching = serializedObject.FindProperty("IKStretchToTarget");
|
||||
sp_IKBaseReactionWeight = serializedObject.FindProperty("IKBaseReactionWeight");
|
||||
sp_IKContinous = serializedObject.FindProperty("IKContinousSolve");
|
||||
//sp_IKMaxStretching = serializedObject.FindProperty("IKMaxStretching");
|
||||
//sp_IKStretchCurve = serializedObject.FindProperty("IKStretchCurve");
|
||||
sp_IKLimitSettings = serializedObject.FindProperty("IKLimitSettings");
|
||||
sp_IKBlend = serializedObject.FindProperty("IKBlend");
|
||||
sp_IKAnimatorBlend = serializedObject.FindProperty("IKAnimatorBlend");
|
||||
|
||||
sp_Deflection = serializedObject.FindProperty("Deflection");
|
||||
sp_DeflectionFalloff = serializedObject.FindProperty("DeflectionFalloff");
|
||||
sp_DeflectionSmooth = serializedObject.FindProperty("DeflectionSmooth");
|
||||
sp_DeflectionStartAngle = serializedObject.FindProperty("DeflectionStartAngle");
|
||||
sp_DeflectOnlyCollisions = serializedObject.FindProperty("DeflectOnlyCollisions");
|
||||
|
||||
sp_UseMaxDistance = serializedObject.FindProperty("UseMaxDistance");
|
||||
sp_DistanceFrom = serializedObject.FindProperty("DistanceFrom");
|
||||
sp_MaximumDistance = serializedObject.FindProperty("MaximumDistance");
|
||||
sp_MaxOutDistanceFactor = serializedObject.FindProperty("MaxOutDistanceFactor");
|
||||
sp_DistanceWithoutY = serializedObject.FindProperty("DistanceWithoutY");
|
||||
sp_DistanceMeasurePoint = serializedObject.FindProperty("DistanceMeasurePoint");
|
||||
sp_FadeDuration = serializedObject.FindProperty("FadeDuration");
|
||||
sp_OverrideKeyframeAnimation = serializedObject.FindProperty("OverrideKeyframeAnimation");
|
||||
|
||||
|
||||
FindComponents();
|
||||
Get.CheckForNullsInGhostChain();
|
||||
|
||||
// First assignment
|
||||
if (!startBone)
|
||||
{
|
||||
if (skins.Count != 0)
|
||||
{
|
||||
// If skins found ad this transform is part of any skeleton then this transform will be start bone
|
||||
bool contains = false;
|
||||
|
||||
for (int i = 0; i < skins.Count; i++)
|
||||
{
|
||||
if (contains) break;
|
||||
|
||||
for (int b = 0; b < skins[i].bones.Length; b++)
|
||||
if (skins[i].bones[b] == Get.transform)
|
||||
{ contains = true; break; }
|
||||
}
|
||||
|
||||
if (contains)
|
||||
{
|
||||
startBone = Get.transform;
|
||||
Get.GetGhostChain();
|
||||
}
|
||||
else
|
||||
{
|
||||
// If skins are found, we assigning first bone from it
|
||||
startBone = largestSkin.bones[0];
|
||||
Get.GetGhostChain();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (Get._TransformsGhostChain == null)
|
||||
{
|
||||
Get._TransformsGhostChain = new System.Collections.Generic.List<Transform>();
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
serializedObject.Update();
|
||||
}
|
||||
|
||||
|
||||
if (Get.UseIK || Get.UseWaving)
|
||||
{
|
||||
if (Get.UseWaving) drawWaving = true; else drawWaving = false;
|
||||
}
|
||||
|
||||
if (Get.UnifyBendiness > 0f || Get.Sustain > 0f)
|
||||
drawTweakAdditional = true;
|
||||
|
||||
if (((Get.ReactionSpeed >= 1f || Get.ReactionSpeed >= 0.99f) && !Get.UseRotSpeedCurve) && (Get.RotationRelevancy >= 1f && !Get.UseRotSpeedCurve))
|
||||
drawSmoothing = false;
|
||||
else
|
||||
if (Get.UseRotSpeedCurve || Get.UsePosSpeedCurve) drawSmoothing = true;
|
||||
|
||||
if (Get.UseCollision) drawCollisions = true;
|
||||
|
||||
if (Get.Deflection > Mathf.Epsilon) drawDefl = true;
|
||||
|
||||
if (Get._editor_animatorViewedCounter < 1)
|
||||
{
|
||||
Get._editor_animatorViewedCounter++;
|
||||
|
||||
if (startBone == null)
|
||||
{
|
||||
topWarning = "No skinned bones found - assign 'Start Bone'";
|
||||
topWarningAlpha = 1.5f;
|
||||
}
|
||||
else
|
||||
{
|
||||
topWarning = "Automatically found start bone - please check if it is correct one";
|
||||
topWarningAlpha = 1.85f;
|
||||
}
|
||||
}
|
||||
|
||||
SetupLangs();
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
if (hideSkin) for (int i = 0; i < skins.Count; i++)
|
||||
{
|
||||
skins[i].shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.On;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4353b07ef84cbd14faeef2a48497adf6
|
||||
timeCreated: 1532131583
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,148 @@
|
||||
using FIMSpace.FEditor;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FIMSpace.FTail
|
||||
{
|
||||
[CustomEditor(typeof(TailAnimator2))]
|
||||
[CanEditMultipleObjects]
|
||||
public partial class FTailAnimator2_Editor : Editor
|
||||
{
|
||||
[MenuItem("CONTEXT/TailAnimator2/Switch displaying header bar")]
|
||||
private static void HideFImpossibleHeader(MenuCommand menuCommand)
|
||||
{
|
||||
int current = EditorPrefs.GetInt("FTailHeader", 1);
|
||||
if (current == 1) current = 0; else current = 1;
|
||||
EditorPrefs.SetInt("FTailHeader", current);
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
//Undo.RecordObject(target, "Spine Animator Inspector");
|
||||
|
||||
serializedObject.Update();
|
||||
|
||||
TailAnimator2 Get = (TailAnimator2)target;
|
||||
string title = drawDefaultInspector ? " Default Inspector" : (" " + Get._editor_Title);
|
||||
|
||||
if (EditorPrefs.GetInt("FTailHeader", 1) == 1)
|
||||
{
|
||||
HeaderBoxMain(title, ref Get.DrawGizmos, ref drawDefaultInspector, _TexTailAnimIcon, Get, 27);
|
||||
}
|
||||
else
|
||||
GUILayout.Space(4);
|
||||
|
||||
if (drawDefaultInspector)
|
||||
DrawDefaultInspector();
|
||||
else
|
||||
DrawNewGUI();
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
void DrawCategoryButton(TailAnimator2.ETailCategory target, Texture icon, string lang)
|
||||
{
|
||||
if (Get._Editor_Category == target) GUI.backgroundColor = new Color(0.1f, 1f, 0.2f, 1f);
|
||||
|
||||
int height = 28;
|
||||
int lim = 360;
|
||||
if (choosedLang == ELangs.русский) lim = 390;
|
||||
|
||||
if (EditorGUIUtility.currentViewWidth > lim)
|
||||
{
|
||||
if (GUILayout.Button(new GUIContent(" " + Lang(lang), icon), FGUI_Resources.ButtonStyle, GUILayout.Height(height))) Get._Editor_Category = target;
|
||||
}
|
||||
else
|
||||
if (GUILayout.Button(new GUIContent(icon, Lang(lang)), FGUI_Resources.ButtonStyle, GUILayout.Height(height))) Get._Editor_Category = target;
|
||||
|
||||
GUI.backgroundColor = bc;
|
||||
}
|
||||
|
||||
void DrawCategoryButton(TailAnimator2.ETailFeaturesCategory target, Texture icon, string lang)
|
||||
{
|
||||
if (Get._Editor_FeaturesCategory == target) GUI.backgroundColor = new Color(0.1f, 1f, 0.2f, 1f);
|
||||
|
||||
int height = 24;
|
||||
int lim = 360;
|
||||
if (choosedLang == ELangs.русский) lim = 390;
|
||||
|
||||
if (EditorGUIUtility.currentViewWidth > lim)
|
||||
{
|
||||
if (GUILayout.Button(new GUIContent(" " + Lang(lang), icon), FGUI_Resources.ButtonStyle, GUILayout.Height(height))) Get._Editor_FeaturesCategory = target;
|
||||
}
|
||||
else
|
||||
if (GUILayout.Button(new GUIContent(icon, Lang(lang)), FGUI_Resources.ButtonStyle, GUILayout.Height(height))) Get._Editor_FeaturesCategory = target;
|
||||
|
||||
GUI.backgroundColor = bc;
|
||||
}
|
||||
|
||||
|
||||
void DrawNewGUI()
|
||||
{
|
||||
#region Preparations for unity versions and skin
|
||||
|
||||
c = Color.Lerp(GUI.color * new Color(0.8f, 0.8f, 0.8f, 0.7f), GUI.color, Mathf.InverseLerp(0f, 0.15f, Get.TailAnimatorAmount));
|
||||
bc = GUI.backgroundColor;
|
||||
|
||||
RectOffset zeroOff = new RectOffset(0, 0, 0, 0);
|
||||
float substr = .18f; float bgAlpha = 0.08f; if (EditorGUIUtility.isProSkin) { bgAlpha = 0.1f; substr = 0f; }
|
||||
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
int headerHeight = 22;
|
||||
#else
|
||||
int headerHeight = 25;
|
||||
#endif
|
||||
|
||||
Get._editor_IsInspectorViewingColliders = Get._Editor_FeaturesCategory == TailAnimator2.ETailFeaturesCategory.Collisions;
|
||||
Get._editor_IsInspectorViewingIncludedColliders = drawInclud && Get._editor_IsInspectorViewingColliders;
|
||||
|
||||
Get.RefreshTransformsList();
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
GUILayout.Space(2);
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
DrawCategoryButton(TailAnimator2.ETailCategory.Setup, FGUI_Resources.Tex_GearSetup, "Setup");
|
||||
DrawCategoryButton(TailAnimator2.ETailCategory.Tweak, FGUI_Resources.Tex_Sliders, "Tweak");
|
||||
DrawCategoryButton(TailAnimator2.ETailCategory.Features, FGUI_Resources.Tex_Module, "Features");
|
||||
DrawCategoryButton(TailAnimator2.ETailCategory.Shaping, FGUI_Resources.Tex_Repair, "Shaping");
|
||||
EditorGUILayout.EndHorizontal();
|
||||
GUILayout.Space(4);
|
||||
|
||||
switch (Get._Editor_Category)
|
||||
{
|
||||
case TailAnimator2.ETailCategory.Setup:
|
||||
GUILayout.BeginVertical(FGUI_Inspector.Style(zeroOff, zeroOff, new Color(.7f - substr, .7f - substr, 0.7f - substr, bgAlpha), Vector4.one * 3, 3));
|
||||
FGUI_Inspector.HeaderBox(Lang("Main Setup"), true, FGUI_Resources.Tex_GearSetup, headerHeight, headerHeight - 1, LangBig());
|
||||
Tab_DrawSetup();
|
||||
GUILayout.EndVertical();
|
||||
break;
|
||||
|
||||
case TailAnimator2.ETailCategory.Tweak:
|
||||
GUILayout.BeginVertical(FGUI_Inspector.Style(zeroOff, zeroOff, new Color(.3f - substr, .4f - substr, 1f - substr, bgAlpha), Vector4.one * 3, 3));
|
||||
FGUI_Inspector.HeaderBox(Lang("Tweak Animation"), true, FGUI_Resources.Tex_Sliders, headerHeight, headerHeight - 1, LangBig());
|
||||
Tab_DrawTweaking();
|
||||
GUILayout.EndVertical();
|
||||
break;
|
||||
|
||||
case TailAnimator2.ETailCategory.Features:
|
||||
GUILayout.BeginVertical(FGUI_Inspector.Style(zeroOff, zeroOff, new Color(.4f - substr, 1f - substr, .8f - substr, bgAlpha * 0.6f), Vector4.one * 3, 3));
|
||||
//FGUI_Inspector.HeaderBox(Lang("Additional Modules"), true, FGUI_Resources.Tex_Module, headerHeight, headerHeight - 1, LangBig());
|
||||
Tab_DrawAdditionalFeatures();
|
||||
GUILayout.EndVertical();
|
||||
break;
|
||||
|
||||
case TailAnimator2.ETailCategory.Shaping:
|
||||
GUILayout.BeginVertical(FGUI_Inspector.Style(zeroOff, zeroOff, new Color(1f - substr, .55f - substr, .55f - substr, bgAlpha * 0.5f), Vector4.one * 3, 3));
|
||||
FGUI_Inspector.HeaderBox(Lang("Additional Shaping"), true, FGUI_Resources.Tex_Repair, headerHeight, headerHeight - 1, LangBig());
|
||||
Tab_DrawShaping();
|
||||
GUILayout.EndVertical();
|
||||
break;
|
||||
}
|
||||
|
||||
GUILayout.Space(2f);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 96a57e14ee3d2d546828fba97946e597
|
||||
timeCreated: 1532131583
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 202e9deb41375844daf2c8a489b596d5
|
||||
folderAsset: yes
|
||||
timeCreated: 1532283218
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6e3d55ec0583b8f458db21ee51c4ead3
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,463 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FIMSpace.FTail
|
||||
{
|
||||
public partial class TailAnimator2
|
||||
{
|
||||
/// <summary>
|
||||
/// FM: Helper class to animate tail bones freely
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class TailSegment
|
||||
{
|
||||
public TailSegment ParentBone { get; private set; }
|
||||
public TailSegment ChildBone { get; private set; }
|
||||
|
||||
/// <summary> All references must have transform reference except GhostChild bone, GhostParent can have same transform as first bone in chain </summary>
|
||||
public Transform transform { get; private set; }
|
||||
|
||||
/// <summary> Index of bone in Tail Animator list </summary>
|
||||
public int Index { get; private set; }
|
||||
|
||||
/// <summary> For quicker value getting from curves </summary>
|
||||
public float IndexOverlLength { get; private set; }
|
||||
|
||||
/// <summary> Procedural position for tail motion without weight blending etc. </summary>
|
||||
public Vector3 ProceduralPosition = Vector3.zero;
|
||||
/// <summary> Final procedural position for tail transforms so weight blended </summary>
|
||||
public Vector3 ProceduralPositionWeightBlended = Vector3.zero;
|
||||
|
||||
/// <summary> Final rotation for tail transform so rotated towards blended position </summary>
|
||||
public Quaternion TrueTargetRotation = Quaternion.identity;
|
||||
/// <summary> Reference rotation for position offset in parent orientation used in rotation smoothing </summary>
|
||||
public Quaternion PosRefRotation = Quaternion.identity;
|
||||
/// <summary> Memory for slithery motion </summary>
|
||||
public Quaternion PreviousPosReferenceRotation = Quaternion.identity;
|
||||
|
||||
/// <summary> Memory for velocity (PreviousProceduralPosition) </summary>
|
||||
public Vector3 PreviousPosition;
|
||||
|
||||
/// <summary> Blend with tail animator motion value used in partial blending </summary>
|
||||
public float BlendValue = 1f;
|
||||
|
||||
/// <summary> Length of the bone in initial world space - distance to next bone transform </summary>
|
||||
public float BoneLength { get; private set; }
|
||||
/// <summary> Length of bone basing on intial positions / keyframe positions scaled with transform scale and length multiplier </summary>
|
||||
public Vector3 BoneDimensionsScaled;
|
||||
public float BoneLengthScaled;
|
||||
|
||||
public Vector3 InitialLocalPosition = Vector3.zero;
|
||||
public Vector3 InitialLocalPositionInRoot = Vector3.zero;
|
||||
public Quaternion InitialLocalRotationInRoot = Quaternion.identity;
|
||||
public Vector3 LocalOffset = Vector3.zero;
|
||||
public Quaternion InitialLocalRotation = Quaternion.identity;
|
||||
|
||||
// Collision related variables
|
||||
public float ColliderRadius = 1f;
|
||||
|
||||
|
||||
public bool CollisionContactFlag = false;
|
||||
public float CollisionContactRelevancy = -1f;
|
||||
public Collision collisionContacts = null;
|
||||
|
||||
// Animation styles helper variables
|
||||
public Vector3 VelocityHelper = Vector3.zero;
|
||||
public Quaternion QVelocityHelper = Quaternion.identity;
|
||||
|
||||
/// <summary> Helper variable for 'Sustain' parameter </summary>
|
||||
public Vector3 PreviousPush = Vector3.zero;
|
||||
|
||||
// Shaping
|
||||
public Quaternion Curving = Quaternion.identity;
|
||||
public Vector3 Gravity = Vector3.zero;
|
||||
public Vector3 GravityLookOffset = Vector3.zero;
|
||||
public float LengthMultiplier = 1f;
|
||||
|
||||
// Expert
|
||||
public float PositionSpeed = 1f;
|
||||
public float RotationSpeed = 1f;
|
||||
public float Springiness = 0f;
|
||||
public float Slithery = 1f;
|
||||
public float Curling = 0.5f;
|
||||
public float Slippery = 1f;
|
||||
|
||||
public TailCollisionHelper CollisionHelper { get; internal set; }
|
||||
|
||||
|
||||
#region Constructors
|
||||
|
||||
public TailSegment() { Index = -1; Curving = Quaternion.identity; Gravity = Vector3.zero; LengthMultiplier = 1f; Deflection = Vector3.zero; DeflectionFactor = 0f; DeflectionRelevancy = -1; deflectionSmoothVelo = 0f; }
|
||||
public TailSegment(Transform transform) : this()
|
||||
{
|
||||
if (transform == null) return;
|
||||
|
||||
this.transform = transform;
|
||||
|
||||
// Init position setup
|
||||
ProceduralPosition = transform.position;
|
||||
PreviousPosition = transform.position;
|
||||
PosRefRotation = transform.rotation;
|
||||
PreviousPosReferenceRotation = PosRefRotation;
|
||||
TrueTargetRotation = PosRefRotation;
|
||||
ReInitializeLocalPosRot(transform.localPosition, transform.localRotation);
|
||||
BoneLength = 0.1f;
|
||||
//ReInitializeLocalPosRot(transform.localPosition, transform.localRotation);
|
||||
}
|
||||
|
||||
public TailSegment(TailSegment copyFrom) : this(copyFrom.transform)
|
||||
{
|
||||
this.transform = copyFrom.transform;
|
||||
|
||||
// Init position setup
|
||||
Index = copyFrom.Index;
|
||||
IndexOverlLength = copyFrom.IndexOverlLength;
|
||||
|
||||
ProceduralPosition = copyFrom.ProceduralPosition;
|
||||
PreviousPosition = copyFrom.PreviousPosition;
|
||||
ProceduralPositionWeightBlended = copyFrom.ProceduralPosition;
|
||||
PosRefRotation = copyFrom.PosRefRotation;
|
||||
PreviousPosReferenceRotation = PosRefRotation;
|
||||
TrueTargetRotation = copyFrom.TrueTargetRotation;
|
||||
|
||||
ReInitializeLocalPosRot(copyFrom.InitialLocalPosition, copyFrom.InitialLocalRotation);
|
||||
}
|
||||
|
||||
|
||||
public void ReInitializeLocalPosRot(Vector3 initLocalPos, Quaternion initLocalRot)
|
||||
{
|
||||
InitialLocalPosition = initLocalPos;
|
||||
InitialLocalRotation = initLocalRot;
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
public void SetIndex(int i, int tailSegments)
|
||||
{
|
||||
Index = i;
|
||||
if (i < 0) IndexOverlLength = 0f;
|
||||
else IndexOverlLength = (float)i / (float)tailSegments;
|
||||
}
|
||||
|
||||
public void SetParentRef(TailSegment parent)
|
||||
{ ParentBone = parent; BoneLength = (ProceduralPosition - ParentBone.ProceduralPosition).magnitude; }
|
||||
|
||||
public void SetChildRef(TailSegment child)
|
||||
{ ChildBone = child; }
|
||||
|
||||
public float GetRadiusScaled()
|
||||
{ return ColliderRadius * transform.lossyScale.x; }
|
||||
|
||||
|
||||
public bool IsDetachable { get; private set; }
|
||||
public void AssignDetachedRootCoords(Transform root)
|
||||
{
|
||||
InitialLocalPositionInRoot = root.InverseTransformPoint(transform.position);
|
||||
InitialLocalRotationInRoot = FEngineering.QToLocal(root.rotation, transform.rotation);
|
||||
IsDetachable = true;
|
||||
}
|
||||
|
||||
//public static Vector3 CalculateLocalLook(Transform parent, Transform child)
|
||||
//{ return -(parent.InverseTransformPoint(child.position) - parent.InverseTransformPoint(parent.position)).normalized; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Blend toward target position
|
||||
/// </summary>
|
||||
internal Vector3 BlendMotionWeight(Vector3 newPosition)
|
||||
{
|
||||
return Vector3.LerpUnclamped
|
||||
(
|
||||
// Blending from default pose to new position
|
||||
ParentBone.ProceduralPosition + FEngineering.TransformVector(ParentBone.LastKeyframeLocalRotation, ParentBone.transform.lossyScale, LastKeyframeLocalPosition),
|
||||
newPosition,
|
||||
BlendValue
|
||||
);
|
||||
}
|
||||
|
||||
internal void PreCalibrate()
|
||||
{
|
||||
transform.localPosition = InitialLocalPosition;
|
||||
transform.localRotation = InitialLocalRotation;
|
||||
}
|
||||
|
||||
internal void Validate()
|
||||
{
|
||||
if (BoneLength == 0f) BoneLength = 0.001f;
|
||||
}
|
||||
|
||||
|
||||
#region Zero keyframe detection
|
||||
|
||||
public void RefreshKeyLocalPosition()
|
||||
{
|
||||
if (transform)
|
||||
LastKeyframeLocalRotation =(transform.localRotation);
|
||||
else
|
||||
LastKeyframeLocalRotation = (InitialLocalRotation);
|
||||
}
|
||||
|
||||
|
||||
public void RefreshKeyLocalPositionAndRotation()
|
||||
{
|
||||
if ( transform)
|
||||
RefreshKeyLocalPositionAndRotation(transform.localPosition, transform.localRotation);
|
||||
else
|
||||
RefreshKeyLocalPositionAndRotation(InitialLocalPosition, InitialLocalRotation);
|
||||
}
|
||||
|
||||
public void RefreshKeyLocalPositionAndRotation(Vector3 p, Quaternion r)
|
||||
{
|
||||
LastKeyframeLocalPosition = p;
|
||||
LastKeyframeLocalRotation = r;
|
||||
}
|
||||
|
||||
/// <summary> Initial local rotation or keyframe local rotation </summary>
|
||||
public Quaternion LastKeyframeLocalRotation;// { get { if (transform) return transform.localRotation; else return InitialLocalRotation; } }
|
||||
/// <summary> Initial local position or keyframe local position </summary>
|
||||
public Vector3 LastKeyframeLocalPosition;// { get { if (transform) return transform.localPosition; else return InitialLocalPosition; } }
|
||||
|
||||
public Vector3 LastFinalPosition { get; private set; }
|
||||
public Quaternion LastFinalRotation { get; private set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Offsset to default segment position from parent relation
|
||||
/// </summary>
|
||||
internal Vector3 ParentToFrontOffset()
|
||||
{
|
||||
return FEngineering.TransformVector
|
||||
(
|
||||
ParentBone.LastKeyframeLocalRotation,
|
||||
ParentBone.transform.lossyScale,
|
||||
LastKeyframeLocalPosition
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public void RefreshFinalPos(Vector3 pos)
|
||||
{ LastFinalPosition = pos; }
|
||||
|
||||
public void RefreshFinalRot(Quaternion rot)
|
||||
{ LastFinalRotation = rot; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Deflection feature support
|
||||
|
||||
/// <summary> Dot product of deflection angle for segment </summary>
|
||||
public float DeflectionFactor { get; private set; }
|
||||
/// <summary> Deflection direction </summary>
|
||||
public Vector3 Deflection { get; private set; }
|
||||
public float DeflectionSmooth { get; private set; }
|
||||
private float deflectionSmoothVelo; // Helper variable for smooth damp
|
||||
|
||||
/// <summary> Deflection world position </summary>
|
||||
public Vector3 DeflectionWorldPosition { get; private set; }
|
||||
/// <summary> Relevancy of deflection in list used for optimization </summary>
|
||||
public int DeflectionRelevancy { get; private set; }
|
||||
public FImp_ColliderData_Base LatestSelectiveCollision { get; internal set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Checking relation between reference position to define deflection
|
||||
/// </summary>
|
||||
public bool CheckDeflectionState(float zeroWhenLower, float smoothTime, float delta)
|
||||
{
|
||||
Vector3 deflection = LastKeyframeLocalPosition - ParentBone.transform.InverseTransformVector(ProceduralPosition - ParentBone.ProceduralPosition);
|
||||
|
||||
#region Debugging
|
||||
//deflection = LastKeyframeLocalPosition - FEngineering.TransformVector(ParentBone.ParentBone.ProceduralRotation, ParentBone.transform.lossyScale, ProceduralPosition - ParentBone.ProceduralPosition);
|
||||
//Debug.DrawRay(ParentBone.transform.position + Vector3.up * 1.1f, ParentBone.transform.TransformVector(ProceduralPosition - ParentBone.ProceduralPosition), Color.red);
|
||||
//Debug.DrawRay(ParentBone.ProceduralPosition + Vector3.up * 1.1f, FEngineering.TransformVector(ParentBone.ParentBone.ProceduralRotation, ParentBone.transform.lossyScale, ProceduralPosition - ParentBone.ProceduralPosition), new Color(1f, 0.5f, 0f, 1f) );
|
||||
#endregion
|
||||
|
||||
DeflectionFactor = Vector3.Dot(LastKeyframeLocalPosition.normalized, deflection.normalized); // Calculating factor in local space
|
||||
|
||||
#if UNITY_EDITOR // Debugging
|
||||
deflection = ChildBone.ParentBone.transform.TransformVector(deflection); // Transforming into world space offset for segments calculations
|
||||
#endif
|
||||
|
||||
// Reseting when too small angle
|
||||
if (DeflectionFactor < zeroWhenLower)
|
||||
{
|
||||
if (smoothTime <= Mathf.Epsilon)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
Deflection = Vector3.zero;
|
||||
#endif
|
||||
DeflectionSmooth = 0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
Deflection = Vector3.zero;
|
||||
#endif
|
||||
|
||||
DeflectionSmooth = Mathf.SmoothDamp(DeflectionSmooth, -Mathf.Epsilon, ref deflectionSmoothVelo, smoothTime / 1.5f, Mathf.Infinity, delta);
|
||||
}
|
||||
}
|
||||
else // Enabling or translating with smooth time
|
||||
{
|
||||
if (smoothTime <= Mathf.Epsilon)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
Deflection = deflection;
|
||||
#endif
|
||||
DeflectionSmooth = 1f;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
Deflection = deflection;
|
||||
#endif
|
||||
|
||||
DeflectionSmooth = Mathf.SmoothDamp(DeflectionSmooth, 1f, ref deflectionSmoothVelo, smoothTime, Mathf.Infinity, delta);
|
||||
}
|
||||
}
|
||||
|
||||
if (DeflectionSmooth <= Mathf.Epsilon) return true;
|
||||
else
|
||||
{
|
||||
if (ChildBone.ChildBone != null)
|
||||
DeflectionWorldPosition = ChildBone.ChildBone.ProceduralPosition;
|
||||
else
|
||||
DeflectionWorldPosition = ChildBone.ProceduralPosition;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Signing bone as deflection point relevant
|
||||
/// </summary>
|
||||
/// <returns> True when deflection just detrected </returns>
|
||||
public bool DeflectionRelevant()
|
||||
{
|
||||
if (DeflectionRelevancy == -1)
|
||||
{
|
||||
DeflectionRelevancy = 3;
|
||||
return true;
|
||||
}
|
||||
|
||||
DeflectionRelevancy = 3;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/// <returns> True when relevancy is high null when it's remove point relevancy false when it's unrelevant </returns>
|
||||
public bool? DeflectionRestoreState()
|
||||
{
|
||||
if (DeflectionRelevancy > 0)
|
||||
{
|
||||
DeflectionRelevancy--;
|
||||
|
||||
if (DeflectionRelevancy == 0) // When relevancy hit 0 then remove callback and set to -1
|
||||
{
|
||||
DeflectionRelevancy = -1;
|
||||
return null;
|
||||
}
|
||||
else return true; // True when relevancy > 0
|
||||
}
|
||||
else
|
||||
return false; // Unrelevant deflection state
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Post Processing and others
|
||||
|
||||
/// <summary>
|
||||
/// Copying animation parameters from other segment
|
||||
/// </summary>
|
||||
internal void ParamsFrom(TailSegment other)
|
||||
{
|
||||
BlendValue = other.BlendValue;
|
||||
ColliderRadius = other.ColliderRadius;
|
||||
Gravity = other.Gravity;
|
||||
LengthMultiplier = other.LengthMultiplier;
|
||||
BoneLength = other.BoneLength;
|
||||
BoneLengthScaled = other.BoneLengthScaled;
|
||||
BoneDimensionsScaled = other.BoneDimensionsScaled;
|
||||
collisionContacts = other.collisionContacts;
|
||||
CollisionHelper = other.CollisionHelper;
|
||||
|
||||
PositionSpeed = other.PositionSpeed;
|
||||
RotationSpeed = other.RotationSpeed;
|
||||
Springiness = other.Springiness;
|
||||
Slithery = other.Slithery;
|
||||
Curling = other.Curling;
|
||||
Slippery = other.Slippery;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copying all available parameters from other segment
|
||||
/// </summary>
|
||||
internal void ParamsFromAll(TailSegment other)
|
||||
{
|
||||
ParamsFrom(other);
|
||||
InitialLocalPosition = other.InitialLocalPosition;
|
||||
InitialLocalRotation = other.InitialLocalRotation;
|
||||
LastFinalPosition = other.LastFinalPosition;
|
||||
LastFinalRotation = other.LastFinalRotation;
|
||||
ProceduralPosition = other.ProceduralPosition;
|
||||
ProceduralPositionWeightBlended = other.ProceduralPositionWeightBlended;
|
||||
TrueTargetRotation = other.TrueTargetRotation;
|
||||
PosRefRotation = other.PosRefRotation;
|
||||
PreviousPosReferenceRotation = other.PreviousPosReferenceRotation;
|
||||
PreviousPosition = other.PreviousPosition;
|
||||
BoneLength = other.BoneLength;
|
||||
BoneDimensionsScaled = other.BoneDimensionsScaled;
|
||||
BoneLengthScaled = other.BoneLengthScaled;
|
||||
LocalOffset = other.LocalOffset;
|
||||
ColliderRadius = other.ColliderRadius;
|
||||
VelocityHelper = other.VelocityHelper;
|
||||
QVelocityHelper = other.QVelocityHelper;
|
||||
PreviousPush = other.PreviousPush;
|
||||
}
|
||||
|
||||
internal void User_ReassignTransform(Transform t)
|
||||
{
|
||||
transform = t;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Resetting
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
PreviousPush = Vector3.zero;
|
||||
VelocityHelper = Vector3.zero;
|
||||
QVelocityHelper = Quaternion.identity;
|
||||
|
||||
if (transform)
|
||||
{
|
||||
ProceduralPosition = transform.position;
|
||||
PosRefRotation = transform.rotation;
|
||||
PreviousPosReferenceRotation = transform.rotation;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ParentBone.transform)
|
||||
ProceduralPosition = ParentBone.transform.position + ParentToFrontOffset();
|
||||
}
|
||||
|
||||
PreviousPosition = ProceduralPosition;
|
||||
ProceduralPositionWeightBlended = ProceduralPosition;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4c0f1ecbfe3d7aa458e3e48da5898b29
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,576 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FIMSpace.FTail
|
||||
{
|
||||
public partial class TailAnimator2
|
||||
{
|
||||
public enum ECollisionSpace { World_Slow, Selective_Fast }
|
||||
public enum ECollisionMode { m_3DCollision, m_2DCollision }
|
||||
|
||||
[Tooltip("Using some simple calculations to make tail bend on colliders")]
|
||||
public bool UseCollision = false;
|
||||
|
||||
[Tooltip("How collision should be detected, world gives you collision on all world colliders but with more use of cpu (using unity's rigidbodies), 'Selective' gives you possibility to detect collision on selected colliders without using Rigidbodies, it also gives smoother motion (deactivated colliders will still detect collision, unless its game object is disabled)")]
|
||||
public ECollisionSpace CollisionSpace = ECollisionSpace.Selective_Fast;
|
||||
public ECollisionMode CollisionMode = ECollisionMode.m_3DCollision;
|
||||
|
||||
/// <summary> Available only when using dynamic world collisions inclusion mode </summary>
|
||||
public SphereCollider GeneratedDynamicInclusionCollider { get; private set; }
|
||||
/// <summary> Available only when using dynamic world collisions inclusion 2D mode </summary>
|
||||
public CircleCollider2D GeneratedDynamicInclusionCollider2D { get; private set; }
|
||||
|
||||
#region Selective Variables
|
||||
|
||||
|
||||
[Tooltip("If you want to stop checking collision if segment collides with one collider\n\nSegment collision with two or more colliders in the same time with this option enabled can result in stuttery motion")]
|
||||
public bool CheapCollision = false;
|
||||
|
||||
[Tooltip("Using trigger collider to include encountered colliders into collide with list")]
|
||||
public bool DynamicWorldCollidersInclusion = false;
|
||||
|
||||
[Tooltip("Radius of trigger collider for dynamic inclusion of colliders")]
|
||||
public float InclusionRadius = 1f;
|
||||
public bool IgnoreMeshColliders = true;
|
||||
|
||||
public List<Collider> IncludedColliders;
|
||||
public List<Collider2D> IncludedColliders2D;
|
||||
/// <summary>Colliders always included with 'Dynamic World Colliders Inclusion' mode</summary>
|
||||
public List<Component> DynamicAlwaysInclude { get; private set; }
|
||||
protected List<FImp_ColliderData_Base> IncludedCollidersData;
|
||||
|
||||
/// <summary> List of collider datas to be checked by every tail segment</summary>
|
||||
protected List<FImp_ColliderData_Base> CollidersDataToCheck;
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region World Collision Variables
|
||||
|
||||
|
||||
[Tooltip("Capsules can give much more precise collision detection")]
|
||||
public int CollidersType = 0;
|
||||
public bool CollideWithOtherTails = false;
|
||||
[Tooltip("Collision with colliders even if they're disabled (but game object must be enabled)\nHelpful to setup character limbs collisions without need to create new Layer")]
|
||||
public bool CollideWithDisabledColliders = true;
|
||||
|
||||
|
||||
[Range(0f, 1f)]
|
||||
public float CollisionSlippery = 1f;
|
||||
[Tooltip("If tail colliding objects should fit to colliders (0) or be reflect from them (Reflecting Only with 'Slithery' parameter greater than ~0.2)")]
|
||||
[Range(0f, 1f)]
|
||||
public float ReflectCollision = 0f;
|
||||
|
||||
public AnimationCurve CollidersScaleCurve = AnimationCurve.Linear(0, 1, 1, 1);
|
||||
public float CollidersScaleMul = 6.5f;
|
||||
[Range(0f, 1f)]
|
||||
public float CollisionsAutoCurve = 0.5f;
|
||||
|
||||
public List<Collider> IgnoredColliders;
|
||||
public List<Collider2D> IgnoredColliders2D;
|
||||
public bool CollidersSameLayer = true;
|
||||
[Tooltip("If you add rigidbodies to each tail segment's collider, collision will work on everything but it will be less optimal, you don't have to add here rigidbodies but then you must have not kinematic rigidbodies on objects segments can collide")]
|
||||
public bool CollidersAddRigidbody = true;
|
||||
public float RigidbodyMass = 1f;
|
||||
|
||||
[FPD_Layers]
|
||||
public int CollidersLayer = 0;
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
void RefreshSegmentsColliders()
|
||||
{
|
||||
if (CollisionSpace == ECollisionSpace.Selective_Fast)
|
||||
{
|
||||
if (TailSegments != null)
|
||||
if (TailSegments.Count > 1)
|
||||
for (int i = 0; i < TailSegments.Count; i++)
|
||||
TailSegments[i].ColliderRadius = GetColliderSphereRadiusFor(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BeginCollisionsUpdate()
|
||||
{
|
||||
if (CollisionSpace == ECollisionSpace.Selective_Fast)
|
||||
{
|
||||
RefreshIncludedCollidersDataList();
|
||||
|
||||
// Letting every tail segment check only enabled colliders by game object
|
||||
CollidersDataToCheck.Clear();
|
||||
|
||||
for (int i = 0; i < IncludedCollidersData.Count; i++)
|
||||
{
|
||||
if (IncludedCollidersData[i].Transform == null) { forceRefreshCollidersData = true; break; }
|
||||
|
||||
if (IncludedCollidersData[i].Transform.gameObject.activeInHierarchy)
|
||||
{
|
||||
|
||||
// Collisions with all even disabled colliders
|
||||
if (CollideWithDisabledColliders)
|
||||
{
|
||||
IncludedCollidersData[i].RefreshColliderData();
|
||||
CollidersDataToCheck.Add(IncludedCollidersData[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (CollisionMode == ECollisionMode.m_3DCollision)
|
||||
{
|
||||
if (IncludedCollidersData[i].Collider == null)
|
||||
{
|
||||
forceRefreshCollidersData = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// If we want to collide even with disabled colliders
|
||||
if (IncludedCollidersData[i].Collider.enabled)
|
||||
{
|
||||
IncludedCollidersData[i].RefreshColliderData();
|
||||
CollidersDataToCheck.Add(IncludedCollidersData[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( IncludedCollidersData[i].Collider2D == null)
|
||||
{
|
||||
forceRefreshCollidersData = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (IncludedCollidersData[i].Collider2D.enabled)
|
||||
{
|
||||
IncludedCollidersData[i].RefreshColliderData();
|
||||
CollidersDataToCheck.Add(IncludedCollidersData[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Generating colliders on tail with provided settings
|
||||
/// If collision space is world then rigidbody colliders are added, if selective no additional components are needed
|
||||
/// </summary>
|
||||
void SetupSphereColliders()
|
||||
{
|
||||
if (CollisionSpace == ECollisionSpace.World_Slow)
|
||||
{
|
||||
for (int i = 1; i < _TransformsGhostChain.Count; i++)
|
||||
{
|
||||
if (CollidersSameLayer) _TransformsGhostChain[i].gameObject.layer = gameObject.layer; else _TransformsGhostChain[i].gameObject.layer = CollidersLayer;
|
||||
}
|
||||
|
||||
if (CollidersType != 0)
|
||||
{
|
||||
for (int i = 1; i < _TransformsGhostChain.Count - 1; i++)
|
||||
{
|
||||
CapsuleCollider caps = _TransformsGhostChain[i].gameObject.AddComponent<CapsuleCollider>();
|
||||
|
||||
TailCollisionHelper tcol = _TransformsGhostChain[i].gameObject.AddComponent<TailCollisionHelper>().Init(CollidersAddRigidbody, RigidbodyMass);
|
||||
tcol.TailCollider = caps;
|
||||
tcol.Index = i;
|
||||
tcol.ParentTail = this;
|
||||
|
||||
caps.radius = GetColliderSphereRadiusFor(_TransformsGhostChain, i);
|
||||
caps.direction = 2;
|
||||
caps.height = (_TransformsGhostChain[i].position - _TransformsGhostChain[i + 1].position).magnitude * 2f - caps.radius;
|
||||
caps.center = _TransformsGhostChain[i].InverseTransformPoint(Vector3.Lerp(_TransformsGhostChain[i].position, _TransformsGhostChain[i + 1].position, 0.5f));
|
||||
|
||||
TailSegments[i].ColliderRadius = caps.radius;
|
||||
TailSegments[i].CollisionHelper = tcol;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 1; i < _TransformsGhostChain.Count; i++)
|
||||
{
|
||||
SphereCollider s = _TransformsGhostChain[i].gameObject.AddComponent<SphereCollider>();
|
||||
TailCollisionHelper tcol = _TransformsGhostChain[i].gameObject.AddComponent<TailCollisionHelper>().Init(CollidersAddRigidbody, RigidbodyMass);
|
||||
tcol.TailCollider = s;
|
||||
tcol.Index = i;
|
||||
tcol.ParentTail = this;
|
||||
s.radius = GetColliderSphereRadiusFor(_TransformsGhostChain, i);
|
||||
TailSegments[i].ColliderRadius = s.radius;
|
||||
TailSegments[i].CollisionHelper = tcol;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < _TransformsGhostChain.Count; i++)
|
||||
TailSegments[i].ColliderRadius = GetColliderSphereRadiusFor(i);
|
||||
|
||||
IncludedCollidersData = new List<FImp_ColliderData_Base>();
|
||||
CollidersDataToCheck = new List<FImp_ColliderData_Base>();
|
||||
|
||||
#region Dynamic inclusion preparations
|
||||
|
||||
if (DynamicWorldCollidersInclusion)
|
||||
{
|
||||
if (CollisionMode == ECollisionMode.m_3DCollision)
|
||||
for (int i = 0; i < IncludedColliders.Count; i++) DynamicAlwaysInclude.Add(IncludedColliders[i]);
|
||||
else
|
||||
for (int i = 0; i < IncludedColliders2D.Count; i++) DynamicAlwaysInclude.Add(IncludedColliders2D[i]);
|
||||
|
||||
Transform middleSegm = TailSegments[TailSegments.Count / 2].transform;
|
||||
float scaleRef = Vector3.Distance(_TransformsGhostChain[0].position, _TransformsGhostChain[_TransformsGhostChain.Count - 1].position);
|
||||
|
||||
TailCollisionHelper cHelper = middleSegm.gameObject.AddComponent<TailCollisionHelper>();
|
||||
cHelper.ParentTail = this;
|
||||
SphereCollider triggerC = null;
|
||||
CircleCollider2D triggerC2D = null;
|
||||
|
||||
if (CollisionMode == ECollisionMode.m_3DCollision)
|
||||
{
|
||||
triggerC = middleSegm.gameObject.AddComponent<SphereCollider>();
|
||||
triggerC.isTrigger = true;
|
||||
cHelper.TailCollider = triggerC;
|
||||
GeneratedDynamicInclusionCollider = triggerC;
|
||||
}
|
||||
else
|
||||
{
|
||||
triggerC2D = middleSegm.gameObject.AddComponent<CircleCollider2D>();
|
||||
triggerC2D.isTrigger = true;
|
||||
cHelper.TailCollider2D = triggerC2D;
|
||||
GeneratedDynamicInclusionCollider2D = triggerC2D;
|
||||
}
|
||||
|
||||
cHelper.Init(true, 1f, true);
|
||||
|
||||
float scale = Mathf.Abs(middleSegm.transform.lossyScale.z);
|
||||
if (scale == 0f) scale = 1f;
|
||||
if (triggerC != null) triggerC.radius = (scaleRef / scale) * InclusionRadius;
|
||||
else triggerC2D.radius = (scaleRef / scale) * InclusionRadius;
|
||||
|
||||
if (CollidersSameLayer)
|
||||
middleSegm.gameObject.layer = gameObject.layer;
|
||||
else
|
||||
middleSegm.gameObject.layer = CollidersLayer;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
RefreshIncludedCollidersDataList();
|
||||
}
|
||||
|
||||
collisionInitialized = true;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Collision data sent by single tail segment
|
||||
/// </summary>
|
||||
internal void CollisionDetection(int index, Collision collision)
|
||||
{
|
||||
TailSegments[index].collisionContacts = collision;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Exitting collision
|
||||
/// </summary>
|
||||
internal void ExitCollision(int index)
|
||||
{
|
||||
TailSegments[index].collisionContacts = null;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Use saved collision contact in right moment when uxecuting update methods
|
||||
/// </summary>
|
||||
protected bool UseCollisionContact(int index, ref Vector3 pos)
|
||||
{
|
||||
if (TailSegments[index].collisionContacts == null) return false;
|
||||
if (TailSegments[index].collisionContacts.contacts.Length == 0) return false; // In newest Unity 2018 versions 'Collision' class is generated even there are no collision contacts
|
||||
|
||||
Collision collision = TailSegments[index].collisionContacts;
|
||||
float thisCollRadius = FImp_ColliderData_Sphere.CalculateTrueRadiusOfSphereCollider(TailSegments[index].transform, TailSegments[index].ColliderRadius) * 0.95f;
|
||||
|
||||
if (collision.collider)
|
||||
{
|
||||
SphereCollider collidedSphere = collision.collider as SphereCollider;
|
||||
|
||||
// If we collide sphere we can calculate precise segment offset for it
|
||||
if (collidedSphere)
|
||||
{
|
||||
FImp_ColliderData_Sphere.PushOutFromSphereCollider(collidedSphere, thisCollRadius, ref pos, Vector3.zero);
|
||||
}
|
||||
else
|
||||
{
|
||||
CapsuleCollider collidedCapsule = collision.collider as CapsuleCollider;
|
||||
|
||||
// If we collide capsule we can calculate precise segment offset for it
|
||||
if (collidedCapsule)
|
||||
{
|
||||
FImp_ColliderData_Capsule.PushOutFromCapsuleCollider(collidedCapsule, thisCollRadius, ref pos, Vector3.zero);
|
||||
}
|
||||
else
|
||||
{
|
||||
BoxCollider collidedBox = collision.collider as BoxCollider;
|
||||
|
||||
// If we collide box we can calculate precise segment offset for it
|
||||
if (collidedBox)
|
||||
{
|
||||
if (TailSegments[index].CollisionHelper.RigBody)
|
||||
{
|
||||
if (collidedBox.attachedRigidbody)
|
||||
{
|
||||
if (TailSegments[index].CollisionHelper.RigBody.mass > 1f)
|
||||
{
|
||||
FImp_ColliderData_Box.PushOutFromBoxCollider(collidedBox, collision, thisCollRadius, ref pos);
|
||||
Vector3 pusherPos = pos;
|
||||
FImp_ColliderData_Box.PushOutFromBoxCollider(collidedBox, thisCollRadius, ref pos);
|
||||
|
||||
pos = Vector3.Lerp(pos, pusherPos, TailSegments[index].CollisionHelper.RigBody.mass / 5f);
|
||||
}
|
||||
else
|
||||
FImp_ColliderData_Box.PushOutFromBoxCollider(collidedBox, thisCollRadius, ref pos);
|
||||
}
|
||||
else
|
||||
FImp_ColliderData_Box.PushOutFromBoxCollider(collidedBox, thisCollRadius, ref pos);
|
||||
}
|
||||
else
|
||||
FImp_ColliderData_Box.PushOutFromBoxCollider(collidedBox, thisCollRadius, ref pos);
|
||||
}
|
||||
else // If we collide mesh we can't calculate very precise segment offset but we can support it in some way
|
||||
{
|
||||
MeshCollider collidedMesh = collision.collider as MeshCollider;
|
||||
if (collidedMesh)
|
||||
{
|
||||
FImp_ColliderData_Mesh.PushOutFromMeshCollider(collidedMesh, collision, thisCollRadius, ref pos);
|
||||
}
|
||||
else // If we collide terrain we can calculate very precise segment offset because terrain not rotates
|
||||
{
|
||||
TerrainCollider terrain = collision.collider as TerrainCollider;
|
||||
FImp_ColliderData_Terrain.PushOutFromTerrain(terrain, thisCollRadius, ref pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Refreshing colliders data for included colliders when it's needed
|
||||
/// </summary>
|
||||
public void RefreshIncludedCollidersDataList()
|
||||
{
|
||||
bool refr = false;
|
||||
|
||||
if (CollisionMode == ECollisionMode.m_3DCollision)
|
||||
{
|
||||
if (IncludedColliders.Count != IncludedCollidersData.Count || forceRefreshCollidersData)
|
||||
{
|
||||
IncludedCollidersData.Clear();
|
||||
|
||||
for (int i = IncludedColliders.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (IncludedColliders[i] == null) { IncludedColliders.RemoveAt(i); continue; }
|
||||
FImp_ColliderData_Base colData = FImp_ColliderData_Base.GetColliderDataFor(IncludedColliders[i]);
|
||||
IncludedCollidersData.Add(colData);
|
||||
}
|
||||
|
||||
refr = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IncludedColliders2D.Count != IncludedCollidersData.Count || forceRefreshCollidersData)
|
||||
{
|
||||
IncludedCollidersData.Clear();
|
||||
|
||||
for (int i = IncludedColliders2D.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (IncludedColliders2D[i] == null) { IncludedColliders2D.RemoveAt(i); continue; }
|
||||
FImp_ColliderData_Base colData = FImp_ColliderData_Base.GetColliderDataFor(IncludedColliders2D[i]);
|
||||
IncludedCollidersData.Add(colData);
|
||||
}
|
||||
|
||||
refr = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (refr) forceRefreshCollidersData = false;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Pushing tail segment from detected collider
|
||||
/// </summary>
|
||||
public bool PushIfSegmentInsideCollider(TailSegment bone, ref Vector3 targetPoint)
|
||||
{
|
||||
bool pushed = false;
|
||||
|
||||
if (!CheapCollision) // Detailed Collision
|
||||
{
|
||||
for (int i = 0; i < CollidersDataToCheck.Count; i++)
|
||||
{
|
||||
bool push = CollidersDataToCheck[i].PushIfInside(ref targetPoint, bone.GetRadiusScaled(), Vector3.zero);
|
||||
if (!pushed) if (push)
|
||||
{
|
||||
pushed = true;
|
||||
bone.LatestSelectiveCollision = CollidersDataToCheck[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < CollidersDataToCheck.Count; i++)
|
||||
{
|
||||
if (CollidersDataToCheck[i].PushIfInside(ref targetPoint, bone.GetRadiusScaled(), Vector3.zero))
|
||||
{
|
||||
bone.LatestSelectiveCollision = CollidersDataToCheck[i];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pushed;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Calculating automatically scale for colliders on tail, which will be automatically assigned after initialization
|
||||
/// </summary>
|
||||
protected float GetColliderSphereRadiusFor(int i)
|
||||
{
|
||||
TailSegment tailPoint = TailSegments[i];
|
||||
float refDistance = 1f;
|
||||
|
||||
if (i >= _TransformsGhostChain.Count) return refDistance;
|
||||
|
||||
if (_TransformsGhostChain.Count > 1)
|
||||
{
|
||||
refDistance = Vector3.Distance(_TransformsGhostChain[1].position, _TransformsGhostChain[0].position);
|
||||
}
|
||||
|
||||
float singleScale = refDistance;
|
||||
if (i != 0) singleScale = Mathf.Lerp(refDistance, Vector3.Distance(_TransformsGhostChain[i - 1].position, _TransformsGhostChain[i].position) * 0.5f, CollisionsAutoCurve);
|
||||
|
||||
float div = _TransformsGhostChain.Count - 1;
|
||||
if (div <= 0f) div = 1f;
|
||||
float step = 1f / div;
|
||||
|
||||
return 0.5f * singleScale * CollidersScaleMul * CollidersScaleCurve.Evaluate(step * (float)i);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Calculating automatically scale for colliders on tail, which will be automatically assigned after initialization
|
||||
/// </summary>
|
||||
protected float GetColliderSphereRadiusFor(List<Transform> transforms, int i)
|
||||
{
|
||||
float refDistance = 1f;
|
||||
if (transforms.Count > 1) refDistance = Vector3.Distance(_TransformsGhostChain[1].position, _TransformsGhostChain[0].position);
|
||||
|
||||
float nextDistance = refDistance;
|
||||
if (i != 0) nextDistance = Vector3.Distance(_TransformsGhostChain[i - 1].position, _TransformsGhostChain[i].position);
|
||||
|
||||
float singleScale = Mathf.Lerp(refDistance, nextDistance * 0.5f, CollisionsAutoCurve);
|
||||
float step = 1f / (float)(transforms.Count - 1);
|
||||
return 0.5f * singleScale * CollidersScaleMul * CollidersScaleCurve.Evaluate(step * (float)i);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Adding collider to included colliders list
|
||||
/// </summary>
|
||||
public void AddCollider(Collider collider)
|
||||
{
|
||||
if (IncludedColliders.Contains(collider)) return;
|
||||
IncludedColliders.Add(collider);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adding collider to included colliders list
|
||||
/// </summary>
|
||||
public void AddCollider(Collider2D collider)
|
||||
{
|
||||
if (IncludedColliders2D.Contains(collider)) return;
|
||||
IncludedColliders2D.Add(collider);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checking if colliders list don't have duplicates
|
||||
/// </summary>
|
||||
public void CheckForColliderDuplicatesAndNulls()
|
||||
{
|
||||
for (int i = 0; i < IncludedColliders.Count; i++)
|
||||
{
|
||||
Collider col = IncludedColliders[i];
|
||||
int count = IncludedColliders.Count(o => o == col);
|
||||
|
||||
if (count > 1)
|
||||
{
|
||||
IncludedColliders.RemoveAll(o => o == col);
|
||||
IncludedColliders.Add(col);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (int i = IncludedColliders.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (IncludedColliders[i] == null) IncludedColliders.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
public void CheckForColliderDuplicatesAndNulls2D()
|
||||
{
|
||||
for (int i = 0; i < IncludedColliders2D.Count; i++)
|
||||
{
|
||||
Collider2D col = IncludedColliders2D[i];
|
||||
int count = IncludedColliders2D.Count(o => o == col);
|
||||
|
||||
if (count > 1)
|
||||
{
|
||||
IncludedColliders2D.RemoveAll(o => o == col);
|
||||
IncludedColliders2D.Add(col);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TailCalculations_ComputeSegmentCollisions(TailSegment bone, ref Vector3 position)
|
||||
{
|
||||
// Computing collision contact timer
|
||||
if (bone.CollisionContactFlag) bone.CollisionContactFlag = false;
|
||||
else if (bone.CollisionContactRelevancy > 0f) bone.CollisionContactRelevancy -= justDelta;
|
||||
|
||||
if (CollisionSpace == ECollisionSpace.Selective_Fast)
|
||||
{
|
||||
// Setting collision contact flag
|
||||
if (PushIfSegmentInsideCollider(bone, ref position))
|
||||
{
|
||||
bone.CollisionContactFlag = true;
|
||||
bone.CollisionContactRelevancy = justDelta * 7f;
|
||||
bone.ChildBone.CollisionContactRelevancy = Mathf.Max(bone.ChildBone.CollisionContactRelevancy, justDelta * 3.5f);
|
||||
if (bone.ChildBone.ChildBone != null) bone.ChildBone.ChildBone.CollisionContactRelevancy = Mathf.Max(bone.ChildBone.CollisionContactRelevancy, justDelta * 3f);
|
||||
//bone.ParentBone.CollisionContactRelevancy = Mathf.Max(bone.ParentBone.CollisionContactRelevancy, delta * 3f);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Setting collision contact flag
|
||||
if (UseCollisionContact(bone.Index, ref position))
|
||||
{
|
||||
bone.CollisionContactFlag = true;
|
||||
bone.CollisionContactRelevancy = justDelta * 7f;
|
||||
bone.ChildBone.CollisionContactRelevancy = Mathf.Max(bone.ChildBone.CollisionContactRelevancy, justDelta * 3.5f);
|
||||
if (bone.ChildBone.ChildBone != null) bone.ChildBone.ChildBone.CollisionContactRelevancy = Mathf.Max(bone.ChildBone.CollisionContactRelevancy, justDelta * 3f);
|
||||
//bone.ParentBone.CollisionContactRelevancy = Mathf.Max(bone.ParentBone.CollisionContactRelevancy, delta * 2f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d17f10109a8683944b551359096896ac
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,195 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace FIMSpace.FTail
|
||||
{
|
||||
public partial class TailAnimator2
|
||||
{
|
||||
public bool UseSlitheryCurve = false;
|
||||
[FPD_FixedCurveWindow(0, 0f, 1f, 1.2f, .1f, 0.8f, 1f, 0.9f)]
|
||||
public AnimationCurve SlitheryCurve = AnimationCurve.EaseInOut(0f, .75f, 1f, 1f);
|
||||
float lastSlithery = -1f;
|
||||
Keyframe[] lastSlitheryCurvKeys;
|
||||
|
||||
public bool UseCurlingCurve = false;
|
||||
[FPD_FixedCurveWindow(0, 0f, 1f, 1f, .65f, 0.4f, 1f, 0.9f)]
|
||||
public AnimationCurve CurlingCurve = AnimationCurve.EaseInOut(0f, .7f, 1f, 0.3f);
|
||||
float lastCurling = -1f;
|
||||
Keyframe[] lastCurlingCurvKeys;
|
||||
|
||||
public bool UseSpringCurve = false;
|
||||
[FPD_FixedCurveWindow(0, 0, 1f, 1f, 0.9f, 0.7f, 0.2f, 0.9f)]
|
||||
public AnimationCurve SpringCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 0f);
|
||||
float lastSpringiness = -1f;
|
||||
Keyframe[] lastSpringCurvKeys;
|
||||
|
||||
public bool UseSlipperyCurve = false;
|
||||
[FPD_FixedCurveWindow(0, 0, 1f, 1f, 0.2f, 0.9f, 0.6f, 0.9f)]
|
||||
public AnimationCurve SlipperyCurve = AnimationCurve.EaseInOut(0f, .7f, 1f, 1f);
|
||||
float lastSlippery = -1f;
|
||||
Keyframe[] lastSlipperyCurvKeys;
|
||||
|
||||
public bool UsePosSpeedCurve = false;
|
||||
[FPD_FixedCurveWindow(0, 0, 1f, 1f, .2f, 1f, 0.3f, .9f)]
|
||||
public AnimationCurve PosCurve = AnimationCurve.EaseInOut(0f, .7f, 1f, 1f);
|
||||
float lastPosSpeeds = -1f;
|
||||
Keyframe[] lastPosCurvKeys;
|
||||
|
||||
public bool UseRotSpeedCurve = false;
|
||||
[FPD_FixedCurveWindow(0, 0, 1f, 1f, 0.7f, 0.7f, 0.7f, 0.9f)]
|
||||
public AnimationCurve RotCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 0.9f);
|
||||
float lastRotSpeeds = -1f;
|
||||
Keyframe[] lastRotCurvKeys;
|
||||
|
||||
|
||||
[Tooltip("Spreading Tail Animator motion weight over bones")]
|
||||
public bool UsePartialBlend = false;
|
||||
[FPD_FixedCurveWindow(0, 0, 1f, 1f, 0.2f, .5f, 0.85f)]
|
||||
public AnimationCurve BlendCurve = AnimationCurve.EaseInOut(0f, .95f, 1f, .45f);
|
||||
float lastTailAnimatorAmount = -1f;
|
||||
Keyframe[] lastBlendCurvKeys;
|
||||
TailSegment _ex_bone;
|
||||
|
||||
|
||||
void ExpertParamsUpdate()
|
||||
{
|
||||
Expert_UpdatePosSpeed();
|
||||
Expert_UpdateRotSpeed();
|
||||
Expert_UpdateSpringiness();
|
||||
Expert_UpdateSlithery();
|
||||
Expert_UpdateCurling();
|
||||
Expert_UpdateSlippery();
|
||||
Expert_UpdateBlending();
|
||||
}
|
||||
|
||||
|
||||
void ExpertCurvesEndUpdate()
|
||||
{
|
||||
lastPosSpeeds = ReactionSpeed;
|
||||
if (!UsePosSpeedCurve) if (lastPosCurvKeys != null) { lastPosCurvKeys = null; lastPosSpeeds += 0.001f; }
|
||||
|
||||
lastRotSpeeds = RotationRelevancy;
|
||||
if (!UseRotSpeedCurve) if (lastRotCurvKeys != null) { lastRotCurvKeys = null; lastRotSpeeds += 0.001f; }
|
||||
|
||||
lastSpringiness = Springiness;
|
||||
if (!UseSpringCurve) if (lastSpringCurvKeys != null) { lastSpringCurvKeys = null; lastSpringiness += 0.001f; }
|
||||
|
||||
lastSlithery = Slithery;
|
||||
if (!UseSlitheryCurve) if (lastSlitheryCurvKeys != null) { lastSlitheryCurvKeys = null; lastSlithery += 0.001f; }
|
||||
|
||||
lastCurling = Curling;
|
||||
if (!UseCurlingCurve) if (lastCurlingCurvKeys != null) { lastCurlingCurvKeys = null; lastCurling += 0.001f; }
|
||||
|
||||
lastSlippery = CollisionSlippery;
|
||||
if (!UseSlipperyCurve) if (lastSlipperyCurvKeys != null) { lastSlipperyCurvKeys = null; lastSlippery += 0.001f; }
|
||||
|
||||
lastTailAnimatorAmount = TailAnimatorAmount;
|
||||
if (!UsePartialBlend) if (lastBlendCurvKeys != null) { lastBlendCurvKeys = null; lastTailAnimatorAmount += 0.001f; }
|
||||
}
|
||||
|
||||
|
||||
void Expert_UpdatePosSpeed()
|
||||
{
|
||||
if (UsePosSpeedCurve)
|
||||
{
|
||||
//if (KeysChanged(PosCurve.keys, lastPosCurvKeys)) // for (int i = 0; i < TailBones.Count; i++) TailBones[i].PositionSpeed = GetValueFromCurve(i, PosCurve);
|
||||
{ _ex_bone = TailSegments[0]; while (_ex_bone != null) { _ex_bone.PositionSpeed = PosCurve.Evaluate(_ex_bone.IndexOverlLength); _ex_bone = _ex_bone.ChildBone; } }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (lastPosSpeeds != ReactionSpeed) // for (int i = 0; i < TailBones.Count; i++) TailBones[i].PositionSpeed = ReactionSpeed;
|
||||
{ _ex_bone = TailSegments[0]; while (_ex_bone != null) { _ex_bone.PositionSpeed = ReactionSpeed; _ex_bone = _ex_bone.ChildBone; } }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Expert_UpdateRotSpeed()
|
||||
{
|
||||
if (UseRotSpeedCurve)
|
||||
{
|
||||
//if (KeysChanged(RotCurve.keys, lastRotCurvKeys)) //for (int i = 0; i < TailBones.Count; i++) TailBones[i].RotationSpeed = GetValueFromCurve(i, RotCurve);
|
||||
{ _ex_bone = TailSegments[0]; while (_ex_bone != null) { _ex_bone.RotationSpeed = RotCurve.Evaluate(_ex_bone.IndexOverlLength); _ex_bone = _ex_bone.ChildBone; } }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (lastRotSpeeds != RotationRelevancy) //for (int i = 0; i < TailBones.Count; i++) TailBones[i].RotationSpeed = RotationRelevancy;
|
||||
{ _ex_bone = TailSegments[0]; while (_ex_bone != null) { _ex_bone.RotationSpeed = RotationRelevancy; _ex_bone = _ex_bone.ChildBone; } }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Expert_UpdateSpringiness()
|
||||
{
|
||||
if (UseSpringCurve)
|
||||
{
|
||||
//if (KeysChanged(SpringCurve.keys, lastSpringCurvKeys)) //for (int i = 0; i < TailBones.Count; i++) TailBones[i].Springiness = GetValueFromCurve(i, SpringCurve);
|
||||
{ _ex_bone = TailSegments[0]; while (_ex_bone != null) { _ex_bone.Springiness = SpringCurve.Evaluate(_ex_bone.IndexOverlLength); _ex_bone = _ex_bone.ChildBone; } }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (lastSpringiness != Springiness) //for (int i = 0; i < TailBones.Count; i++) TailBones[i].Springiness = Springiness;
|
||||
{ _ex_bone = TailSegments[0]; while (_ex_bone != null) { _ex_bone.Springiness = Springiness; _ex_bone = _ex_bone.ChildBone; } }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Expert_UpdateSlithery()
|
||||
{
|
||||
if (UseSlitheryCurve)
|
||||
{
|
||||
//if (KeysChanged(SlitheryCurve, lastSlitheryCurvKeys)) //for (int i = 0; i < TailBones.Count; i++) TailBones[i].Slithery = GetValueFromCurve(i, SlitheryCurve);
|
||||
{ _ex_bone = TailSegments[0]; while (_ex_bone != null) { _ex_bone.Slithery = SlitheryCurve.Evaluate(_ex_bone.IndexOverlLength); _ex_bone = _ex_bone.ChildBone; } }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (lastSlithery != Slithery)
|
||||
{ _ex_bone = TailSegments[0]; while (_ex_bone != null) { _ex_bone.Slithery = Slithery; _ex_bone = _ex_bone.ChildBone; } }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Expert_UpdateCurling()
|
||||
{
|
||||
if (UseCurlingCurve)
|
||||
{
|
||||
//if (KeysChanged(CurlingCurve.keys, lastCurlingCurvKeys)) //for (int i = 0; i < TailBones.Count; i++) TailBones[i].Curling = GetValueFromCurve(i, CurlingCurve);
|
||||
{ _ex_bone = TailSegments[0]; while (_ex_bone != null) { _ex_bone.Curling = CurlingCurve.Evaluate(_ex_bone.IndexOverlLength); _ex_bone = _ex_bone.ChildBone; } }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (lastCurling != Curling)
|
||||
{ _ex_bone = TailSegments[0]; while (_ex_bone != null) { _ex_bone.Curling = Curling; _ex_bone = _ex_bone.ChildBone; } }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Expert_UpdateSlippery()
|
||||
{
|
||||
if (UseSlipperyCurve)
|
||||
{
|
||||
//if (KeysChanged(SlipperyCurve.keys, lastSlipperyCurvKeys)) //for (int i = 0; i < TailBones.Count; i++) TailBones[i].Slippery = GetValueFromCurve(i, SlipperyCurve);
|
||||
{ _ex_bone = TailSegments[0]; while (_ex_bone != null) { _ex_bone.Slippery = SlipperyCurve.Evaluate(_ex_bone.IndexOverlLength); _ex_bone = _ex_bone.ChildBone; } }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (lastSlippery != CollisionSlippery) //for (int i = 0; i < TailBones.Count; i++) TailBones[i].Slippery = CollisionSlippery;
|
||||
{ _ex_bone = TailSegments[0]; while (_ex_bone != null) { _ex_bone.Slippery = CollisionSlippery; _ex_bone = _ex_bone.ChildBone; } }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Expert_UpdateBlending()
|
||||
{
|
||||
if (UsePartialBlend)
|
||||
{
|
||||
//if (KeysChanged(BlendCurve.keys, lastBlendCurvKeys)) // for (int i = 0; i < TailBones.Count; i++) TailBones[i].BlendValue = GetValueFromCurve(i, BlendCurve);//Mathf.Clamp(Mathf.Pow(GetValueFromCurve(i, BlendCurve), .3f /*3*/), 0f, 1.5f);
|
||||
{ _ex_bone = TailSegments[0]; while (_ex_bone != null) { _ex_bone.BlendValue = BlendCurve.Evaluate(_ex_bone.IndexOverlLength); _ex_bone = _ex_bone.ChildBone; } }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (lastTailAnimatorAmount != TailAnimatorAmount)
|
||||
{ _ex_bone = TailSegments[0]; while (_ex_bone != null) { _ex_bone.BlendValue = TailAnimatorAmount; _ex_bone = _ex_bone.ChildBone; } }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 18157dba56a9a3f42a851b679615af5d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,236 @@
|
||||
using FIMSpace.FTools;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FIMSpace.FTail
|
||||
{
|
||||
public partial class TailAnimator2
|
||||
{
|
||||
// IK Definition
|
||||
public bool UseIK = false;
|
||||
bool ikInitialized = false;
|
||||
[SerializeField] FIK_CCDProcessor IK;
|
||||
|
||||
// IK Parameters
|
||||
[Tooltip("Target object to follow by IK")]
|
||||
public Transform IKTarget;
|
||||
[Tooltip("Making end bone be rotated as IK target object")]
|
||||
[Range(0f, 1f)] public float IKAlignEndWithTarget = 0f;
|
||||
|
||||
public bool IKAutoWeights = true;
|
||||
[Range(0f, 1f)]
|
||||
public float IKBaseReactionWeight = .65f;
|
||||
[FPD_FixedCurveWindow(0, 0, 1f, 1f, 0.2f, .5f, 0.85f)]
|
||||
public AnimationCurve IKReactionWeightCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, .25f);
|
||||
|
||||
public bool IKAutoAngleLimits = true;
|
||||
//[Range(0f, 181f)]
|
||||
[FPD_Suffix(0, 181, FPD_SuffixAttribute.SuffixMode.FromMinToMaxRounded, "°")]
|
||||
public float IKAutoAngleLimit = 40f;
|
||||
[Tooltip("If ik process should work referencing to previously computed CCDIK pose (can be more precise but need more adjusting in weights and angle limits)")]
|
||||
public bool IKContinousSolve = false;
|
||||
[Tooltip("Inverting ik iteration order to generate different pose results - more straight towards target")]
|
||||
public bool IkInvertOrder = false;
|
||||
|
||||
[FPD_Suffix(0f, 1f)]
|
||||
[Tooltip("How much IK motion sohuld be used in tail animator motion -> 0: turned off")]
|
||||
public float IKBlend = 1f;
|
||||
[FPD_Suffix(0f, 1f)]
|
||||
[Tooltip("If syncing with animator then applying motion of keyframe animation for IK")]
|
||||
public float IKAnimatorBlend = 0.5f;
|
||||
|
||||
[Range(1, 32)]
|
||||
[Tooltip("How much iterations should do CCDIK algorithm in one frame")]
|
||||
public int IKReactionQuality = 2;
|
||||
[Range(0f, 1f)]
|
||||
[Tooltip("Smoothing reactions in CCD IK algorithm")]
|
||||
public float IKSmoothing = .0f;
|
||||
[Range(0f, 1.5f)]
|
||||
public float IKStretchToTarget = 0f;
|
||||
[FPD_FixedCurveWindow(0, 0, 1f, 1f, 0.9f, .4f, 0.5f)]
|
||||
public AnimationCurve IKStretchCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);
|
||||
|
||||
public List<IKBoneSettings> IKLimitSettings;
|
||||
public bool IKSelectiveChain = false;
|
||||
|
||||
void InitIK()
|
||||
{
|
||||
if (IKSelectiveChain == false)
|
||||
IK = new FIK_CCDProcessor(_TransformsGhostChain.ToArray());
|
||||
else
|
||||
{
|
||||
List<Transform> ikChain = new List<Transform>();
|
||||
if (IKLimitSettings.Count != _TransformsGhostChain.Count) ikChain = _TransformsGhostChain;
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < _TransformsGhostChain.Count; i++)
|
||||
{
|
||||
if (IKLimitSettings[i].UseInChain)
|
||||
ikChain.Add(_TransformsGhostChain[i]);
|
||||
}
|
||||
}
|
||||
|
||||
IK = new FIK_CCDProcessor(ikChain.ToArray());
|
||||
}
|
||||
|
||||
if (IKAutoWeights) IK.AutoWeightBones(IKBaseReactionWeight); else IK.AutoWeightBones(IKReactionWeightCurve);
|
||||
if (IKAutoAngleLimits) IK.AutoLimitAngle(IKAutoAngleLimit, 4f + IKAutoAngleLimit / 15f);
|
||||
|
||||
if (IKSelectiveChain == false)
|
||||
IK.Init(_TransformsGhostChain[0]);
|
||||
else
|
||||
IK.Init(IK.Bones[0].transform);
|
||||
|
||||
ikInitialized = true;
|
||||
|
||||
IK_ApplyLimitBoneSettings();
|
||||
}
|
||||
|
||||
|
||||
Vector3? _IKCustomPos = null;
|
||||
public void IKSetCustomPosition(Vector3? tgt)
|
||||
{
|
||||
_IKCustomPos = tgt;
|
||||
}
|
||||
|
||||
void UpdateIK()
|
||||
{
|
||||
if (!ikInitialized) InitIK();
|
||||
if (IKBlend <= Mathf.Epsilon) return;
|
||||
|
||||
if (_IKCustomPos != null) IK.IKTargetPosition = _IKCustomPos.Value;
|
||||
else
|
||||
{
|
||||
if (IKTarget == null) IK.IKTargetPosition = TailSegments[TailSegments.Count - 1].ProceduralPosition;
|
||||
else IK.IKTargetPosition = IKTarget.position;
|
||||
}
|
||||
|
||||
IK.Invert = IkInvertOrder;
|
||||
IK.IKWeight = IKBlend;
|
||||
IK.SyncWithAnimator = IKAnimatorBlend; //else IK.SyncWithAnimator = 0f;
|
||||
IK.ReactionQuality = IKReactionQuality;
|
||||
IK.Smoothing = IKSmoothing;
|
||||
IK.StretchToTarget = IKStretchToTarget;
|
||||
IK.StretchCurve = IKStretchCurve;
|
||||
IK.ContinousSolving = IKContinousSolve;
|
||||
if (IK.StretchToTarget > 0f) IK.ContinousSolving = false;
|
||||
if (Axis2D == 3) IK.Use2D = true; else IK.Use2D = false;
|
||||
|
||||
IK.Update();
|
||||
|
||||
if (IKAlignEndWithTarget > 0f && IKTarget != null && IK.Bones.Length > 1)
|
||||
{
|
||||
var lastBone = IK.Bones[IK.Bones.Length - 1];
|
||||
|
||||
#region Old faster code but for two axes only
|
||||
|
||||
//Quaternion targetRotation = Quaternion.FromToRotation((lastBone.transform.position - lastBone.transform.parent.position).normalized, IKTarget.forward);
|
||||
//targetRotation = targetRotation * lastBone.transform.rotation;
|
||||
//if (IKAlignEndWithTarget < 1f) targetRotation = Quaternion.Slerp(lastBone.transform.rotation, targetRotation, IKAlignEndWithTarget);
|
||||
//lastBone.transform.rotation = targetRotation;
|
||||
|
||||
#endregion
|
||||
|
||||
Vector3 boneForward = (lastBone.transform.position - lastBone.transform.parent.position).normalized;
|
||||
Vector3 boneUp = lastBone.transform.up;
|
||||
Vector3 targetForward = IKTarget.forward;
|
||||
Vector3 targetUp = IKTarget.up;
|
||||
|
||||
Quaternion boneRot = Quaternion.LookRotation(boneForward, boneUp);
|
||||
Quaternion targetRot = Quaternion.LookRotation(targetForward, targetUp);
|
||||
Quaternion delta = targetRot * Quaternion.Inverse(boneRot);
|
||||
|
||||
Quaternion finalRot = delta * lastBone.transform.rotation;
|
||||
if (IKAlignEndWithTarget < 1f) finalRot = Quaternion.Slerp(lastBone.transform.rotation, finalRot, IKAlignEndWithTarget);
|
||||
lastBone.transform.rotation = finalRot;
|
||||
}
|
||||
|
||||
if (DetachChildren)
|
||||
{
|
||||
TailSegment child = TailSegments[0];
|
||||
|
||||
child = TailSegments[1];
|
||||
if (IncludeParent == false)
|
||||
{
|
||||
child.RefreshKeyLocalPositionAndRotation(child.InitialLocalPosition, child.InitialLocalRotation);
|
||||
child = TailSegments[2];
|
||||
}
|
||||
|
||||
while (child != GhostChild)
|
||||
{
|
||||
child.RefreshKeyLocalPositionAndRotation(child.InitialLocalPosition, child.InitialLocalRotation);
|
||||
child = child.ChildBone;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TailSegment child = TailSegments[0];
|
||||
while (child != GhostChild)
|
||||
{
|
||||
child.RefreshKeyLocalPositionAndRotation();
|
||||
child = child.ChildBone;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// FC: Helper class to manage ik bones settings
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class IKBoneSettings
|
||||
{
|
||||
[Range(0f, 181f)]
|
||||
public float AngleLimit = 45f;
|
||||
[Range(0f, 181f)]
|
||||
public float TwistAngleLimit = 5f;
|
||||
|
||||
public bool UseInChain = true;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Applying changes to IK bones only when changes occuring
|
||||
/// </summary>
|
||||
public void IK_ApplyLimitBoneSettings()
|
||||
{
|
||||
if (!IKAutoAngleLimits)
|
||||
{
|
||||
if (IKLimitSettings.Count != _TransformsGhostChain.Count)
|
||||
IK_RefreshLimitSettingsContainer();
|
||||
|
||||
if (IK.IKBones.Length != IKLimitSettings.Count)
|
||||
{
|
||||
Debug.Log("[TAIL ANIMATOR IK] Wrong IK bone count!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IKAutoAngleLimits)
|
||||
{
|
||||
for (int i = 0; i < IKLimitSettings.Count; i++)
|
||||
{
|
||||
IK.IKBones[i].AngleLimit = IKLimitSettings[i].AngleLimit;
|
||||
IK.IKBones[i].TwistAngleLimit = IKLimitSettings[i].TwistAngleLimit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ikInitialized) if (IKAutoWeights) IK.AutoWeightBones(IKBaseReactionWeight); else IK.AutoWeightBones(IKReactionWeightCurve);
|
||||
if (IKAutoAngleLimits) IK.AutoLimitAngle(IKAutoAngleLimit, 10f + IKAutoAngleLimit / 10f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generating new IK Limit Settings list with the same length as ghost transforms chain
|
||||
/// </summary>
|
||||
public void IK_RefreshLimitSettingsContainer()
|
||||
{
|
||||
IKLimitSettings = new List<IKBoneSettings>();
|
||||
for (int i = 0; i < _TransformsGhostChain.Count; i++)
|
||||
{
|
||||
IKLimitSettings.Add(new IKBoneSettings());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: adf0396b6095c7c4f93a78f8ee022984
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,114 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FIMSpace.FTail
|
||||
{
|
||||
// Positions Post Processing support calculations for effects like deflection
|
||||
// which needs baked position to correctly detect needed stuff for
|
||||
// every frame update
|
||||
public partial class TailAnimator2
|
||||
{
|
||||
/// <summary> Always return chain with coordinates without any POST processes as reference for POST processing algorithms. Separated list of tail bones operating on the same transforms but without post processed coords </summary>
|
||||
private List<TailSegment> _pp_reference;
|
||||
|
||||
// Artificial bone points bakery
|
||||
private TailSegment _pp_ref_rootParent;
|
||||
private TailSegment _pp_ref_lastChild;
|
||||
|
||||
private bool _pp_initialized = false;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Return true if Tail Aniamtor is using feature which requires post processing support
|
||||
/// </summary>
|
||||
bool PostProcessingNeeded()
|
||||
{
|
||||
if (Deflection > Mathf.Epsilon) return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Post processing start frame calculations
|
||||
/// </summary>
|
||||
void PostProcessing_Begin()
|
||||
{
|
||||
TailSegments_UpdateCoordsForRootBone(_pp_reference[_tc_startI]);
|
||||
|
||||
// Deflection support
|
||||
if (Deflection > Mathf.Epsilon) Deflection_BeginUpdate();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Computing reference coordinates for POST processing
|
||||
/// </summary>
|
||||
void PostProcessing_ReferenceUpdate()
|
||||
{
|
||||
TailSegment child = _pp_reference[_tc_startI];
|
||||
|
||||
#region Prepare base positions calculation for tail segments to use in coords calculations and as reference
|
||||
|
||||
|
||||
while (child != _pp_ref_lastChild)
|
||||
{
|
||||
child.ParamsFrom(TailSegments[child.Index]); // Copying parameters settings from true bones
|
||||
TailSegment_PrepareVelocity(child);
|
||||
child = child.ChildBone;
|
||||
}
|
||||
|
||||
// Udpate for artificial end bone
|
||||
TailSegment_PrepareMotionParameters(_pp_ref_lastChild);
|
||||
TailSegment_PrepareVelocity(_pp_ref_lastChild);
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Processing segments, calculating full target coords and apply to transforms
|
||||
|
||||
child = _pp_reference[_tc_startII];
|
||||
|
||||
if (!DetachChildren)
|
||||
{
|
||||
while (child != _pp_ref_lastChild)
|
||||
{
|
||||
TailSegment_PrepareRotation(child);
|
||||
TailSegment_BaseSwingProcessing(child);
|
||||
TailCalculations_SegmentPreProcessingStack(child);
|
||||
TailSegment_PreRotationPositionBlend(child);
|
||||
child = child.ChildBone;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (child != _pp_ref_lastChild)
|
||||
{
|
||||
TailSegment_PrepareRotationDetached(child);
|
||||
TailSegment_BaseSwingProcessing(child);
|
||||
TailCalculations_SegmentPreProcessingStack(child);
|
||||
TailSegment_PreRotationPositionBlend(child);
|
||||
child = child.ChildBone;
|
||||
}
|
||||
}
|
||||
|
||||
// Applying processing for artificial child bone without transform
|
||||
TailCalculations_UpdateArtificialChildBone(_pp_ref_lastChild);
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
child = _pp_reference[_tc_startII];
|
||||
while (child != _pp_ref_lastChild)
|
||||
{
|
||||
// Calculate rotation
|
||||
TailCalculations_SegmentRotation(child, child.LastKeyframeLocalPosition);
|
||||
child = child.ChildBone;
|
||||
}
|
||||
|
||||
// If ghost child has transform let's apply motion too (change rotation of last bone)
|
||||
TailCalculations_SegmentRotation(child, child.LastKeyframeLocalPosition);
|
||||
child.ParentBone.RefreshFinalRot(child.ParentBone.TrueTargetRotation);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9655b675af6b2334ea694f30ff189f44
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,154 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace FIMSpace.FTail
|
||||
{
|
||||
public partial class TailAnimator2
|
||||
{
|
||||
[Tooltip("Rotation offset for tail (just first (root) bone is rotated)")]
|
||||
public Quaternion RotationOffset = Quaternion.identity;
|
||||
|
||||
|
||||
[Tooltip("Rotate each segment a bit to create curving effect")]
|
||||
public Quaternion Curving = Quaternion.identity;
|
||||
[Tooltip("Spread curving rotation offset weight over tail segments")]
|
||||
public bool UseCurvingCurve = false;
|
||||
[FPD_FixedCurveWindow(0f, -1f, 1f, 1f, 0.75f, .75f, 0.75f, 0.85f)]
|
||||
public AnimationCurve CurvCurve = AnimationCurve.EaseInOut(0f, 0.75f, 1f, 1f);
|
||||
Quaternion lastCurving = Quaternion.identity;
|
||||
Keyframe[] lastCurvingKeys;
|
||||
|
||||
[Tooltip("Make tail longer or shorter")]
|
||||
public float LengthMultiplier = 1f;
|
||||
[Tooltip("Spread length multiplier weight over tail segments")]
|
||||
public bool UseLengthMulCurve = false;
|
||||
[FPD_FixedCurveWindow(0, 0, 1f, 3f)]
|
||||
public AnimationCurve LengthMulCurve = AnimationCurve.EaseInOut(0f, 1f, 1f, 1f);
|
||||
float lastLengthMul = 1f;
|
||||
Keyframe[] lastLengthKeys;
|
||||
|
||||
[Tooltip("Spread gravity weight over tail segments")]
|
||||
public bool UseGravityCurve = false;
|
||||
[FPD_FixedCurveWindow(0, 0, 1f, 1f, 0.85f, .35f, 0.25f, 0.85f)]
|
||||
[Tooltip("Spread gravity weight over tail segments")]
|
||||
public AnimationCurve GravityCurve = AnimationCurve.EaseInOut(0f, .65f, 1f, 1f);
|
||||
[Tooltip("Simulate gravity weight for tail logics")]
|
||||
public Vector3 Gravity = Vector3.zero;
|
||||
Vector3 lastGravity = Vector3.zero;
|
||||
Keyframe[] lastGravityKeys;
|
||||
|
||||
|
||||
void ShapingParamsUpdate()
|
||||
{
|
||||
Shaping_UpdateCurving();
|
||||
Shaping_UpdateGravity();
|
||||
Shaping_UpdateLengthMultiplier();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Shaping_UpdateCurving()
|
||||
{
|
||||
if (!FEngineering.QIsZero(Curving))
|
||||
{
|
||||
if (UseCurvingCurve) // Operations with curve
|
||||
{
|
||||
_ex_bone = TailSegments[0];
|
||||
while (_ex_bone != null) { _ex_bone.Curving = Quaternion.LerpUnclamped(Quaternion.identity, Curving, CurvCurve.Evaluate(_ex_bone.IndexOverlLength)); _ex_bone = _ex_bone.ChildBone; }
|
||||
}
|
||||
else // Operations without curve
|
||||
{
|
||||
if (!FEngineering.QIsSame(Curving, lastCurving))
|
||||
for (int i = 0; i < TailSegments.Count; i++) TailSegments[i].Curving = Curving;
|
||||
}
|
||||
}
|
||||
else // Curving reset
|
||||
{
|
||||
if (!FEngineering.QIsSame(Curving, lastCurving))
|
||||
for (int i = 0; i < TailSegments.Count; i++) TailSegments[i].Curving = Quaternion.identity;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Shaping_UpdateGravity()
|
||||
{
|
||||
if (!FEngineering.VIsZero(Gravity))
|
||||
{
|
||||
if (UseGravityCurve) // Operations with curve
|
||||
{
|
||||
//if (!FEngineering.VIsSame(Gravity, lastGravity) || KeysChanged(GravityCurve.keys, lastGravityKeys))
|
||||
//{
|
||||
// for (int i = 0; i < TailSegments.Count; i++)
|
||||
// {
|
||||
// TailSegments[i].Gravity = Gravity * GetValueFromCurve(i, GravityCurve) / 40f;
|
||||
// TailSegments[i].Gravity *= (1 + ((TailSegments[i].Index / 2f) * (1f - TailSegments[i].Slithery)));
|
||||
// }
|
||||
//}
|
||||
|
||||
_ex_bone = TailSegments[0];
|
||||
while (_ex_bone != null) { _ex_bone.Gravity = Gravity * 40f * GravityCurve.Evaluate(_ex_bone.IndexOverlLength); _ex_bone = _ex_bone.ChildBone; }
|
||||
}
|
||||
else // Operations without curve
|
||||
{
|
||||
if (!FEngineering.VIsSame(Gravity, lastGravity))
|
||||
for (int i = 0; i < TailSegments.Count; i++)
|
||||
{
|
||||
TailSegments[i].Gravity = Gravity / 40f;
|
||||
TailSegments[i].Gravity *= (1 + ((TailSegments[i].Index / 2f) * (1f - TailSegments[i].Slithery)));
|
||||
}
|
||||
}
|
||||
}
|
||||
else // Gravity reset
|
||||
{
|
||||
if (!FEngineering.VIsSame(Gravity, lastGravity))
|
||||
{
|
||||
for (int i = 0; i < TailSegments.Count; i++)
|
||||
{
|
||||
TailSegments[i].Gravity = Vector3.zero;
|
||||
TailSegments[i].GravityLookOffset = Vector3.zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Shaping_UpdateLengthMultiplier()
|
||||
{
|
||||
if (UseLengthMulCurve)
|
||||
{
|
||||
//if (lastLengthMul != LengthMultiplier || KeysChanged(LengthMulCurve.keys, lastLengthKeys))
|
||||
//{
|
||||
// for (int i = 0; i < TailSegments.Count; i++) TailSegments[i].LengthMultiplier = /*LengthMultiplier */ GetValueFromCurve(i, LengthMulCurve);
|
||||
//}
|
||||
|
||||
_ex_bone = TailSegments[0];
|
||||
while (_ex_bone != null) { _ex_bone.LengthMultiplier = LengthMulCurve.Evaluate(_ex_bone.IndexOverlLength); _ex_bone = _ex_bone.ChildBone; }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (lastLengthMul != LengthMultiplier)
|
||||
for (int i = 0; i < TailSegments.Count; i++) TailSegments[i].LengthMultiplier = LengthMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Remembering previous parameters to avoid triggering full tail iterations every frame
|
||||
/// </summary>
|
||||
void ShapingEndUpdate()
|
||||
{
|
||||
lastCurving = Curving;
|
||||
if (!UseCurvingCurve) if (lastCurvingKeys != null) { lastCurvingKeys = null; lastCurving.x += 0.001f; }
|
||||
//if (UseCurvingCurve) lastCurvingKeys = CurvCurve.keys; else if (lastCurvingKeys != null) { lastCurvingKeys = null; lastCurving.x += 0.001f; }
|
||||
|
||||
lastGravity = Gravity;
|
||||
if (!UseGravityCurve) if (lastGravityKeys != null) { lastGravityKeys = null; lastGravity.x += 0.001f; }
|
||||
//if (UseGravityCurve) lastGravityKeys = GravityCurve.keys; else if (lastGravityKeys != null) { lastGravityKeys = null; lastGravity.x += 0.001f; }
|
||||
|
||||
lastLengthMul = LengthMultiplier;
|
||||
if (!UseLengthMulCurve) if (lastLengthKeys != null) { lastLengthKeys = null; lastLengthMul += 0.0001f; }
|
||||
//if (UseLengthMulCurve) lastLengthKeys = LengthMulCurve.keys; else if (lastLengthKeys != null) { lastLengthKeys = null; lastLengthMul += 0.0001f; }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9d872664813634c49b522c82ee361f4c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,165 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace FIMSpace.FTail
|
||||
{
|
||||
public partial class TailAnimator2
|
||||
{
|
||||
|
||||
#region Inspector Variables
|
||||
|
||||
[Tooltip("Using auto waving option to give floating effect")]
|
||||
public bool UseWaving = true;
|
||||
|
||||
[Tooltip("Adding some variation to waving animation")]
|
||||
public bool CosinusAdd = false;
|
||||
|
||||
[Tooltip("If you want few tails to wave in the same way you can set this sinus period cycle value")]
|
||||
public float FixedCycle = 0f;
|
||||
|
||||
[Tooltip("How frequent swings should be")]
|
||||
public float WavingSpeed = 3f;
|
||||
[Tooltip("How big swings should be")]
|
||||
public float WavingRange = 0.8f;
|
||||
|
||||
[Tooltip("What rotation axis should be used in auto waving")]
|
||||
public Vector3 WavingAxis = new Vector3(1.0f, 1.0f, 1.0f);
|
||||
|
||||
public Quaternion WavingRotationOffset { get; private set; }
|
||||
|
||||
[Tooltip("Type of waving animation algorithm, it can be simple trigonometric wave or animation based on noises (advanced)")]
|
||||
public FEWavingType WavingType = FEWavingType.Advanced;
|
||||
public enum FEWavingType { Simple, Advanced }
|
||||
|
||||
[Tooltip("Offsetting perlin noise to generate different variation of tail rotations")]
|
||||
public float AlternateWave = 1f;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
// ------------------------ Auto Waving Section ------------------------ \\
|
||||
|
||||
/// <summary> Trigonometric function time variable </summary>
|
||||
float _waving_waveTime;
|
||||
float _waving_cosTime;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Defining time variables for trigonometrics
|
||||
/// </summary>
|
||||
void Waving_Initialize()
|
||||
{
|
||||
if (FixedCycle == 0f)
|
||||
{
|
||||
_waving_waveTime = Random.Range(-Mathf.PI, Mathf.PI) * 100f;
|
||||
_waving_cosTime = Random.Range(-Mathf.PI, Mathf.PI) * 50f;
|
||||
}
|
||||
else
|
||||
{
|
||||
_waving_waveTime = FixedCycle;
|
||||
_waving_cosTime = FixedCycle;
|
||||
}
|
||||
|
||||
_waving_sustain = Vector3.zero;
|
||||
//_waving_sustainVelo = Vector3.zero;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Calculating trigonometric waving feature
|
||||
/// </summary>
|
||||
void Waving_AutoSwingUpdate()
|
||||
{
|
||||
// Defining base variables
|
||||
_waving_waveTime += justDelta * (2 * WavingSpeed);
|
||||
|
||||
// Simple trigonometrical waving
|
||||
if (WavingType == FEWavingType.Simple)
|
||||
{
|
||||
float sinVal = Mathf.Sin(_waving_waveTime) * (30f * WavingRange);
|
||||
|
||||
if (CosinusAdd)
|
||||
{
|
||||
_waving_cosTime += justDelta * (2.535f * WavingSpeed);
|
||||
sinVal += Mathf.Cos(_waving_cosTime) * (27f * WavingRange);
|
||||
}
|
||||
|
||||
WavingRotationOffset = Quaternion.Euler(sinVal * WavingAxis * TailSegments[0].BlendValue);
|
||||
}
|
||||
else
|
||||
// Advanced waving based on perlin noise
|
||||
{
|
||||
float perTime = _waving_waveTime * 0.23f;
|
||||
|
||||
float altX = AlternateWave * -5f;
|
||||
float altY = AlternateWave * 100f;
|
||||
float altZ = AlternateWave * 20f;
|
||||
|
||||
float x = Mathf.PerlinNoise(perTime, altX) * 2.0f - 1.0f;
|
||||
float y = Mathf.PerlinNoise(altY + perTime, perTime + altY) * 2.0f - 1.0f;
|
||||
float z = Mathf.PerlinNoise(altZ, perTime) * 2.0f - 1.0f;
|
||||
|
||||
WavingRotationOffset = Quaternion.Euler(Vector3.Scale(WavingAxis * WavingRange * 35f * TailSegments[0].BlendValue, new Vector3(x, y, z)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// ------------------------ Sustain Section ------------------------ \\
|
||||
|
||||
|
||||
/// <summary> Sustain smooth damp helper variable </summary>
|
||||
//Vector3 _waving_sustainVelo = Vector3.zero;
|
||||
/// <summary> Sustain position offset for previous procedural position</summary>
|
||||
Vector3 _waving_sustain = Vector3.zero;
|
||||
|
||||
/// <summary>
|
||||
/// Calculating sustain feature offset
|
||||
/// </summary>
|
||||
void Waving_SustainUpdate()
|
||||
{
|
||||
TailSegment firstB = TailSegments[0];
|
||||
|
||||
// When tail is short and have few segments we have to ampify sustain effect behaviour and vice versa
|
||||
float tailRatio = (_TC_TailLength / (float)TailSegments.Count);
|
||||
tailRatio = Mathf.Pow(tailRatio, 1.65f);
|
||||
tailRatio = (_sg_curly / tailRatio) / 6f;
|
||||
|
||||
// Clamp extreme values
|
||||
if (tailRatio < 0.1f) tailRatio = 0.1f; else if (tailRatio > 1f) tailRatio = 1f;
|
||||
|
||||
int mid = (int)Mathf.LerpUnclamped(TailSegments.Count * 0.4f, TailSegments.Count * 0.6f, Sustain);
|
||||
|
||||
float susFact = FEasing.EaseOutExpo(1f, 0.09f, Sustain);
|
||||
|
||||
float mild = 1.5f;
|
||||
mild *= (1f - TailSegments[0].Curling / 8f);
|
||||
mild *= (1.5f - tailRatio / 1.65f);
|
||||
mild *= Mathf.Lerp(0.7f, 1.2f, firstB.Slithery);
|
||||
mild *= FEasing.EaseOutExpo(1f, susFact, firstB.Springiness);
|
||||
|
||||
Vector3 velo = TailSegments[mid].PreviousPush;
|
||||
if (mid + 1 < TailSegments.Count) velo += TailSegments[mid + 1].PreviousPush;
|
||||
if (mid - 1 > TailSegments.Count) velo += TailSegments[mid - 1].PreviousPush;
|
||||
|
||||
|
||||
_waving_sustain = velo * Sustain * mild * 2f;
|
||||
|
||||
#region Backup
|
||||
//_waving_sustain = Vector3.Lerp(_waving_sustain, TailBones[mid].PreviousPush * Sustain * mild, unifiedDelta);
|
||||
//Vector3.SmoothDamp
|
||||
//(
|
||||
//_waving_sustain,
|
||||
//TailBones[mid].PreviousPush * Sustain * mild,
|
||||
//ref _waving_sustainVelo,
|
||||
//Mathf.LerpUnclamped(0.15f + tailRatio / 5f, 0.1f + tailRatio / 5f, Sustain),
|
||||
//Mathf.Infinity, Time.smoothDeltaTime);
|
||||
|
||||
//TailBones[Mathf.Min(TailBones.Count - 1, _tc_startII)].PreviousPosition += _waving_sustain * mild;
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fcfde61a5f0bcac4fac26bf2152d6a2e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,26 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace FIMSpace.FTail
|
||||
{
|
||||
public partial class TailAnimator2
|
||||
{
|
||||
public bool UseWind = false;
|
||||
[FPD_Suffix(0f, 2.5f, FPD_SuffixAttribute.SuffixMode.PercentageUnclamped)]
|
||||
public float WindEffectPower = 1f;
|
||||
[FPD_Suffix(0f, 2.5f, FPD_SuffixAttribute.SuffixMode.PercentageUnclamped)]
|
||||
public float WindTurbulencePower = 1f;
|
||||
[FPD_Suffix(0f, 1.5f, FPD_SuffixAttribute.SuffixMode.PercentageUnclamped)]
|
||||
public float WindWorldNoisePower = 0.5f;
|
||||
|
||||
/// <summary> Wind power vector used by Tail Animator Wind component </summary>
|
||||
public Vector3 WindEffect = Vector3.zero;
|
||||
|
||||
void WindEffectUpdate()
|
||||
{
|
||||
if (TailAnimatorWind.Instance)
|
||||
{
|
||||
TailAnimatorWind.Instance.AffectTailWithWind(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dfa827566ed68c5469e8b78e674d1d89
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,424 @@
|
||||
#if UNITY_EDITOR
|
||||
|
||||
using FIMSpace.FEditor;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FIMSpace.FTail
|
||||
{
|
||||
public partial class TailAnimator2
|
||||
{
|
||||
[FPD_Header("Debug Switch")]
|
||||
[SerializeField]
|
||||
private bool fDebug = false;
|
||||
|
||||
public Transform _gizmosEditorStartPreview;
|
||||
public Transform _gizmospesp;
|
||||
public Transform _gizmosEditorEndPreview;
|
||||
public Transform _gizmospeep;
|
||||
|
||||
public string _editor_Title = "Tail Animator 2";
|
||||
public bool _editor_IsInspectorViewingColliders = true;
|
||||
public bool _editor_IsInspectorViewingIncludedColliders = false;
|
||||
public int _editor_animatorViewedCounter = -1;
|
||||
|
||||
void OnDrawGizmosSelected()
|
||||
{
|
||||
RefreshTransformsList();
|
||||
if (_TransformsGhostChain.Count == 0) return;
|
||||
if (!DrawGizmos) return;
|
||||
|
||||
if (UseIK) Gizmos_DrawIK();
|
||||
|
||||
if (UseMaxDistance) Gizmos_DrawMaxDistance();
|
||||
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
if (!initialized) return;
|
||||
|
||||
if (!IncludeParent) Editor_TailCalculations_RefreshArtificialParentBone();
|
||||
|
||||
if (_Editor_Category == ETailCategory.Shaping || fDebug)
|
||||
{
|
||||
Handles.color = new Color(0.2f, .2f, 0.85f, 0.5f);
|
||||
Handles.SphereHandleCap(0, TailSegments[0].transform.position, Quaternion.identity, HandleUtility.GetHandleSize(TailSegments[0].transform.position) * 0.05f, EventType.Repaint);
|
||||
|
||||
Handles.color = new Color(0.5f, 1f, 0.35f, 0.3f);
|
||||
|
||||
for (int i = 1; i < TailSegments.Count; i++)
|
||||
{
|
||||
Handles.SphereHandleCap(0, TailSegments[i].ProceduralPosition, Quaternion.identity, HandleUtility.GetHandleSize(TailSegments[i].ProceduralPosition) * 0.09f, EventType.Repaint);
|
||||
Handles.DrawDottedLine(TailSegments[i].ProceduralPosition, TailSegments[i].ParentBone.ProceduralPosition, 2f);
|
||||
}
|
||||
|
||||
if (IncludeParent) Handles.color = new Color(1f, .2f, 0.6f, 1f);
|
||||
Handles.DrawDottedLine(TailSegments[0].ProceduralPosition, TailSegments[0].ParentBone.ProceduralPosition, 2f);
|
||||
|
||||
Handles.color = new Color(1f, .2f, 0.6f, 1f);
|
||||
Handles.DrawDottedLine(GhostChild.ProceduralPosition, GhostChild.ParentBone.ProceduralPosition, 2f);
|
||||
|
||||
Handles.SphereHandleCap(0, GhostParent.ProceduralPosition, Quaternion.identity, HandleUtility.GetHandleSize(GhostParent.ProceduralPosition) * 0.09f, EventType.Repaint);
|
||||
Handles.SphereHandleCap(0, GhostChild.ProceduralPosition, Quaternion.identity, HandleUtility.GetHandleSize(GhostParent.ProceduralPosition) * 0.09f, EventType.Repaint);
|
||||
}
|
||||
|
||||
|
||||
if (fDebug)
|
||||
{
|
||||
Vector3 uoff;
|
||||
|
||||
if (PostProcessingNeeded() && _pp_initialized)
|
||||
{
|
||||
uoff = Vector3.up * _TC_TailLength * 0.065f;
|
||||
Gizmos.color = new Color(0.8f, 0.2f, 0.5f, 0.4f); // Post processing reference line (transparent dark pinnk)
|
||||
for (int i = 0; i < _pp_reference.Count; i++)
|
||||
{
|
||||
Gizmos.DrawSphere(_pp_reference[i].ProceduralPosition, .3f);
|
||||
|
||||
Gizmos.DrawLine(_pp_reference[i].ParentBone.ProceduralPosition + uoff, _pp_reference[i].ProceduralPosition + uoff);
|
||||
}
|
||||
|
||||
Handles.color = new Color(0.8f, 0.2f, 0.5f, 0.4f); // Deflection source segment sphere
|
||||
for (int i = 0; i < _defl_source.Count; i++)
|
||||
Handles.SphereHandleCap(0, _defl_source[i].ParentBone.ProceduralPosition + uoff, Quaternion.identity, HandleUtility.GetHandleSize(_defl_source[i].ProceduralPosition) * 0.09f, EventType.Repaint);
|
||||
|
||||
Handles.color = new Color(0.55f, .2f, 0.8f, 0.6f); // Deflection source segment sphere
|
||||
for (int i = 0; i < _defl_source.Count; i++)
|
||||
Handles.SphereHandleCap(0, Vector3.LerpUnclamped(TailSegments[_defl_source[i].Index].ParentBone.ProceduralPosition, TailSegments[_defl_source[i].Index].ProceduralPosition, 0.5f) + uoff, Quaternion.identity, HandleUtility.GetHandleSize(_defl_source[i].ProceduralPosition) * 0.09f, EventType.Repaint);
|
||||
|
||||
|
||||
#region Debug
|
||||
|
||||
//Handles.color = new Color(0.55f, .2f, 0.8f, 0.8f);
|
||||
//for (int i = 0; i < _defl_source.Count; i++)
|
||||
// Handles.DrawDottedLine(_defl_source[i].ProceduralPosition + uoff, _defl_source[i].DeflectionWorldPosition + uoff, 2f);
|
||||
|
||||
//Handles.color = new Color(0.0f, 1f, 1f, 0.8f);
|
||||
//for (int i = 0; i < _defl_source.Count; i++)
|
||||
//{
|
||||
// int backRange = _tc_startI; if (i > 0) backRange = _defl_source[i - 1].Index;
|
||||
|
||||
// for (int k = _defl_source[i].Index; k >= backRange; k--)
|
||||
// Handles.DrawDottedLine(TailBones[k].ProceduralPosition + uoff, _defl_source[i].DeflectionWorldPosition + uoff, 2f);
|
||||
//}
|
||||
|
||||
#endregion
|
||||
|
||||
Gizmos.color = new Color(1f, 0.1f, 0.35f, 0.6f); // Deflection push focus (magenta)
|
||||
for (int i = 0; i < _defl_source.Count; i++)
|
||||
{
|
||||
Gizmos.DrawLine(_defl_source[i].DeflectionWorldPosition + uoff, _defl_source[i].ParentBone.ProceduralPosition + uoff);
|
||||
//Handles.Label(_pp_reference[_defl_source[i].Index].ParentBone.ProceduralPosition + uoff + transform.right * _tc_tailLength * 0.032f + uoff, "b.par=[" + _defl_source[i].Index + "]");
|
||||
Handles.DrawDottedLine(_pp_reference[_defl_source[i].Index].ParentBone.ProceduralPosition + uoff + transform.right * _TC_TailLength * 0.032f + uoff, TailSegments[_defl_source[i].Index].ProceduralPosition + uoff, 3f);
|
||||
}
|
||||
|
||||
|
||||
uoff = Vector3.up * _TC_TailLength * 0.044f;
|
||||
Gizmos.color = new Color(0.2f, 0.9f, 0.4f, 0.5f); // True position line
|
||||
for (int i = 0; i < _pp_reference.Count; i++)
|
||||
Gizmos.DrawLine(TailSegments[i].ParentBone.ProceduralPosition + uoff, TailSegments[i].ProceduralPosition + uoff);
|
||||
|
||||
Gizmos.DrawLine(_pp_ref_lastChild.ParentBone.ProceduralPosition + uoff, _pp_ref_lastChild.ProceduralPosition + uoff);
|
||||
|
||||
|
||||
// All segments debug draw
|
||||
uoff = Vector3.up * _TC_TailLength * 0.065f;
|
||||
Handles.color = new Color(1f, 1f, 1f, 0.4f);
|
||||
for (int i = 0; i < TailSegments.Count; i++)
|
||||
{
|
||||
Handles.SphereHandleCap(0, TailSegments[i].ProceduralPosition, Quaternion.identity, HandleUtility.GetHandleSize(TailSegments[i].ProceduralPosition) * 0.09f, EventType.Repaint);
|
||||
Handles.Label(TailSegments[i].ProceduralPosition - transform.right * _TC_TailLength * 0.02f + uoff, "[" + i + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_Editor_Category == ETailCategory.Setup)
|
||||
{
|
||||
if (_TransformsGhostChain != null)
|
||||
{
|
||||
if (_TransformsGhostChain.Count > 1)
|
||||
{
|
||||
|
||||
if (!IncludeParent) Handles.color = new Color(.9f, .4f, .7f, .9f); else Handles.color = new Color(0.5f, 1f, 0.35f, 0.8f);
|
||||
|
||||
if (_TransformsGhostChain.Count > 1)
|
||||
{
|
||||
FGUI_Handles.DrawBoneHandle(_TransformsGhostChain[0].position, _TransformsGhostChain[1].position, BaseTransform.forward, 1f);
|
||||
Handles.SphereHandleCap(0, _TransformsGhostChain[0].position, Quaternion.identity, HandleUtility.GetHandleSize(_TransformsGhostChain[0].position) * 0.09f, EventType.Repaint);
|
||||
}
|
||||
|
||||
|
||||
for (int i = 1; i < _TransformsGhostChain.Count - 1; i++) // -1 because we painting bones from i to i+1
|
||||
{
|
||||
Handles.color = new Color(0.5f, 1f, 0.35f, 0.8f);
|
||||
FGUI_Handles.DrawBoneHandle(_TransformsGhostChain[i].position, _TransformsGhostChain[i + 1].position, BaseTransform.forward, 1f);
|
||||
|
||||
Handles.color = new Color(0.5f, 1f, 0.35f, 0.3f);
|
||||
Handles.SphereHandleCap(0, _TransformsGhostChain[i].position, Quaternion.identity, HandleUtility.GetHandleSize(_TransformsGhostChain[i].position) * 0.09f, EventType.Repaint);
|
||||
}
|
||||
|
||||
if (_TransformsGhostChain.Count > 1)
|
||||
if (IncludeParent)
|
||||
{
|
||||
if (_TransformsGhostChain[0].parent)
|
||||
{
|
||||
Handles.color = new Color(1f, .2f, 0.6f, 0.3f);
|
||||
FGUI_Handles.DrawBoneHandle(_TransformsGhostChain[0].parent.position, _TransformsGhostChain[0].position, BaseTransform.forward, 1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_TransformsGhostChain.Count > 0)
|
||||
{
|
||||
if (_TransformsGhostChain[0].parent)
|
||||
{
|
||||
Transform t = _TransformsGhostChain[0]; Transform p = _TransformsGhostChain[0].parent;
|
||||
|
||||
Handles.color = new Color(0.8f, .8f, 0.2f, 0.8f);
|
||||
FGUI_Handles.DrawBoneHandle(_TransformsGhostChain[0].parent.position, _TransformsGhostChain[0].position, BaseTransform.forward, 1f);
|
||||
Handles.color = new Color(0.8f, .8f, 0.2f, 0.3f);
|
||||
Handles.SphereHandleCap(0, _TransformsGhostChain[0].position, Quaternion.identity, HandleUtility.GetHandleSize(_TransformsGhostChain[0].position) * 0.135f, EventType.Repaint);
|
||||
Handles.Label(t.position + Vector3.Cross(t.forward, p.forward).normalized * (t.position - p.position).magnitude / 2f, new GUIContent("[i]", "Tail chain with one bone setup - try using End Bone Offset in 'Setup' tab"));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (_TransformsGhostChain.Count < 2)
|
||||
{
|
||||
Handles.color = new Color(1f, 1f, 1f, 0.5f);
|
||||
Handles.SphereHandleCap(0, _TransformsGhostChain[0].position, Quaternion.identity, HandleUtility.GetHandleSize(_TransformsGhostChain[0].position) * 0.135f, EventType.Repaint);
|
||||
|
||||
if (_TransformsGhostChain.Count > 0)
|
||||
{
|
||||
if (!_TransformsGhostChain[0].parent)
|
||||
{
|
||||
Handles.color = new Color(1f, .2f, 0.2f, 0.8f);
|
||||
Vector3 infoPos = _TransformsGhostChain[0].position + (_TransformsGhostChain[0].up + _TransformsGhostChain[0].right) * 0.2f;
|
||||
Handles.DrawDottedLine(_TransformsGhostChain[0].position, infoPos, 2f);
|
||||
Handles.DrawDottedLine(_TransformsGhostChain[0].position, transform.position, 2f);
|
||||
Handles.Label(infoPos, new GUIContent(FGUI_Resources.Tex_Warning, "No parent in this bone, tail chain can't be created"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (_Editor_Category == ETailCategory.Setup)
|
||||
{
|
||||
Handles.color = new Color(1f, .2f, 0.2f, 0.8f);
|
||||
Gizmos_DrawEndBoneJoint();
|
||||
}
|
||||
|
||||
|
||||
if (_editor_IsInspectorViewingColliders && _Editor_Category == ETailCategory.Features) Gizmos_DrawColliders();
|
||||
}
|
||||
|
||||
|
||||
void Gizmos_DrawEndBoneJoint()
|
||||
{
|
||||
// Drawing auto end joint offset
|
||||
if (FEngineering.VIsZero(EndBoneJointOffset))
|
||||
{
|
||||
Transform t = _TransformsGhostChain[_TransformsGhostChain.Count - 1];
|
||||
Transform p = _TransformsGhostChain[_TransformsGhostChain.Count - 1].parent;
|
||||
|
||||
if (p) // Reference from parent
|
||||
{
|
||||
Vector3 worldOffset = t.position - p.position;
|
||||
|
||||
Handles.color = new Color(0.3f, .3f, 1f, 0.8f);
|
||||
FGUI_Handles.DrawBoneHandle(t.position, t.position + worldOffset, BaseTransform.forward, 1f);
|
||||
}
|
||||
else // Reference to child
|
||||
{
|
||||
if (t.childCount > 0)
|
||||
{
|
||||
Transform ch = _TransformsGhostChain[0].GetChild(0);
|
||||
Vector3 worldOffset = ch.position - t.position;
|
||||
FGUI_Handles.DrawBoneHandle(t.position, t.position + worldOffset, BaseTransform.forward, 1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Drawing custom joint offset
|
||||
else
|
||||
{
|
||||
Transform t = _TransformsGhostChain[_TransformsGhostChain.Count - 1];
|
||||
Handles.color = new Color(0.3f, .3f, 1f, 0.8f);
|
||||
FGUI_Handles.DrawBoneHandle(t.position, t.position + t.TransformVector(EndBoneJointOffset), BaseTransform.forward, 1f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Gizmos_DrawColliders()
|
||||
{
|
||||
if (UseCollision)
|
||||
{
|
||||
if (IncludedColliders == null) IncludedColliders = new System.Collections.Generic.List<Collider>();
|
||||
|
||||
Color preCol = Gizmos.color;
|
||||
Gizmos.color = new Color(0.2f, 1f, 0.2f, 0.25f);
|
||||
|
||||
for (int i = 1; i < _TransformsGhostChain.Count - 1; i++)
|
||||
{
|
||||
if (_TransformsGhostChain[i] == null) continue;
|
||||
Matrix4x4 curr = Matrix4x4.TRS(_TransformsGhostChain[i].position, _TransformsGhostChain[i].rotation, _TransformsGhostChain[i].lossyScale);
|
||||
float radius = 1f;
|
||||
if (Application.isPlaying) radius = TailSegments[i].ColliderRadius; else radius = GetColliderSphereRadiusFor(_TransformsGhostChain, i);
|
||||
|
||||
if (CollidersType != 0)
|
||||
{
|
||||
if (CollisionSpace == ECollisionSpace.World_Slow)
|
||||
{
|
||||
float preRadius = 1f;
|
||||
if (Application.isPlaying) preRadius = TailSegments[i - 1].ColliderRadius; else preRadius = GetColliderSphereRadiusFor(_TransformsGhostChain, i - 1);
|
||||
|
||||
Gizmos.color = Color.HSVToRGB((float)i / (float)_TransformsGhostChain.Count, 0.9f, 0.9f) * new Color(1f, 1f, 1f, 0.55f);
|
||||
|
||||
Matrix4x4 pre = Matrix4x4.TRS(_TransformsGhostChain[i - 1].position, _TransformsGhostChain[i - 1].rotation, _TransformsGhostChain[i - 1].lossyScale);
|
||||
|
||||
Gizmos.DrawLine(pre.MultiplyPoint(Vector3.up * preRadius), curr.MultiplyPoint(Vector3.up * radius));
|
||||
Gizmos.DrawLine(pre.MultiplyPoint(-Vector3.up * preRadius), curr.MultiplyPoint(-Vector3.up * radius));
|
||||
Gizmos.DrawLine(pre.MultiplyPoint(Vector3.right * preRadius), curr.MultiplyPoint(Vector3.right * radius));
|
||||
Gizmos.DrawLine(pre.MultiplyPoint(Vector3.left * preRadius), curr.MultiplyPoint(Vector3.left * radius));
|
||||
|
||||
if (i % 2 == 0)
|
||||
{
|
||||
Gizmos.matrix = curr;
|
||||
Gizmos.DrawWireSphere(Vector3.zero, radius);
|
||||
Gizmos.matrix = Matrix4x4.identity;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Gizmos.matrix = curr;
|
||||
Gizmos.DrawWireSphere(Vector3.zero, radius);
|
||||
Gizmos.matrix = Matrix4x4.identity;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Gizmos.matrix = curr;
|
||||
Gizmos.DrawWireSphere(Vector3.zero, radius);
|
||||
Gizmos.matrix = Matrix4x4.identity;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (CollisionSpace == ECollisionSpace.Selective_Fast)
|
||||
{
|
||||
if (_editor_IsInspectorViewingIncludedColliders)
|
||||
{
|
||||
Handles.color = new Color(0.4f, 1f, 0.25f, 0.22f);
|
||||
int c = Mathf.Min(IncludedColliders.Count, 10); // Drawing max 10 lines toward included colliders
|
||||
for (int i = 0; i < c; i++)
|
||||
{
|
||||
if (IncludedColliders[i] != null)
|
||||
{
|
||||
Handles.DrawDottedLine(_TransformsGhostChain[0].position, IncludedColliders[i].transform.position, 2f);
|
||||
Handles.SphereHandleCap(0, IncludedColliders[i].transform.position, Quaternion.identity, HandleUtility.GetHandleSize(IncludedColliders[i].transform.position) * 0.09f, EventType.Repaint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!Application.isPlaying)
|
||||
if (DynamicWorldCollidersInclusion)
|
||||
{
|
||||
float scaleRef = Vector3.Distance(_TransformsGhostChain[0].position, _TransformsGhostChain[_TransformsGhostChain.Count - 1].position);
|
||||
Transform collSource = _TransformsGhostChain[_TransformsGhostChain.Count / 2];
|
||||
Gizmos.DrawWireSphere(collSource.position, scaleRef * InclusionRadius);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Gizmos.color = preCol;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Gizmos_DrawIK()
|
||||
{
|
||||
if (_TransformsGhostChain.Count < 2) return;
|
||||
if (_Editor_Category != ETailCategory.Features) return;
|
||||
if (_Editor_FeaturesCategory != ETailFeaturesCategory.IK) return;
|
||||
|
||||
Vector3 start = _TransformsGhostChain[0].position;
|
||||
Vector3 end = _TransformsGhostChain[_TransformsGhostChain.Count - 1].position;
|
||||
Vector3 targetIK;
|
||||
|
||||
if (IKTarget)
|
||||
{
|
||||
Handles.color = new Color(0f, 0.7f, 0.3f, 0.7f);
|
||||
targetIK = IKTarget.position;
|
||||
}
|
||||
else
|
||||
{
|
||||
Handles.color = new Color(0.7f, 0.0f, 0.3f, 0.7f);
|
||||
targetIK = _TransformsGhostChain[_TransformsGhostChain.Count - 1].position;
|
||||
}
|
||||
|
||||
float d = (start - end).magnitude * 0.06f;
|
||||
|
||||
Handles.DrawDottedLine(start, targetIK, 3f);
|
||||
Handles.DrawDottedLine(end, targetIK, 3f);
|
||||
|
||||
Handles.DrawLine(targetIK - BaseTransform.forward * d, targetIK + BaseTransform.forward * d);
|
||||
Handles.DrawLine(targetIK - BaseTransform.right * d, targetIK + BaseTransform.right * d);
|
||||
Handles.DrawLine(targetIK - BaseTransform.up * d, targetIK + BaseTransform.up * d);
|
||||
Handles.SphereHandleCap(0, targetIK, Quaternion.identity, d * 0.25f, EventType.Repaint);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Gizmos_DrawMaxDistance()
|
||||
{
|
||||
if (MaximumDistance <= 0f) return;
|
||||
|
||||
float a = 0.525f;
|
||||
Vector3 startPos = BaseTransform.position + BaseTransform.TransformVector(DistanceMeasurePoint);
|
||||
|
||||
if (DistanceWithoutY)
|
||||
{
|
||||
if (maxDistanceExceed)
|
||||
Handles.color = new Color(1f, .1f, .1f, a);
|
||||
else Handles.color = new Color(0.02f, .65f, 0.2f, a);
|
||||
|
||||
Handles.DrawWireDisc(startPos, Vector3.up, MaximumDistance);
|
||||
|
||||
if (DistanceMeasurePoint != Vector3.zero)
|
||||
{
|
||||
Gizmos.color = new Color(0.02f, .65f, 0.2f, a);
|
||||
Gizmos.DrawLine(startPos - Vector3.right * (MaximumDistance + MaximumDistance * MaxOutDistanceFactor), startPos + Vector3.right * (MaximumDistance + MaximumDistance * MaxOutDistanceFactor));
|
||||
Gizmos.DrawLine(startPos - Vector3.forward * (MaximumDistance + MaximumDistance * MaxOutDistanceFactor), startPos + Vector3.forward * (MaximumDistance + MaximumDistance * MaxOutDistanceFactor));
|
||||
}
|
||||
|
||||
if (MaxOutDistanceFactor > 0f)
|
||||
{
|
||||
Handles.color = new Color(.835f, .135f, .08f, a);
|
||||
Handles.DrawWireDisc(startPos, Vector3.up, MaximumDistance + MaximumDistance * MaxOutDistanceFactor);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (maxDistanceExceed)
|
||||
Gizmos.color = new Color(1f, .1f, .1f, a);
|
||||
else
|
||||
Gizmos.color = new Color(0.02f, .65f, 0.2f, a);
|
||||
|
||||
Gizmos.DrawWireSphere(startPos, MaximumDistance);
|
||||
|
||||
if (MaxOutDistanceFactor > 0f)
|
||||
{
|
||||
Gizmos.color = new Color(.835f, .135f, .08f, a);
|
||||
Gizmos.DrawWireSphere(startPos, MaximumDistance + MaximumDistance * MaxOutDistanceFactor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 516e3bfcbbd526a419d62b47bb170926
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,312 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FIMSpace.FTail
|
||||
{
|
||||
public partial class TailAnimator2
|
||||
{
|
||||
/// <summary> Procedural tail bone list </summary>
|
||||
public List<TailSegment> TailSegments;
|
||||
|
||||
/// <summary> Artificial or existing parent bone instance for slithery motion support </summary>
|
||||
[SerializeField] TailSegment GhostParent;
|
||||
[SerializeField] TailSegment GhostChild;
|
||||
|
||||
/// <summary>
|
||||
/// Method to initialize component, to have more controll than waiting for Start() method, init can be executed before or after start, as programmer need it.
|
||||
/// </summary>
|
||||
protected virtual void Init()
|
||||
{
|
||||
if (initialized) return;
|
||||
|
||||
|
||||
// Checking if we have transform to create tail chain from
|
||||
if (_TransformsGhostChain == null || _TransformsGhostChain.Count == 0)
|
||||
{
|
||||
_TransformsGhostChain = new List<Transform>();
|
||||
GetGhostChain();
|
||||
}
|
||||
|
||||
|
||||
// Generating tail instances for procedural animation
|
||||
TailSegments = new List<TailSegment>();
|
||||
|
||||
for (int i = 0; i < _TransformsGhostChain.Count; i++)
|
||||
{
|
||||
if (_TransformsGhostChain[i] == null)
|
||||
{
|
||||
Debug.Log("[Tail Animator] Null bones in " + name + " !");
|
||||
continue;
|
||||
}
|
||||
|
||||
TailSegment b = new TailSegment(_TransformsGhostChain[i]);
|
||||
b.SetIndex(i, _TransformsGhostChain.Count);
|
||||
TailSegments.Add(b);
|
||||
}
|
||||
|
||||
|
||||
// Checking correctness
|
||||
if (TailSegments.Count == 0)
|
||||
{
|
||||
Debug.Log("[Tail Animator] Could not create tail bones chain in " + name + " !");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
_TC_TailLength = 0f;
|
||||
_baseTransform = _TransformsGhostChain[0];
|
||||
|
||||
//if (_baseTransform.parent)
|
||||
// _baseTransform = _baseTransform.parent;
|
||||
//else
|
||||
// IncludeParent = false;
|
||||
|
||||
|
||||
// Setting parent-child relation for tail logics
|
||||
for (int i = 0; i < TailSegments.Count; i++)
|
||||
{
|
||||
TailSegment current = TailSegments[i];
|
||||
TailSegment parent;
|
||||
|
||||
#region Defining Parent Bones
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
if (current.transform.parent)
|
||||
{
|
||||
// Creating parent and setting safety parent
|
||||
parent = new TailSegment(current.transform.parent);
|
||||
parent.SetParentRef(new TailSegment(parent.transform.parent));
|
||||
}
|
||||
else
|
||||
#region If first bone is parentless
|
||||
{
|
||||
parent = new TailSegment(current.transform);
|
||||
|
||||
Vector3 toStartDir;
|
||||
|
||||
if (_TransformsGhostChain.Count > 1)
|
||||
{
|
||||
toStartDir = _TransformsGhostChain[0].position - _TransformsGhostChain[1].position;
|
||||
if (toStartDir.magnitude == 0) toStartDir = transform.position - _TransformsGhostChain[1].position;
|
||||
}
|
||||
else
|
||||
{
|
||||
toStartDir = current.transform.position - _TransformsGhostChain[0].position;
|
||||
}
|
||||
|
||||
if (toStartDir.magnitude == 0) toStartDir = transform.position - _TransformsGhostChain[0].position;
|
||||
if (toStartDir.magnitude == 0) toStartDir = transform.forward;
|
||||
|
||||
parent.LocalOffset = parent.transform.InverseTransformPoint(parent.transform.position + toStartDir);
|
||||
parent.SetParentRef(new TailSegment(current.transform));
|
||||
}
|
||||
#endregion
|
||||
|
||||
//current.InitialLocalRotation = Quaternion.Inverse(current.transform.localRotation);
|
||||
GhostParent = parent;
|
||||
GhostParent.Validate();
|
||||
current.SetParentRef(GhostParent);
|
||||
}
|
||||
else // i != 0
|
||||
{
|
||||
parent = TailSegments[i - 1];
|
||||
// If bones are removed manually from chain we support custom length of bone undependent from transform parenting chain structure
|
||||
current.ReInitializeLocalPosRot(parent.transform.InverseTransformPoint(current.transform.position), current.transform.localRotation);
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Defining Last Child Bone
|
||||
|
||||
if (i == TailSegments.Count - 1)
|
||||
{
|
||||
Transform childT = null;
|
||||
if (current.transform.childCount > 0) childT = current.transform.GetChild(0);
|
||||
|
||||
GhostChild = new TailSegment(childT);
|
||||
|
||||
// Scale ref for ghosting object position offset
|
||||
Vector3 scaleDir;
|
||||
|
||||
if (FEngineering.VIsZero(EndBoneJointOffset))
|
||||
{
|
||||
if (current.transform.parent)
|
||||
{ scaleDir = current.transform.position - current.transform.parent.position; }
|
||||
else
|
||||
if (current.transform.childCount > 0)
|
||||
{ scaleDir = current.transform.GetChild(0).position - current.transform.position; }
|
||||
else
|
||||
{ scaleDir = current.transform.TransformDirection(Vector3.forward) * 0.05f; }
|
||||
}
|
||||
else
|
||||
scaleDir = current.transform.TransformVector(EndBoneJointOffset);
|
||||
|
||||
|
||||
GhostChild.ProceduralPosition = current.transform.position + scaleDir;
|
||||
GhostChild.ProceduralPositionWeightBlended = GhostChild.ProceduralPosition;
|
||||
GhostChild.PreviousPosition = GhostChild.ProceduralPosition;
|
||||
GhostChild.PosRefRotation = Quaternion.identity;
|
||||
GhostChild.PreviousPosReferenceRotation = Quaternion.identity;
|
||||
GhostChild.ReInitializeLocalPosRot(current.transform.InverseTransformPoint(GhostChild.ProceduralPosition), Quaternion.identity);
|
||||
GhostChild.RefreshFinalPos(GhostChild.ProceduralPosition);
|
||||
GhostChild.RefreshFinalRot(GhostChild.PosRefRotation);
|
||||
GhostChild.TrueTargetRotation = GhostChild.PosRefRotation;
|
||||
current.TrueTargetRotation = current.transform.rotation;
|
||||
|
||||
current.SetChildRef(GhostChild);
|
||||
GhostChild.SetParentRef(current);
|
||||
}
|
||||
else
|
||||
{
|
||||
current.SetChildRef(TailSegments[i + 1]);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
current.SetParentRef(parent);
|
||||
|
||||
_TC_TailLength += Vector3.Distance(current.ProceduralPosition, parent.ProceduralPosition);
|
||||
|
||||
if (current.transform != _baseTransform) current.AssignDetachedRootCoords(BaseTransform);
|
||||
}
|
||||
|
||||
|
||||
// List with ghosts for curves etc.
|
||||
GhostParent.SetIndex(-1, TailSegments.Count);
|
||||
GhostChild.SetIndex(TailSegments.Count, TailSegments.Count);
|
||||
GhostParent.SetChildRef(TailSegments[0]);
|
||||
|
||||
previousWorldPosition = BaseTransform.position;
|
||||
WavingRotationOffset = Quaternion.identity;
|
||||
|
||||
if (CollidersDataToCheck == null) CollidersDataToCheck = new List<FImp_ColliderData_Base>();
|
||||
|
||||
DynamicAlwaysInclude = new List<Component>();
|
||||
if (UseCollision) SetupSphereColliders();
|
||||
|
||||
// List instance for deflection feature
|
||||
if (_defl_source == null) _defl_source = new List<TailSegment>();
|
||||
|
||||
Waving_Initialize();
|
||||
|
||||
if (DetachChildren) DetachChildrenTransforms();
|
||||
|
||||
initialized = true;
|
||||
|
||||
if (TailSegments.Count == 1)
|
||||
{
|
||||
if (TailSegments[0].transform.parent == null)
|
||||
{
|
||||
Debug.Log("[Tail Animator] Can't initialize one-bone length chain on bone which don't have any parent!");
|
||||
Debug.LogError("[Tail Animator] Can't initialize one-bone length chain on bone which don't have any parent!");
|
||||
TailAnimatorAmount = 0f;
|
||||
initialized = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (UseWind) TailAnimatorWind.Refresh();
|
||||
|
||||
if (PostProcessingNeeded()) if (!_pp_initialized) InitializePostProcessing();
|
||||
|
||||
#region Prewarming tail to target state
|
||||
|
||||
if (Prewarm)
|
||||
{
|
||||
ShapingParamsUpdate();
|
||||
ExpertParamsUpdate();
|
||||
|
||||
Update();
|
||||
LateUpdate();
|
||||
|
||||
justDelta = rateDelta;
|
||||
secPeriodDelta = 1f;
|
||||
deltaForLerps = secPeriodDelta;
|
||||
rateDelta = 1f / 60f;
|
||||
|
||||
CheckIfTailAnimatorShouldBeUpdated();
|
||||
|
||||
if (updateTailAnimator)
|
||||
{
|
||||
int loopCount = 60 + TailSegments.Count / 2;
|
||||
|
||||
for (int d = 0; d < loopCount; d++)
|
||||
{
|
||||
PreCalibrateBones();
|
||||
LateUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Detaching children for optimized work of Unity transform matrixes when tail is very long
|
||||
/// </summary>
|
||||
public void DetachChildrenTransforms()
|
||||
{
|
||||
int to = IncludeParent ? 0 : 1;
|
||||
for (int i = TailSegments.Count - 1; i >= to; i--)
|
||||
{
|
||||
if (TailSegments[i].transform)
|
||||
TailSegments[i].transform.DetachChildren();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initialize post processing reference points
|
||||
/// </summary>
|
||||
void InitializePostProcessing()
|
||||
{
|
||||
_pp_reference = new List<TailSegment>();
|
||||
|
||||
// Generating copy of whole tail processing chain
|
||||
_pp_ref_rootParent = new TailSegment(GhostParent);
|
||||
for (int i = 0; i < TailSegments.Count; i++) { TailSegment bone = new TailSegment(TailSegments[i]); _pp_reference.Add(bone); }
|
||||
_pp_ref_lastChild = new TailSegment(GhostChild);
|
||||
|
||||
|
||||
// Setting child parent relation
|
||||
_pp_ref_rootParent.SetChildRef(_pp_reference[0]); // root have just child
|
||||
_pp_ref_rootParent.SetParentRef(new TailSegment(GhostParent.ParentBone.transform)); // Safety parent
|
||||
|
||||
for (int i = 0; i < _pp_reference.Count; i++)
|
||||
{
|
||||
TailSegment bone = _pp_reference[i];
|
||||
bone.SetIndex(i, TailSegments.Count);
|
||||
|
||||
if (i == 0) // First bone have ghost parent
|
||||
{
|
||||
bone.SetParentRef(_pp_ref_rootParent);
|
||||
bone.SetChildRef(_pp_reference[i + 1]);
|
||||
}
|
||||
else if (i == _pp_reference.Count - 1) // last bone have ghost child
|
||||
{
|
||||
bone.SetParentRef(_pp_reference[i - 1]);
|
||||
bone.SetChildRef(_pp_ref_lastChild);
|
||||
}
|
||||
else // Default bone from chain middle points
|
||||
{
|
||||
bone.SetParentRef(_pp_reference[i - 1]);
|
||||
bone.SetChildRef(_pp_reference[i + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
_pp_ref_lastChild.SetParentRef(_pp_reference[_pp_reference.Count - 1]); // end have just parent
|
||||
|
||||
|
||||
_pp_initialized = true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e3b722fb0fe3ed44685a7cfc9ad05ac8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,354 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace FIMSpace.FTail
|
||||
{
|
||||
public partial class TailAnimator2
|
||||
{
|
||||
Vector3 _limiting_limitPosition = Vector3.zero;
|
||||
Vector3 _limiting_influenceOffset = Vector3.zero;
|
||||
|
||||
/// <summary> Helping stretching limiting be more responsible (lerp value help) </summary>
|
||||
float _limiting_stretchingHelperTooLong = 0f;
|
||||
float _limiting_stretchingHelperTooShort = 0f;
|
||||
|
||||
/// <summary>
|
||||
/// If tail is too long we making it shorter if too short - back to default scale
|
||||
/// </summary>
|
||||
protected void StretchingLimiting(TailSegment bone)
|
||||
{
|
||||
Vector3 backDir = (bone.ParentBone.ProceduralPosition) - (bone.ProceduralPosition);
|
||||
float dist = backDir.magnitude;
|
||||
|
||||
if (dist > 0f)
|
||||
{
|
||||
float maxDist = bone.BoneLengthScaled + bone.BoneLengthScaled * 2.5f * MaxStretching;
|
||||
|
||||
if (dist > maxDist) // If tail too long
|
||||
{
|
||||
if (MaxStretching == 0f)
|
||||
{
|
||||
_limiting_limitPosition = bone.ProceduralPosition + backDir * ((dist - bone.BoneLengthScaled) / dist);
|
||||
bone.ProceduralPosition = _limiting_limitPosition;
|
||||
}
|
||||
else
|
||||
{
|
||||
_limiting_limitPosition = bone.ParentBone.ProceduralPosition - backDir.normalized * maxDist;
|
||||
//bone.ProceduralPosition = _limiting_limitPosition;
|
||||
float limValue = Mathf.InverseLerp(dist, 0f, maxDist) + _limiting_stretchingHelperTooLong; if (limValue > 0.999f) limValue = 0.99f;
|
||||
if (ReactionSpeed < 0.5f) limValue *= deltaForLerps * (10f + ReactionSpeed * 30f);
|
||||
bone.ProceduralPosition = Vector3.Lerp(bone.ProceduralPosition, _limiting_limitPosition, limValue);
|
||||
}
|
||||
}
|
||||
else // If tail too short
|
||||
{
|
||||
maxDist = bone.BoneLengthScaled + bone.BoneLengthScaled * 1.1f * MaxStretching;
|
||||
|
||||
if (dist < maxDist)
|
||||
{
|
||||
_limiting_limitPosition = bone.ProceduralPosition + backDir * ((dist - bone.BoneLengthScaled) / dist);
|
||||
|
||||
if (MaxStretching == 0f)
|
||||
bone.ProceduralPosition = _limiting_limitPosition;
|
||||
else
|
||||
bone.ProceduralPosition = Vector3.LerpUnclamped(bone.ProceduralPosition, _limiting_limitPosition, Mathf.InverseLerp(dist, 0f, maxDist) + _limiting_stretchingHelperTooShort);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Quaternion _limiting_angle_ToTargetRot;
|
||||
Quaternion _limiting_angle_targetInLocal;
|
||||
Quaternion _limiting_angle_newLocal;
|
||||
|
||||
/// <summary>
|
||||
/// If segment rotation is in too big angle we straighten it
|
||||
/// </summary>
|
||||
protected Vector3 AngleLimiting(TailSegment child, Vector3 targetPos)
|
||||
{
|
||||
float angleFactor = 0f;
|
||||
_limiting_limitPosition = targetPos;
|
||||
|
||||
|
||||
_limiting_angle_ToTargetRot = (
|
||||
Quaternion.FromToRotation
|
||||
(
|
||||
child.ParentBone.transform.TransformDirection(child.LastKeyframeLocalPosition),
|
||||
targetPos - child.ParentBone.ProceduralPosition)
|
||||
)
|
||||
* child.ParentBone.transform.rotation;
|
||||
|
||||
_limiting_angle_targetInLocal = FEngineering.QToLocal(child.ParentBone.transform.rotation, _limiting_angle_ToTargetRot); // Quaternion.Inverse(child.ParentBone.PreviousRotation) * _limiting_angle_ToTargetRot;
|
||||
|
||||
|
||||
// Limiting all axis or one
|
||||
float angleDiffToInitPose = 0f;
|
||||
|
||||
if (AngleLimitAxis.sqrMagnitude == 0f) // All axis limit angle
|
||||
angleDiffToInitPose = Quaternion.Angle(_limiting_angle_targetInLocal, child.LastKeyframeLocalRotation);
|
||||
else // Selective axis
|
||||
{
|
||||
#region Selective axis limits
|
||||
|
||||
AngleLimitAxis.Normalize();
|
||||
|
||||
if (LimitAxisRange.x == LimitAxisRange.y)
|
||||
{
|
||||
angleDiffToInitPose = Mathf.DeltaAngle(
|
||||
Vector3.Scale(child.InitialLocalRotation.eulerAngles, AngleLimitAxis).magnitude,
|
||||
Vector3.Scale(_limiting_angle_targetInLocal.eulerAngles, AngleLimitAxis).magnitude);
|
||||
|
||||
if (angleDiffToInitPose < 0f) angleDiffToInitPose = -angleDiffToInitPose;
|
||||
}
|
||||
else
|
||||
{
|
||||
angleDiffToInitPose = Mathf.DeltaAngle(
|
||||
Vector3.Scale(child.InitialLocalRotation.eulerAngles, AngleLimitAxis).magnitude,
|
||||
Vector3.Scale(_limiting_angle_targetInLocal.eulerAngles, AngleLimitAxis).magnitude);
|
||||
|
||||
if (angleDiffToInitPose > LimitAxisRange.x && angleDiffToInitPose < LimitAxisRange.y) angleDiffToInitPose = 0f;
|
||||
if (angleDiffToInitPose < 0) angleDiffToInitPose = -angleDiffToInitPose;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
#region Debug
|
||||
//Debug.Log("Atarget in local = " +
|
||||
// FEngineering.WrapVector(_limiting_angle_targetInLocal.eulerAngles) + " last key local = " +
|
||||
// FEngineering.WrapVector(child.lastKeyframeLocalRotation.eulerAngles) + " angle = " + angleDiffToInitPose);
|
||||
#endregion
|
||||
|
||||
// Finding rotate back to limited angle coordinates
|
||||
if (angleDiffToInitPose > AngleLimit)
|
||||
{
|
||||
|
||||
float exceededAngle = Mathf.Abs(Mathf.DeltaAngle(angleDiffToInitPose, AngleLimit));
|
||||
angleFactor = Mathf.InverseLerp(0f, AngleLimit, exceededAngle); // percentage value (0-1) from target rotation to limit
|
||||
|
||||
#region Debug
|
||||
|
||||
//Debug.DrawLine(child.ParentBone.ParentBone.transform.position + child.ParentBone.ParentBone.ProceduralRotation * child.ParentBone.transform.localPosition,
|
||||
//child.ProceduralPosition, Color.red, 1f);
|
||||
|
||||
//Debug.Log("[" + child.Index + "] diff = "
|
||||
// + angleDiffToInitPose + " exc = "
|
||||
// + exceededAngle + " fact = "
|
||||
// + angleFactor);
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
if (LimitSmoothing > Mathf.Epsilon)
|
||||
{
|
||||
float smooth = Mathf.Lerp(55f, 15f, LimitSmoothing);
|
||||
_limiting_angle_newLocal = Quaternion.SlerpUnclamped(_limiting_angle_targetInLocal, child.LastKeyframeLocalRotation, deltaForLerps * smooth * angleFactor);
|
||||
}
|
||||
else
|
||||
_limiting_angle_newLocal = Quaternion.SlerpUnclamped(_limiting_angle_targetInLocal, child.LastKeyframeLocalRotation, angleFactor);
|
||||
|
||||
|
||||
_limiting_angle_ToTargetRot = FEngineering.QToWorld(child.ParentBone.transform.rotation, _limiting_angle_newLocal);
|
||||
_limiting_limitPosition = child.ParentBone.ProceduralPosition + _limiting_angle_ToTargetRot * Vector3.Scale(child.transform.lossyScale, child.LastKeyframeLocalPosition);
|
||||
|
||||
}
|
||||
|
||||
if (angleFactor > Mathf.Epsilon) return _limiting_limitPosition; else return targetPos;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Limiting tail motion in world space position movement
|
||||
/// </summary>
|
||||
void MotionInfluenceLimiting()
|
||||
{
|
||||
if (MotionInfluence != 1f)
|
||||
{ // one - param: param = 1 -> 0 param = 0 -> 1
|
||||
|
||||
_limiting_influenceOffset = (BaseTransform.position - previousWorldPosition) * (1f - MotionInfluence);
|
||||
|
||||
if (MotionInfluenceInY < 1f)
|
||||
_limiting_influenceOffset.y = (BaseTransform.position.y - previousWorldPosition.y) * (1f - MotionInfluenceInY);
|
||||
|
||||
for (int i = 0; i < TailSegments.Count; i++)
|
||||
{
|
||||
TailSegments[i].ProceduralPosition += _limiting_influenceOffset;
|
||||
TailSegments[i].PreviousPosition += _limiting_influenceOffset;
|
||||
}
|
||||
|
||||
GhostChild.ProceduralPosition += _limiting_influenceOffset;
|
||||
GhostChild.PreviousPosition += _limiting_influenceOffset;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary> Helper gravity calculations variable to avoid GC </summary>
|
||||
Vector3 _tc_segmentGravityOffset = Vector3.zero;
|
||||
/// <summary> Helper gravity calculations variable to avoid GC </summary>
|
||||
Vector3 _tc_segmentGravityToParentDir = Vector3.zero;
|
||||
Vector3 _tc_preGravOff = Vector3.zero;
|
||||
|
||||
/// <summary>
|
||||
/// Calculating gravity parameter position offset for tail segment with some vector direction operations
|
||||
/// </summary>
|
||||
void CalculateGravityPositionOffsetForSegment(TailSegment bone)
|
||||
{
|
||||
//if (updateLoops > 0)
|
||||
{
|
||||
_tc_segmentGravityOffset = (bone.Gravity + WindEffect) * bone.BoneLengthScaled;
|
||||
_tc_segmentGravityToParentDir = bone.ProceduralPosition - bone.ParentBone.ProceduralPosition;
|
||||
|
||||
_tc_preGravOff = (_tc_segmentGravityToParentDir + _tc_segmentGravityOffset).normalized * _tc_segmentGravityToParentDir.magnitude;
|
||||
|
||||
// Keeping same length of the bone to prevent gravity effect from stretching bones but offsetting in computed direction
|
||||
bone.ProceduralPosition = bone.ParentBone.ProceduralPosition + _tc_preGravOff;
|
||||
}
|
||||
//else
|
||||
//{
|
||||
// bone.ProceduralPosition = bone.ParentBone.ProceduralPosition + _tc_preGravOff;
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Limiting movement of tail bones in selected axis
|
||||
/// </summary>
|
||||
void Axis2DLimit(TailSegment child)
|
||||
{
|
||||
child.ProceduralPosition -=
|
||||
FEngineering.VAxis2DLimit(
|
||||
child.ParentBone.transform,
|
||||
child.ParentBone.ProceduralPosition,
|
||||
child.ProceduralPosition, Axis2D);
|
||||
|
||||
}
|
||||
|
||||
|
||||
#region Distance Limiting Calculations
|
||||
|
||||
[Tooltip("If you want to use max distance fade option to smoothly disable tail animator when object is going far away from camera")]
|
||||
public bool UseMaxDistance = false;
|
||||
|
||||
[Tooltip("(By default camera transform) Measuring distance from this object to define if object is too far and not need to update tail animator")]
|
||||
public Transform DistanceFrom;
|
||||
[HideInInspector]
|
||||
public Transform _distanceFrom_Auto;
|
||||
|
||||
[Tooltip("Max distance to main camera / target object to smoothly turn off tail animator.")]
|
||||
public float MaximumDistance = 35f;
|
||||
|
||||
[Tooltip("If object in range should be detected only when is nearer than 'MaxDistance' to avoid stuttery enabled - disable switching")]
|
||||
[Range(0.0f, 1f)]
|
||||
public float MaxOutDistanceFactor = 0f;
|
||||
|
||||
[Tooltip("If distance should be measured not using Up (y) axis")]
|
||||
public bool DistanceWithoutY = false;
|
||||
|
||||
[Tooltip("Offsetting point from which we want to measure distance to target")]
|
||||
public Vector3 DistanceMeasurePoint;
|
||||
|
||||
[Tooltip("Disable fade duration in seconds")]
|
||||
[Range(0.25f, 2f)]
|
||||
public float FadeDuration = 0.75f;
|
||||
|
||||
private bool maxDistanceExceed = false;
|
||||
private Transform finalDistanceFrom;
|
||||
private bool wasCameraSearch = false;
|
||||
|
||||
/// <summary> Multiplier for blend weight when tail animator is far from camera or provided object </summary>
|
||||
private float distanceWeight = 1f;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Getting distance value from distance measure point to target position
|
||||
/// </summary>
|
||||
public float GetDistanceMeasure(Vector3 targetPosition)
|
||||
{
|
||||
if (DistanceWithoutY)
|
||||
{
|
||||
Vector3 p = BaseTransform.position + BaseTransform.TransformVector(DistanceMeasurePoint);
|
||||
Vector2 p2 = new Vector2(p.x, p.z);
|
||||
return Vector2.Distance(p2, new Vector2(targetPosition.x, targetPosition.z));
|
||||
}
|
||||
else
|
||||
return Vector3.Distance(BaseTransform.position + BaseTransform.TransformVector(DistanceMeasurePoint), targetPosition);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Handling max distance feature
|
||||
/// </summary>
|
||||
private void MaxDistanceCalculations()
|
||||
{
|
||||
|
||||
if (DistanceFrom != null)
|
||||
finalDistanceFrom = DistanceFrom;
|
||||
#region Defining distance measure reference if not found
|
||||
else
|
||||
{
|
||||
if (finalDistanceFrom == null)
|
||||
{
|
||||
if (_distanceFrom_Auto == null)
|
||||
{
|
||||
Camera c = Camera.main;
|
||||
if (c) _distanceFrom_Auto = c.transform;
|
||||
else
|
||||
{
|
||||
if (!wasCameraSearch)
|
||||
{
|
||||
#if UNITY_2023_1_OR_NEWER
|
||||
c = FindFirstObjectByType<Camera>();
|
||||
#else
|
||||
c = FindObjectOfType<Camera>();
|
||||
#endif
|
||||
if (c) _distanceFrom_Auto = c.transform;
|
||||
wasCameraSearch = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
finalDistanceFrom = _distanceFrom_Auto;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
// If we are using distance limitation
|
||||
if (MaximumDistance > 0f && finalDistanceFrom != null)
|
||||
{
|
||||
if (!maxDistanceExceed) // If look motion is not out of look range etc.
|
||||
{
|
||||
float distance = GetDistanceMeasure(finalDistanceFrom.position);
|
||||
|
||||
if (distance > MaximumDistance + MaximumDistance * MaxOutDistanceFactor)
|
||||
maxDistanceExceed = true;
|
||||
|
||||
distanceWeight += Time.unscaledDeltaTime * (1f / FadeDuration);
|
||||
if (distanceWeight > 1f) distanceWeight = 1f;
|
||||
}
|
||||
else // When disabling tail animator
|
||||
{
|
||||
// Entering back distance range
|
||||
float distance = GetDistanceMeasure(finalDistanceFrom.position);
|
||||
if (distance <= MaximumDistance) maxDistanceExceed = false;
|
||||
|
||||
distanceWeight -= Time.unscaledDeltaTime * (1f / FadeDuration);
|
||||
if (distanceWeight < 0f) distanceWeight = 0f;
|
||||
}
|
||||
}
|
||||
else // If we don't use max of distance feature
|
||||
{
|
||||
maxDistanceExceed = false;
|
||||
distanceWeight = 1f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bfe18301d3b8b4e49b7767eb91d25c7e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,81 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace FIMSpace.FTail
|
||||
{
|
||||
public partial class TailAnimator2
|
||||
{
|
||||
|
||||
#region Position
|
||||
|
||||
/// <summary> [Tail Calculations - TC] Smoothing position for _tc_bone changing _tc_smoothPos variable in iteration towards _tc_targetPos </summary>
|
||||
Vector3 TailCalculations_SmoothPosition(Vector3 from, Vector3 to, TailSegment bone)
|
||||
{
|
||||
if (SmoothingStyle == EAnimationStyle.Accelerating)
|
||||
return TailCalculations_SmoothPositionSmoothDamp(from, to, ref bone.VelocityHelper, bone.PositionSpeed);
|
||||
else if (SmoothingStyle == EAnimationStyle.Quick)
|
||||
return TailCalculations_SmoothPositionLerp(from, to, bone.PositionSpeed);
|
||||
else
|
||||
return TailCalculations_SmoothPositionLinear(from, to, bone.PositionSpeed );
|
||||
}
|
||||
|
||||
|
||||
/// <summary> Smoothing position for _tc_bone with lerp divide logics changing _tc_smoothPos variable in iteration towards _tc_targetPos </summary>
|
||||
Vector3 TailCalculations_SmoothPositionLerp(Vector3 from, Vector3 to, float speed)
|
||||
{
|
||||
return Vector3.Lerp(from, to, secPeriodDelta * speed);
|
||||
}
|
||||
|
||||
/// <summary> Smoothing position for _tc_bone with smooth damp method changing _tc_smoothPos variable in iteration towards _tc_targetPos </summary>
|
||||
Vector3 TailCalculations_SmoothPositionSmoothDamp(Vector3 from, Vector3 to, ref Vector3 velo, float speed)
|
||||
{
|
||||
return Vector3.SmoothDamp(from, to, ref velo, Mathf.LerpUnclamped(0.08f, 0.0001f, Mathf.Sqrt(Mathf.Sqrt(speed))), Mathf.Infinity, rateDelta);
|
||||
}
|
||||
|
||||
/// <summary> Smoothing position for _tc_bone linearly changing _tc_smoothPos variable in iteration towards _tc_targetPos </summary>
|
||||
Vector3 TailCalculations_SmoothPositionLinear(Vector3 from, Vector3 to, float speed)
|
||||
{
|
||||
return Vector3.MoveTowards(from, to, deltaForLerps * speed * 45f);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Rotation
|
||||
|
||||
|
||||
|
||||
/// <summary> [Tail Calculations - TC] Smoothing rotation for _tc_bone changing _tc_smoothRot variable in iteration towards _tc_targetRot </summary>
|
||||
Quaternion TailCalculations_SmoothRotation(Quaternion from, Quaternion to, TailSegment bone)
|
||||
{
|
||||
if (SmoothingStyle == EAnimationStyle.Accelerating)
|
||||
return TailCalculations_SmoothRotationSmoothDamp(from, to, ref bone.QVelocityHelper, bone.RotationSpeed);
|
||||
else
|
||||
if (SmoothingStyle == EAnimationStyle.Quick)
|
||||
return TailCalculations_SmoothRotationLerp(from, to, bone.RotationSpeed);
|
||||
else
|
||||
return TailCalculations_SmoothRotationLinear(from, to, bone.RotationSpeed);
|
||||
}
|
||||
|
||||
/// <summary> Smoothing rotation for _tc_bone with lerp divide logics changing _tc_smoothRot variable in iteration towards _tc_targetRot </summary>
|
||||
Quaternion TailCalculations_SmoothRotationLerp(Quaternion from, Quaternion to, float speed)
|
||||
{
|
||||
return Quaternion.Lerp(from, to, secPeriodDelta * speed);
|
||||
}
|
||||
|
||||
/// <summary> Smoothing rotation for _tc_bone with smooth damp method changing _tc_smoothRot variable in iteration towards _tc_targetRot </summary>
|
||||
Quaternion TailCalculations_SmoothRotationSmoothDamp(Quaternion from, Quaternion to, ref Quaternion velo, float speed)
|
||||
{
|
||||
return FEngineering.SmoothDampRotation(from, to, ref velo, Mathf.LerpUnclamped(0.25f, 0.0001f, Mathf.Sqrt(Mathf.Sqrt(speed))), rateDelta);
|
||||
}
|
||||
|
||||
/// <summary> Smoothing rotation for _tc_bone linearly changing _tc_smoothRot variable in iteration towards _tc_targetRot </summary>
|
||||
Quaternion TailCalculations_SmoothRotationLinear(Quaternion from, Quaternion to, float speed)
|
||||
{
|
||||
return (Quaternion.RotateTowards(from, to, speed * deltaForLerps * 1600f));
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d1f8936842303b74dbace3df066c79d2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,213 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace FIMSpace.FTail
|
||||
{
|
||||
public partial class TailAnimator2
|
||||
{
|
||||
/// <summary> Tail calculations start index for interations </summary>
|
||||
int _tc_startI = 0;
|
||||
/// <summary> Indexes in front of root </summary>
|
||||
int _tc_startII = 1;
|
||||
/// <summary> Delta time multiplied one itme instead of i-times </summary>
|
||||
//float _tc_offsetDelta = 0.1f;
|
||||
/// <summary> Full length of tail computed at initialize in world space, used for unify animation feature </summary>
|
||||
public float _TC_TailLength { get; private set; }
|
||||
|
||||
/// <summary> Tail calculations helper bone class instance reference </summary>
|
||||
TailSegment _tc_rootBone = null;
|
||||
|
||||
/// <summary> Tail calculations helper rotation variable to avoid GC </summary>
|
||||
Quaternion _tc_lookRot = Quaternion.identity;
|
||||
/// <summary> Tail calculations helper rotation variable to avoid GC </summary>
|
||||
Quaternion _tc_targetParentRot = Quaternion.identity;
|
||||
|
||||
/// <summary> Chain root offset rotation for shaping and auto-waving features </summary>
|
||||
Quaternion _tc_startBoneRotOffset = Quaternion.identity;
|
||||
float _tc_tangle = 1f;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Define root of chain >> _tc_rootBone - root bone of tail chain >> TailBones[0] or GhostParent
|
||||
/// </summary>
|
||||
void TailCalculations_Begin()
|
||||
{
|
||||
if (IncludeParent) // Include first bone in chain to be modified
|
||||
{
|
||||
_tc_startI = 0;
|
||||
_tc_rootBone = TailSegments[0];
|
||||
}
|
||||
else // Leaving first bone in chain intact (exclude)
|
||||
{
|
||||
_tc_startI = 1;
|
||||
if (TailSegments.Count > 1) _tc_rootBone = TailSegments[1]; else { _tc_rootBone = TailSegments[0]; _tc_startI = -1; }
|
||||
}
|
||||
|
||||
_tc_startII = _tc_startI + 1;
|
||||
if (_tc_startII > TailSegments.Count - 1) _tc_startII = -1;
|
||||
|
||||
if (Deflection > Mathf.Epsilon) if (!_pp_initialized) InitializePostProcessing();
|
||||
|
||||
|
||||
if (Tangle < 0)
|
||||
_tc_tangle = Mathf.LerpUnclamped(1f, 1.5f, Tangle + 1f);
|
||||
else
|
||||
_tc_tangle = Mathf.LerpUnclamped(1f, -4f, Tangle);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Defining start bone root reference coordinates and initial processing
|
||||
/// </summary>
|
||||
void TailSegments_UpdateRootFeatures()
|
||||
{
|
||||
// Root bone rotation offset for auto-waving feature
|
||||
if (UseWaving)
|
||||
{
|
||||
Waving_AutoSwingUpdate();
|
||||
_tc_startBoneRotOffset = (WavingRotationOffset * RotationOffset);
|
||||
}
|
||||
else
|
||||
_tc_startBoneRotOffset = RotationOffset;
|
||||
|
||||
// Sustain support
|
||||
if (Sustain > Mathf.Epsilon) Waving_SustainUpdate();
|
||||
|
||||
// Post process advanced features
|
||||
if (PostProcessingNeeded()) PostProcessing_Begin();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Processing calculated simple segment position with special effects like limiting / collision / smoothing etc.
|
||||
/// Calling methods using bone's parent variables
|
||||
/// </summary>
|
||||
void TailCalculations_SegmentPreProcessingStack(TailSegment child)
|
||||
{
|
||||
if (!UseCollision) // Basic motion without collision
|
||||
// Different update order with enable/disable collisions to avoid jittering on angle limiting
|
||||
{
|
||||
// Limit segments angles
|
||||
if (AngleLimit < 181) child.ProceduralPosition = AngleLimiting(child, child.ProceduralPosition);
|
||||
|
||||
// Smoothing motion
|
||||
if (child.PositionSpeed < 1f) child.ProceduralPosition = TailCalculations_SmoothPosition(child.PreviousPosition /*+ _limiting_influenceOffset*/, child.ProceduralPosition, child);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Smoothing motion
|
||||
if (child.PositionSpeed < 1f) child.ProceduralPosition = TailCalculations_SmoothPosition(child.PreviousPosition /*+ _limiting_influenceOffset*/, child.ProceduralPosition, child);
|
||||
|
||||
// Computing collision offset as first thing
|
||||
TailCalculations_ComputeSegmentCollisions(child, ref child.ProceduralPosition);
|
||||
|
||||
// Limit segments angles
|
||||
if (AngleLimit < 181) child.ProceduralPosition = AngleLimiting(child, child.ProceduralPosition);
|
||||
}
|
||||
|
||||
|
||||
// Control stretching
|
||||
if (MaxStretching < 1f) StretchingLimiting(child);
|
||||
|
||||
// Apply gravity
|
||||
if (!FEngineering.VIsZero(child.Gravity) || UseWind) CalculateGravityPositionOffsetForSegment(child);
|
||||
|
||||
if (Axis2D > 0) Axis2DLimit(child);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Post processing for segment if used for example deflection
|
||||
/// </summary>
|
||||
void TailCalculations_SegmentPostProcessing(TailSegment bone)
|
||||
{
|
||||
// Applying deflection
|
||||
if (Deflection > Mathf.Epsilon) Deflection_SegmentOffsetSimple(bone, ref bone.ProceduralPosition);
|
||||
|
||||
// Soon there may be more post processes
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Second iteration for segments rotation calculations
|
||||
/// Rotating segments towards calculated procedural positions with blending if used
|
||||
/// </summary>
|
||||
void TailCalculations_SegmentRotation(TailSegment child, Vector3 localOffset)
|
||||
{
|
||||
|
||||
// Calculating correct rotation towards calculated position in parent orientation
|
||||
_tc_lookRot = Quaternion.FromToRotation
|
||||
( // Support negative scale with transform direction
|
||||
child.ParentBone.transform.TransformDirection(localOffset), // Child local pos offset - direction from parent true position towards default bone postion from keyframe animation
|
||||
child.ProceduralPositionWeightBlended - child.ParentBone.ProceduralPositionWeightBlended // Direction from parent calculated position towards child target calculated postion
|
||||
);
|
||||
|
||||
// Rotating towards desired orientation
|
||||
_tc_targetParentRot = _tc_lookRot * child.ParentBone.transform.rotation;
|
||||
|
||||
if ( AnimateRoll)
|
||||
{
|
||||
_tc_targetParentRot = Quaternion.Lerp(child.ParentBone.TrueTargetRotation, _tc_targetParentRot, deltaForLerps * Mathf.LerpUnclamped(10f, 60f, child.RotationSpeed));
|
||||
}
|
||||
|
||||
// Notice than we setting parent rotation from child relation : parent rotation is dictating child position
|
||||
// Remember transform rotaiton before smoothing reference rotation !!!
|
||||
child.ParentBone.TrueTargetRotation = _tc_targetParentRot;
|
||||
|
||||
// Remembering previous value before changing to new
|
||||
child.ParentBone.PreviousPosReferenceRotation = child.ParentBone.PosRefRotation;
|
||||
|
||||
// Setting positions reference rotation separately
|
||||
if ( !AnimateRoll) if (child.RotationSpeed < 1f) _tc_targetParentRot = TailCalculations_SmoothRotation(child.ParentBone.PosRefRotation, _tc_targetParentRot, child);
|
||||
|
||||
child.ParentBone.PosRefRotation = _tc_targetParentRot;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Detached tail mode works on slightly different vector logics
|
||||
/// </summary>
|
||||
void TailCalculations_SegmentRotationDetached(TailSegment child, Vector3 localOffset)
|
||||
{
|
||||
//Quaternion tgtRot = child.ParentBone.TrueTargetRotation;
|
||||
//if (child.IsDetachable)
|
||||
//{
|
||||
// tgtRot = FEngineering.QToWorld(BaseTransform.rotation, child.ParentBone.InitialLocalRotationInRoot);
|
||||
//}
|
||||
|
||||
_tc_lookRot = Quaternion.FromToRotation
|
||||
(
|
||||
child.ParentBone.transform.TransformDirection(localOffset), // Child local pos offset - direction from parent true position towards default bone postion
|
||||
child.ProceduralPositionWeightBlended - child.ParentBone.ProceduralPositionWeightBlended // Direction from parent calculated position towards child target calculated postion
|
||||
);
|
||||
|
||||
|
||||
|
||||
_tc_targetParentRot = _tc_lookRot * child.transform.rotation;
|
||||
if (AnimateRoll) _tc_targetParentRot = Quaternion.Lerp(child.ParentBone.TrueTargetRotation, _tc_targetParentRot, deltaForLerps * Mathf.LerpUnclamped(10f, 60f, child.RotationSpeed));
|
||||
|
||||
child.ParentBone.TrueTargetRotation = _tc_targetParentRot;
|
||||
child.ParentBone.PreviousPosReferenceRotation = child.ParentBone.PosRefRotation;
|
||||
|
||||
if (!AnimateRoll) if (child.RotationSpeed < 1f) _tc_targetParentRot = TailCalculations_SmoothRotation(child.ParentBone.PosRefRotation, _tc_targetParentRot, child);
|
||||
|
||||
child.ParentBone.PosRefRotation = _tc_targetParentRot;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applying tail motion to transforms
|
||||
/// Accesing parent of bone to change it's rotation
|
||||
/// </summary>
|
||||
void TailCalculations_ApplySegmentMotion(TailSegment child)
|
||||
{
|
||||
child.ParentBone.transform.rotation = child.ParentBone.TrueTargetRotation;
|
||||
child.transform.position = child.ProceduralPositionWeightBlended;
|
||||
|
||||
child.RefreshFinalPos(child.ProceduralPositionWeightBlended);
|
||||
child.ParentBone.RefreshFinalRot(child.ParentBone.TrueTargetRotation);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 94df3f76d7ce99142bd705f911882f19
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,334 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace FIMSpace.FTail
|
||||
{
|
||||
/// <summary>
|
||||
/// FC: Calculations focused on single tail bone segments operations
|
||||
/// </summary>
|
||||
public partial class TailAnimator2
|
||||
{
|
||||
// Motion controll variables
|
||||
float _sg_springVelo = 0.5f;
|
||||
//float _sg_curl = 0.5f;
|
||||
float _sg_curly = 0.5f;
|
||||
|
||||
// Motion calculation variables
|
||||
Vector3 _sg_push;
|
||||
Vector3 _sg_targetPos;
|
||||
Vector3 _sg_targetChildWorldPosInParentFront;
|
||||
Vector3 _sg_dirToTargetParentFront;
|
||||
Quaternion _sg_orientation;
|
||||
float _sg_slitFactor = 0.5f;
|
||||
|
||||
|
||||
void TailSegment_PrepareBoneLength(TailSegment child)
|
||||
{
|
||||
// Remember bone scale referenced from initial position
|
||||
child.BoneDimensionsScaled = Vector3.Scale(child.ParentBone.transform.lossyScale * child.LengthMultiplier, child.LastKeyframeLocalPosition);
|
||||
child.BoneLengthScaled = child.BoneDimensionsScaled.magnitude; //(child.ParentBone.transform.position - child.transform.position).magnitude * child.LengthMultiplier;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Preparing motion parameters for individual segment settings
|
||||
/// </summary>
|
||||
void TailSegment_PrepareMotionParameters(TailSegment child)
|
||||
{
|
||||
//// Non-Slithery
|
||||
//_sg_curly = Mathf.LerpUnclamped(0.6f, 0.15f, child.Curling);
|
||||
//_sg_springVelo = Mathf.LerpUnclamped(0.65f, 0.9f, child.Springiness);
|
||||
|
||||
//// Slithery Blend
|
||||
//_sg_curly = Mathf.Lerp(_sg_curly, Mathf.LerpUnclamped(0.99f, 0.135f, child.Curling), child.Slithery);
|
||||
//_sg_springVelo = Mathf.Lerp(_sg_springVelo, Mathf.LerpUnclamped(0.0f, 0.8f, child.Springiness), child.Slithery);
|
||||
|
||||
// Non-Slithery
|
||||
_sg_curly = Mathf.LerpUnclamped(0.5f, 0.125f, child.Curling);
|
||||
_sg_springVelo = Mathf.LerpUnclamped(0.65f, 0.9f, child.Springiness);
|
||||
|
||||
// Slithery Blend
|
||||
_sg_curly = Mathf.Lerp(_sg_curly, Mathf.LerpUnclamped(0.95f, 0.135f, child.Curling), child.Slithery);
|
||||
_sg_springVelo = Mathf.Lerp(_sg_springVelo, Mathf.LerpUnclamped(0.1f, 0.85f, child.Springiness), child.Slithery);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Preparing segment positioning parameters
|
||||
/// </summary>
|
||||
void TailSegment_PrepareVelocity(TailSegment child)
|
||||
{
|
||||
// Velocity change check
|
||||
_sg_push = (child.ProceduralPosition - child.PreviousPosition);
|
||||
|
||||
// Remember actual position after using previous position memory
|
||||
child.PreviousPosition = child.ProceduralPosition;
|
||||
|
||||
// Collision slippery modify
|
||||
float swinginess = _sg_springVelo;
|
||||
if (child.CollisionContactFlag) swinginess *= child.Slippery;
|
||||
|
||||
// Tail Motion velocity motion base calculations
|
||||
child.ProceduralPosition += _sg_push * swinginess;
|
||||
|
||||
// Remember previous push for sustain feature
|
||||
child.PreviousPush = _sg_push;
|
||||
}
|
||||
|
||||
|
||||
void TailSegment_PrepareRotation(TailSegment child)
|
||||
{
|
||||
_sg_targetChildWorldPosInParentFront = child.ParentBone.ProceduralPosition + TailSegment_GetSwingRotation(child, _sg_slitFactor) * child.BoneDimensionsScaled; // Local offset scaled with custom rotation
|
||||
}
|
||||
|
||||
void TailSegment_PrepareRotationDetached(TailSegment child)
|
||||
{
|
||||
_sg_targetChildWorldPosInParentFront = child.ParentBone.ProceduralPosition + TailSegment_GetSwingRotationDetached(child, _sg_slitFactor) * child.BoneDimensionsScaled; // Local offset scaled with custom rotation
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base position processing for swingy parameters animation
|
||||
/// Changing UnprocessedPosition value in child argument
|
||||
/// </summary>
|
||||
void TailSegment_BaseSwingProcessing(TailSegment child)
|
||||
{
|
||||
_sg_slitFactor = child.Slithery; // Collision fixing for slithery calculations
|
||||
if (child.CollisionContactRelevancy > 0f) _sg_slitFactor = ReflectCollision; // (0.5f - Mathf.Min(0.5f, child.CollisionContactRelevancy * 10f) ) * child.Slithery;
|
||||
|
||||
_sg_dirToTargetParentFront = _sg_targetChildWorldPosInParentFront - child.ProceduralPosition;
|
||||
|
||||
// Unifying bendiness parameters on tail length and segments count then translating
|
||||
if (UnifyBendiness > 0f)
|
||||
child.ProceduralPosition += _sg_dirToTargetParentFront * secPeriodDelta *
|
||||
_sg_curly * TailSegment_GetUnifiedBendinessMultiplier(child);
|
||||
else
|
||||
// Translating toward target position without restricitons
|
||||
child.ProceduralPosition += _sg_dirToTargetParentFront * _sg_curly * secPeriodDelta;
|
||||
|
||||
if (Tangle != 0f)
|
||||
if (child.Slithery >= 1f)
|
||||
child.ProceduralPosition = Vector3.LerpUnclamped(child.ProceduralPosition, _sg_targetChildWorldPosInParentFront, _tc_tangle);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Processing position for blending weight
|
||||
/// </summary>
|
||||
void TailSegment_PreRotationPositionBlend(TailSegment child)
|
||||
{
|
||||
if (child.BlendValue * conditionalWeight < 1f)
|
||||
child.ProceduralPositionWeightBlended = Vector3.LerpUnclamped(
|
||||
child.transform.position, child.ProceduralPosition, child.BlendValue * conditionalWeight);
|
||||
//child.ParentBone.transform.TransformVector(child.LastFinalLocalPosition), child.ProceduralPosition, child.BlendValue);
|
||||
else
|
||||
child.ProceduralPositionWeightBlended = child.ProceduralPosition;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Calculations for slithery tail motion reference parent rotation
|
||||
/// </summary>
|
||||
Quaternion TailSegment_RotationSlithery(TailSegment child)
|
||||
{
|
||||
|
||||
if (!FEngineering.QIsZero(child.Curving))
|
||||
{
|
||||
return GetSlitheryReferenceRotation(child) // Back rotation for parent of parent bone
|
||||
* child.Curving // Curving
|
||||
* child.ParentBone.LastKeyframeLocalRotation; // Sync with animator
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetSlitheryReferenceRotation(child) // Back rotation for parent of parent bone
|
||||
* child.ParentBone.LastKeyframeLocalRotation; // Sync with animator
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculations for slithery tail motion reference parent rotation
|
||||
/// </summary>
|
||||
Quaternion TailSegment_RotationSlitheryDetached(TailSegment child)
|
||||
{
|
||||
|
||||
if (!FEngineering.QIsZero(child.Curving))
|
||||
{
|
||||
return GetSlitheryReferenceRotation(child) // Back rotation for parent of parent bone
|
||||
* child.Curving // Curving
|
||||
* child.ParentBone.InitialLocalRotation; // Sync with animator
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetSlitheryReferenceRotation(child) // Back rotation for parent of parent bone
|
||||
* child.ParentBone.InitialLocalRotation; // Sync with animator
|
||||
}
|
||||
}
|
||||
|
||||
Quaternion GetSlitheryReferenceRotation(TailSegment child)
|
||||
{
|
||||
if (child.Slithery <= 1f)
|
||||
return child.ParentBone.ParentBone.PosRefRotation;
|
||||
else
|
||||
{
|
||||
return Quaternion.LerpUnclamped(child.ParentBone.ParentBone.PosRefRotation,
|
||||
child.ParentBone.ParentBone.PreviousPosReferenceRotation, (child.Slithery - 1f) * 5f);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculations for stiff tail motion reference parent rotation
|
||||
/// </summary>
|
||||
Quaternion TailSegment_RotationStiff(TailSegment child)
|
||||
{
|
||||
// Curving feature
|
||||
if (!FEngineering.QIsZero(child.Curving))
|
||||
{
|
||||
return child.ParentBone.transform.rotation * // Parent bone rotation
|
||||
MultiplyQ(child.Curving, child.Index * 2f) // Curving multiplier
|
||||
;
|
||||
}
|
||||
else // No Curving
|
||||
{
|
||||
return child.ParentBone.transform.rotation; // Parent bone rotation
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defining style of tail motion
|
||||
/// </summary>
|
||||
Quaternion TailSegment_GetSwingRotation(TailSegment child, float curlFactor)
|
||||
{
|
||||
if (curlFactor >= 1f) // Slithery == 1
|
||||
{
|
||||
return TailSegment_RotationSlithery(child);
|
||||
}
|
||||
else if (curlFactor > Mathf.Epsilon) // Blend non slithery with slithery feature
|
||||
{
|
||||
return Quaternion.LerpUnclamped(
|
||||
TailSegment_RotationStiff(child), // A - Stiff
|
||||
TailSegment_RotationSlithery(child), // B - Slithery
|
||||
curlFactor); // Lerp
|
||||
}
|
||||
else // Slithery == 0
|
||||
return TailSegment_RotationStiff(child);
|
||||
}
|
||||
|
||||
|
||||
Quaternion TailSegment_GetSwingRotationDetached(TailSegment child, float curlFactor)
|
||||
{
|
||||
if (curlFactor >= 1f) // Slithery == 1
|
||||
{
|
||||
return TailSegment_RotationSlitheryDetached(child);
|
||||
}
|
||||
else if (curlFactor > Mathf.Epsilon) // Blend non slithery with slithery feature
|
||||
{
|
||||
return Quaternion.LerpUnclamped(
|
||||
TailSegment_RotationStiff(child), // A - Stiff
|
||||
TailSegment_RotationSlitheryDetached(child), // B - Slithery
|
||||
curlFactor); // Lerp
|
||||
}
|
||||
else // Slithery == 0
|
||||
return TailSegment_RotationStiff(child);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Calculating multiplier value for translation based on tail length and segments count
|
||||
/// To make different length and segment count tails behave in similar way
|
||||
/// </summary>
|
||||
float TailSegment_GetUnifiedBendinessMultiplier(TailSegment child)
|
||||
{
|
||||
// When short tail -> 0.2f / 1.25f -> 0.16 -> We want here small mul value
|
||||
// When long and many segments -> 0.1f / 8f -> 0.0125 -> We want here high mul value
|
||||
float segmentRatio = (child.BoneLength / _TC_TailLength);
|
||||
segmentRatio = Mathf.Pow(segmentRatio, 0.5f);
|
||||
|
||||
if (segmentRatio == 0f) segmentRatio = 1f; // No dividing by zero ¯\_(ツ)_/¯
|
||||
|
||||
float unifyMul = (_sg_curly / segmentRatio) / 2f;
|
||||
unifyMul = Mathf.LerpUnclamped(_sg_curly, unifyMul, UnifyBendiness);
|
||||
|
||||
// Clamp extreme values
|
||||
if (unifyMul < 0.15f) unifyMul = 0.15f; else if (unifyMul > 1.4f) unifyMul = 1.4f;
|
||||
|
||||
//Debug.Log(System.Math.Round( unifyMul, 3) + " Count = " + TailSegments.Count + " child.BoneLength " + child.BoneLength + "_tc_tailLength " + _TC_TailLength + "curl = " + _sg_curly + " Mul " + unifyMul + " segmentRatio " + segmentRatio + " mixed = " + (_sg_curly * unifyMul) );
|
||||
return unifyMul;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Updateing root parent bone with component parameters and features
|
||||
/// </summary>
|
||||
public void TailSegments_UpdateCoordsForRootBone(TailSegment parent)
|
||||
{
|
||||
TailSegment root = TailSegments[0];
|
||||
root.transform.localRotation = root.LastKeyframeLocalRotation * _tc_startBoneRotOffset;
|
||||
//parent.transform.localRotation = parent.LastKeyframeLocalRotation * _tc_startBoneRotOffset;
|
||||
|
||||
parent.PreviousPosReferenceRotation = parent.PosRefRotation;
|
||||
parent.PosRefRotation = parent.transform.rotation;
|
||||
|
||||
parent.PreviousPosition = parent.ProceduralPosition;
|
||||
parent.ProceduralPosition = parent.transform.position;
|
||||
if (DetachChildren) root.TrueTargetRotation = root.transform.rotation;
|
||||
|
||||
parent.RefreshFinalPos(parent.transform.position);
|
||||
|
||||
parent.ProceduralPositionWeightBlended = parent.ProceduralPosition;
|
||||
|
||||
if (parent.ParentBone.transform != null)
|
||||
{
|
||||
// Update of ghost parent for slithery motion
|
||||
parent.ParentBone.PreviousPosReferenceRotation = parent.ParentBone.PosRefRotation;
|
||||
parent.ParentBone.PreviousPosition = parent.ParentBone.ProceduralPosition;
|
||||
|
||||
parent.ParentBone.ProceduralPosition = parent.ParentBone.transform.position;
|
||||
parent.ParentBone.PosRefRotation = parent.ParentBone.transform.rotation;
|
||||
|
||||
parent.ParentBone.ProceduralPositionWeightBlended = parent.ParentBone.ProceduralPosition;
|
||||
}
|
||||
|
||||
TailSegments[_tc_startI].ChildBone.PreviousPosition += _waving_sustain;
|
||||
root.RefreshKeyLocalPosition();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Begin update operations for additionaly genrated child bone of chain
|
||||
/// </summary>
|
||||
public void TailCalculations_UpdateArtificialChildBone(TailSegment child)
|
||||
{
|
||||
// Pre processing with limiting, gravity etc.
|
||||
//TailCalculations_SegmentPreProcessingStack(lastChild);
|
||||
|
||||
//// Blending animation weight
|
||||
//TailSegment_PreRotationPositionBlend(lastChild);
|
||||
|
||||
if (DetachChildren) TailSegment_PrepareRotationDetached(child); else TailSegment_PrepareRotation(child);
|
||||
TailSegment_BaseSwingProcessing(child);
|
||||
|
||||
if (child.PositionSpeed < 1f) child.ProceduralPosition = TailCalculations_SmoothPosition(child.PreviousPosition /*+ _limiting_influenceOffset*/, child.ProceduralPosition, child);
|
||||
|
||||
if (MaxStretching < 1f) StretchingLimiting(child);
|
||||
|
||||
if (!FEngineering.VIsZero(child.Gravity) || UseWind) CalculateGravityPositionOffsetForSegment(child);
|
||||
|
||||
if (Axis2D > 0) Axis2DLimit(child);
|
||||
|
||||
child.CollisionContactRelevancy = -1f;
|
||||
|
||||
// Blending or just setting target position
|
||||
if (child.BlendValue * conditionalWeight < 1f)
|
||||
child.ProceduralPositionWeightBlended = Vector3.LerpUnclamped(
|
||||
child.ParentBone.transform.TransformPoint(child.LastKeyframeLocalPosition), child.ProceduralPosition, child.BlendValue * conditionalWeight);
|
||||
else
|
||||
child.ProceduralPositionWeightBlended = child.ProceduralPosition;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Refreshing position for additionaly generated parent bone
|
||||
/// </summary>
|
||||
public void Editor_TailCalculations_RefreshArtificialParentBone()
|
||||
{
|
||||
GhostParent.ProceduralPosition = GhostParent.transform.position + FEngineering.TransformVector(GhostParent.transform.rotation, GhostParent.transform.lossyScale, GhostParent.LocalOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 90e74887a690e1c44b4c416583a50f76
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,255 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace FIMSpace.FTail
|
||||
{
|
||||
public partial class TailAnimator2
|
||||
{
|
||||
|
||||
void SimulateTailMotionFrame(bool pp)
|
||||
{
|
||||
#region Prepare base positions calculation for tail segments to use in coords calculations and as reference
|
||||
|
||||
TailSegments_UpdateRootFeatures();
|
||||
|
||||
TailSegments_UpdateCoordsForRootBone(_tc_rootBone);
|
||||
|
||||
if (pp) PostProcessing_ReferenceUpdate();
|
||||
|
||||
|
||||
if (_tc_startI > -1)
|
||||
{
|
||||
TailSegment child = TailSegments[_tc_startI]; // Used in while() loops below
|
||||
// Going in while is 2x faster than for(i;i;i) loop
|
||||
|
||||
if (!DetachChildren)
|
||||
{
|
||||
while (child != GhostChild)
|
||||
{
|
||||
// Remember bone scale referenced from initial position
|
||||
child.BoneDimensionsScaled = Vector3.Scale(child.ParentBone.transform.lossyScale * child.LengthMultiplier, child.LastKeyframeLocalPosition);
|
||||
child.BoneLengthScaled = child.BoneDimensionsScaled.magnitude; //(child.ParentBone.transform.position - child.transform.position).magnitude * child.LengthMultiplier;
|
||||
|
||||
// Preparing parameter values adapted to stiff and slithery character and blended
|
||||
TailSegment_PrepareBoneLength(child);
|
||||
TailSegment_PrepareMotionParameters(child);
|
||||
|
||||
// Velocity changes detection
|
||||
TailSegment_PrepareVelocity(child);
|
||||
|
||||
child = child.ChildBone;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (child != GhostChild)
|
||||
{
|
||||
// Remember bone scale referenced from initial position
|
||||
child.BoneDimensionsScaled = Vector3.Scale(child.ParentBone.transform.lossyScale * child.LengthMultiplier, child.InitialLocalPosition);
|
||||
child.BoneLengthScaled = child.BoneDimensionsScaled.magnitude; //(child.ParentBone.transform.position - child.transform.position).magnitude * child.LengthMultiplier;
|
||||
TailSegment_PrepareMotionParameters(child);
|
||||
TailSegment_PrepareVelocity(child);
|
||||
child = child.ChildBone;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Udpate for artificial end bone
|
||||
TailSegment_PrepareBoneLength(GhostChild);
|
||||
TailSegment_PrepareMotionParameters(GhostChild);
|
||||
TailSegment_PrepareVelocity(GhostChild);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Processing segments, calculating full target coords and apply to transforms
|
||||
|
||||
if (_tc_startII > -1)
|
||||
{
|
||||
// Ignoring root related calculations
|
||||
TailSegment child = TailSegments[_tc_startII];
|
||||
|
||||
if (!DetachChildren)
|
||||
{
|
||||
while (child != GhostChild)
|
||||
{
|
||||
TailSegment_PrepareRotation(child);
|
||||
TailSegment_BaseSwingProcessing(child);
|
||||
|
||||
// Pre processing with limiting, gravity etc.
|
||||
TailCalculations_SegmentPreProcessingStack(child);
|
||||
|
||||
if (pp) TailCalculations_SegmentPostProcessing(child);
|
||||
|
||||
// Blending animation weight
|
||||
TailSegment_PreRotationPositionBlend(child);
|
||||
|
||||
child = child.ChildBone;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (child != GhostChild)
|
||||
{
|
||||
TailSegment_PrepareRotationDetached(child);
|
||||
TailSegment_BaseSwingProcessing(child);
|
||||
TailCalculations_SegmentPreProcessingStack(child);
|
||||
if (pp) TailCalculations_SegmentPostProcessing(child);
|
||||
TailSegment_PreRotationPositionBlend(child);
|
||||
child = child.ChildBone;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Applying processing for artificial child bone without transform
|
||||
TailCalculations_UpdateArtificialChildBone(GhostChild);
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
void UpdateTailAlgorithm()
|
||||
{
|
||||
TailCalculations_Begin(); // Root definition
|
||||
|
||||
if (DeltaType != EFDeltaType.UnscaledDeltaTime && Time.timeScale == 0f) // Pause motion
|
||||
{
|
||||
if (_tc_startI > -1)
|
||||
{
|
||||
TailSegment segment = TailSegments[_tc_startI];
|
||||
|
||||
while (segment != null)
|
||||
{
|
||||
if (segment.transform)
|
||||
{
|
||||
segment.transform.position = segment.LastFinalPosition;
|
||||
segment.transform.rotation = segment.LastFinalRotation;
|
||||
}
|
||||
else break;
|
||||
|
||||
segment = segment.ChildBone;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (framesToSimulate != 0) // If framerate not defined then framesToSimulate is always == 1
|
||||
{
|
||||
|
||||
if (UseCollision) BeginCollisionsUpdate(); // Updating colliders to collide with
|
||||
|
||||
// If post processing is needed we computing reference coordinates
|
||||
bool postProcesses = PostProcessingNeeded();
|
||||
|
||||
MotionInfluenceLimiting();
|
||||
|
||||
for (int i = 0; i < framesToSimulate; i++) // Simulating update frames
|
||||
SimulateTailMotionFrame(postProcesses);
|
||||
|
||||
// Updating root bone position
|
||||
TailSegments[_tc_startI].transform.position = TailSegments[_tc_startI].ProceduralPositionWeightBlended;
|
||||
TailSegments[_tc_startI].RefreshFinalPos(TailSegments[_tc_startI].ProceduralPositionWeightBlended);
|
||||
//TailSegments[_tc_startI].RefreshFinalLocalPos(TailSegments[_tc_startI].transform.localPosition);
|
||||
|
||||
if (!DetachChildren) // When using common algorithm
|
||||
{
|
||||
// Applying calculated coords to transforms
|
||||
if (_tc_startII > -1)
|
||||
{
|
||||
TailSegment child = TailSegments[_tc_startII]; // Used in while() loops below
|
||||
while (child != GhostChild)
|
||||
{
|
||||
// Calculate rotation
|
||||
TailCalculations_SegmentRotation(child, child.LastKeyframeLocalPosition);
|
||||
|
||||
// Apply coords to segments
|
||||
TailCalculations_ApplySegmentMotion(child);
|
||||
child = child.ChildBone;
|
||||
}
|
||||
}
|
||||
}
|
||||
else // Detached mode needs some changes
|
||||
{
|
||||
#region Detached Mode
|
||||
|
||||
if (_tc_startII > -1)
|
||||
{
|
||||
TailSegment child = TailSegments[_tc_startII]; // Used in while() loops below
|
||||
while (child != GhostChild)
|
||||
{
|
||||
TailCalculations_SegmentRotation(child, child.InitialLocalPosition);
|
||||
//TailCalculations_SegmentRotationDetached(child, child.InitialLocalPosition);
|
||||
TailCalculations_ApplySegmentMotion(child);
|
||||
child = child.ChildBone;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
// If ghost child has transform let's apply motion too (change rotation of last bone)
|
||||
TailCalculations_SegmentRotation(GhostChild, GhostChild.LastKeyframeLocalPosition);
|
||||
GhostChild.ParentBone.transform.rotation = GhostChild.ParentBone.TrueTargetRotation;
|
||||
GhostChild.ParentBone.RefreshFinalRot(GhostChild.ParentBone.TrueTargetRotation);
|
||||
|
||||
if (GhostChild.transform)
|
||||
{
|
||||
GhostChild.RefreshFinalPos(GhostChild.transform.position);
|
||||
GhostChild.RefreshFinalRot(GhostChild.transform.rotation);
|
||||
}
|
||||
}
|
||||
else // Skipping tail motion simulation and just applying coords computed lately
|
||||
// Executed only when using target UpdateRate
|
||||
{
|
||||
|
||||
if (InterpolateRate)
|
||||
{
|
||||
secPeriodDelta = rateDelta / 24f;
|
||||
deltaForLerps = secPeriodDelta; // Unify delta value not amplified -> 1f / rate
|
||||
|
||||
SimulateTailMotionFrame(PostProcessingNeeded());
|
||||
|
||||
if (_tc_startII > -1)
|
||||
{
|
||||
TailSegment child = TailSegments[_tc_startII];
|
||||
while (child != GhostChild)
|
||||
{
|
||||
TailCalculations_SegmentRotation(child, child.LastKeyframeLocalPosition);
|
||||
TailCalculations_ApplySegmentMotion(child);
|
||||
child = child.ChildBone;
|
||||
}
|
||||
}
|
||||
|
||||
TailCalculations_SegmentRotation(GhostChild, GhostChild.LastKeyframeLocalPosition);
|
||||
GhostChild.ParentBone.transform.rotation = GhostChild.ParentBone.TrueTargetRotation;
|
||||
GhostChild.ParentBone.RefreshFinalRot(GhostChild.ParentBone.TrueTargetRotation);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_tc_startI > -1)
|
||||
{
|
||||
TailSegment segment = TailSegments[_tc_startI];
|
||||
|
||||
while (segment != null)
|
||||
{
|
||||
if (segment.transform)
|
||||
{
|
||||
segment.transform.position = segment.LastFinalPosition;
|
||||
segment.transform.rotation = segment.LastFinalRotation;
|
||||
}
|
||||
else break;
|
||||
|
||||
segment = segment.ChildBone;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6fd7b67b43fe5784cb55474315c6c30e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,396 @@
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FIMSpace.FTail
|
||||
{
|
||||
public partial class TailAnimator2
|
||||
{
|
||||
/// <summary> For resetting tail procedural data when just enabling animator </summary>
|
||||
bool wasDisabled = true;
|
||||
/// <summary> Just selected delta value from Time.delta unmodified </summary>
|
||||
float justDelta = 0.016f;
|
||||
/// <summary> Delta used for component logics -> it's value is near full 1f </summary>
|
||||
float secPeriodDelta = 0.5f;
|
||||
/// <summary> Delta for pos = Lerp(pos, target) operations -> It's value is desired to be around 0.016f but much higher in higher fps domain </summary>
|
||||
float deltaForLerps = 0.016f;
|
||||
/// <summary> Helper delta for target update rate usage -> -> It's value is desired to be 1f / targetRate </summary>
|
||||
float rateDelta = 0.016f;
|
||||
|
||||
/// <summary> Helper for calculating stable delta calculations </summary>
|
||||
protected float collectedDelta = 0f;
|
||||
/// <summary> How many udpate loops should be done according to stable update rate </summary>
|
||||
protected int framesToSimulate = 1;
|
||||
protected int previousframesToSimulate = 1;
|
||||
|
||||
bool updateTailAnimator = false;
|
||||
|
||||
/// <summary>
|
||||
/// Conditions to do any calculations within Tail Animator
|
||||
/// </summary>
|
||||
void CheckIfTailAnimatorShouldBeUpdated()
|
||||
{
|
||||
if (!initialized)
|
||||
{
|
||||
if (StartAfterTPose)
|
||||
{
|
||||
startAfterTPoseCounter++;
|
||||
if (startAfterTPoseCounter > 6) Init();
|
||||
}
|
||||
|
||||
updateTailAnimator = false;
|
||||
return;
|
||||
}
|
||||
|
||||
#region Debug "`" disable key for editor only
|
||||
|
||||
#if UNITY_EDITOR
|
||||
#if ENABLE_LEGACY_INPUT_MANAGER
|
||||
if (Input.GetKey(KeyCode.BackQuote))
|
||||
{
|
||||
updateTailAnimator = false;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
if (UseMaxDistance)
|
||||
{
|
||||
MaxDistanceCalculations();
|
||||
conditionalWeight = OverrideWeight * distanceWeight;
|
||||
}
|
||||
else
|
||||
conditionalWeight = OverrideWeight;
|
||||
|
||||
|
||||
#region Force disable transition implementation
|
||||
|
||||
if (_forceDisable) // fade to disabled state
|
||||
{
|
||||
if (FadeDuration > 0f)
|
||||
{
|
||||
_forceDisableElapsed += Time.unscaledDeltaTime * (1f / FadeDuration);
|
||||
if (_forceDisableElapsed > 1f) _forceDisableElapsed = 1f;
|
||||
}
|
||||
else
|
||||
_forceDisableElapsed = 1f;
|
||||
|
||||
conditionalWeight *= 1f - _forceDisableElapsed;
|
||||
}
|
||||
else // Fade back in
|
||||
{
|
||||
if (_forceDisableElapsed > 0f)
|
||||
if (FadeDuration > 0f)
|
||||
{
|
||||
_forceDisableElapsed -= Time.unscaledDeltaTime * (1f / FadeDuration);
|
||||
if (_forceDisableElapsed < 0f) _forceDisableElapsed = 0f;
|
||||
conditionalWeight *= 1f - _forceDisableElapsed;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
if (DisabledByInvisibility()) return;
|
||||
|
||||
//#region Triggering Animate Physics Support
|
||||
|
||||
//if (AnimatePhysics)
|
||||
//{
|
||||
// if (!animatePhysicsWorking) StartCoroutine(AnimatePhysicsClock());
|
||||
// if (!triggerAnimatePhysics) { updateTailAnimator = false; return; } else triggerAnimatePhysics = false;
|
||||
//}
|
||||
|
||||
//#endregion
|
||||
|
||||
if (UseCollision) if (!collisionInitialized) SetupSphereColliders();
|
||||
|
||||
if (TailSegments.Count == 0)
|
||||
{
|
||||
Debug.LogError("[TAIL ANIMATOR] No tail bones defined in " + name + " !");
|
||||
initialized = false;
|
||||
updateTailAnimator = false;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Enabling / disabling with blending value
|
||||
if (TailAnimatorAmount * conditionalWeight <= Mathf.Epsilon)
|
||||
{
|
||||
wasDisabled = true;
|
||||
updateTailAnimator = false;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (wasDisabled)
|
||||
{
|
||||
User_ReposeTail();
|
||||
previousWorldPosition = transform.position;
|
||||
wasDisabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (IncludeParent) if (TailSegments.Count > 0) if (!TailSegments[0].transform.parent) IncludeParent = false;
|
||||
|
||||
if (TailSegments.Count < 1)
|
||||
{
|
||||
updateTailAnimator = false;
|
||||
return;
|
||||
}
|
||||
|
||||
updateTailAnimator = true;
|
||||
}
|
||||
|
||||
|
||||
public bool DisabledByInvisibility()
|
||||
{
|
||||
if (OptimizeWithMesh != null)
|
||||
{
|
||||
bool somethingVisible = false;
|
||||
if (OptimizeWithMesh.isVisible) somethingVisible = true;
|
||||
else
|
||||
{
|
||||
if (OptimizeWithMeshes != null)
|
||||
if (OptimizeWithMeshes.Length > 0)
|
||||
for (int i = 0; i < OptimizeWithMeshes.Length; i++)
|
||||
{
|
||||
if (OptimizeWithMeshes[i] == null) continue;
|
||||
if (OptimizeWithMeshes[i].isVisible) { somethingVisible = true; break; }
|
||||
}
|
||||
}
|
||||
|
||||
if (somethingVisible == false) { updateTailAnimator = false; return true; }
|
||||
}
|
||||
|
||||
return false; // Not Disabled
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Just defining delta time for component operations
|
||||
/// </summary>
|
||||
void DeltaTimeCalculations()
|
||||
{
|
||||
if (UpdateRate > 0) // If we setted target update rate
|
||||
{
|
||||
switch (DeltaType)
|
||||
{
|
||||
case EFDeltaType.SafeDelta: case EFDeltaType.DeltaTime: justDelta = Time.deltaTime / Mathf.Clamp(Time.timeScale, 0.01f, 1f); break;
|
||||
case EFDeltaType.SmoothDeltaTime: justDelta = Time.smoothDeltaTime; break;
|
||||
case EFDeltaType.UnscaledDeltaTime: justDelta = Time.unscaledDeltaTime; break;
|
||||
case EFDeltaType.FixedDeltaTime: justDelta = Time.fixedDeltaTime; break;
|
||||
}
|
||||
|
||||
justDelta *= TimeScale;
|
||||
secPeriodDelta = 1f;
|
||||
deltaForLerps = secPeriodDelta;
|
||||
rateDelta = 1f / (float)UpdateRate;
|
||||
|
||||
StableUpdateRateCalculations();
|
||||
}
|
||||
else // Unlimited update rate
|
||||
{
|
||||
switch (DeltaType)
|
||||
{
|
||||
case EFDeltaType.SafeDelta: justDelta = Mathf.Lerp(justDelta, GetClampedSmoothDelta(), 0.075f); break;
|
||||
case EFDeltaType.DeltaTime: justDelta = Time.deltaTime; break;
|
||||
case EFDeltaType.SmoothDeltaTime: justDelta = Time.smoothDeltaTime; break;
|
||||
case EFDeltaType.UnscaledDeltaTime: justDelta = Time.unscaledDeltaTime; break;
|
||||
case EFDeltaType.FixedDeltaTime: justDelta = Time.fixedDeltaTime; break;
|
||||
}
|
||||
|
||||
rateDelta = justDelta;
|
||||
deltaForLerps = Mathf.Pow(secPeriodDelta, 0.1f) * 0.02f;
|
||||
justDelta *= TimeScale;
|
||||
|
||||
// Helper parameter to not calculate "*60" i-times
|
||||
secPeriodDelta = Mathf.Min(1f, justDelta * 60f);
|
||||
|
||||
framesToSimulate = 1;
|
||||
previousframesToSimulate = 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Calculating how many update loops should be done in this frame according to target update rate and elapsed deltaTime
|
||||
/// </summary>
|
||||
void StableUpdateRateCalculations()
|
||||
{
|
||||
previousframesToSimulate = framesToSimulate; // Remembering how many loops used in this frame for bones animation calibration in next frame
|
||||
collectedDelta += justDelta; // Collecting delta time from game frames
|
||||
framesToSimulate = 0; // Collecting delta for [one second] div by [UpdateRate] update so for one frame in static defined time rate
|
||||
|
||||
while (collectedDelta >= rateDelta) // Collected delta is big enough to do tail motion frame
|
||||
{
|
||||
collectedDelta -= rateDelta;
|
||||
framesToSimulate += 1;
|
||||
if (framesToSimulate >= 3) { collectedDelta = 0; break; } // Simulating up to 3 frames update in one unity game frame
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Preparing not animated bones, if animated they will be changed after Update() and before LateUpdate() by Unity Animator
|
||||
/// </summary>
|
||||
void PreCalibrateBones()
|
||||
{
|
||||
TailSegment child = TailSegments[0];
|
||||
|
||||
while (child != GhostChild)
|
||||
{
|
||||
child.PreCalibrate();
|
||||
child = child.ChildBone;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Preparing bones for animation synchronized with keyframe animations
|
||||
/// </summary>
|
||||
void CalibrateBones()
|
||||
{
|
||||
if (UseIK)
|
||||
if (IKBlend > 0f)
|
||||
{
|
||||
UpdateIK();
|
||||
}
|
||||
|
||||
_limiting_stretchingHelperTooLong = Mathf.Lerp(0.4f, 0.0f, MaxStretching);
|
||||
_limiting_stretchingHelperTooShort = _limiting_stretchingHelperTooLong * 1.5f;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Checking for null referencees in ghost chain list
|
||||
/// </summary>
|
||||
public void CheckForNullsInGhostChain()
|
||||
{
|
||||
if (_TransformsGhostChain == null) _TransformsGhostChain = new System.Collections.Generic.List<Transform>();
|
||||
for (int i = _TransformsGhostChain.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (_TransformsGhostChain[i] == null) _TransformsGhostChain.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary> Helper variable for start after t-pose feature </summary>
|
||||
int startAfterTPoseCounter;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Limiting smooth delta in certain ranges to prevent jittery
|
||||
/// </summary>
|
||||
float GetClampedSmoothDelta()
|
||||
{
|
||||
return Mathf.Clamp(Time.smoothDeltaTime, 0f, 0.25f);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Helper quaternion multiply method for non-slithery motion
|
||||
/// </summary>
|
||||
Quaternion MultiplyQ(Quaternion rotation, float times)
|
||||
{
|
||||
return Quaternion.AngleAxis(rotation.x * Mathf.Rad2Deg * times, Vector3.right) *
|
||||
Quaternion.AngleAxis(rotation.z * Mathf.Rad2Deg * times, Vector3.forward) *
|
||||
Quaternion.AngleAxis(rotation.y * Mathf.Rad2Deg * times, Vector3.up);
|
||||
}
|
||||
|
||||
|
||||
#region Curves Operations
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Evaluating value for tail segment from given clamped curve
|
||||
/// </summary>
|
||||
public float GetValueFromCurve(int i, AnimationCurve c)
|
||||
{
|
||||
if (!initialized) return c.Evaluate((float)i / (float)_TransformsGhostChain.Count);
|
||||
else
|
||||
return c.Evaluate(TailSegments[i].IndexOverlLength);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Clamping curve keys to fit in given bounds
|
||||
/// </summary>
|
||||
public AnimationCurve ClampCurve(AnimationCurve a, float timeStart, float timeEnd, float lowest, float highest)
|
||||
{
|
||||
Keyframe[] keys = a.keys;
|
||||
|
||||
for (int i = 0; i < keys.Length; i++)
|
||||
{
|
||||
if (keys[i].time < timeStart) keys[i].time = timeStart; else if (keys[i].time > timeEnd) keys[i].time = timeEnd;
|
||||
if (keys[i].value < lowest) keys[i].value = lowest; else if (keys[i].value > highest) keys[i].value = highest;
|
||||
}
|
||||
|
||||
a.keys = keys;
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Checking if curve keyframes are not equal
|
||||
/// </summary>
|
||||
//public bool KeysChanged(Keyframe[] a, Keyframe[] b)
|
||||
//{
|
||||
// if (a == null || b == null) return true;
|
||||
// if (a.Length != b.Length) return true;
|
||||
|
||||
// for (int i = 0; i < a.Length; i++)
|
||||
// {
|
||||
// if (a[i].time != b[i].time) return true;
|
||||
// if (a[i].value != b[i].value) return true;
|
||||
// if (a[i].inTangent != b[i].inTangent) return true;
|
||||
// if (a[i].outTangent != b[i].outTangent) return true;
|
||||
// }
|
||||
|
||||
// return false;
|
||||
//}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Making sure ghost transform chain list is valid
|
||||
/// </summary>
|
||||
public void RefreshTransformsList()
|
||||
{
|
||||
if (_TransformsGhostChain == null) _TransformsGhostChain = new System.Collections.Generic.List<Transform>();
|
||||
else
|
||||
for (int i = _TransformsGhostChain.Count - 1; i >= 0; i--)
|
||||
if (_TransformsGhostChain[0] == null) _TransformsGhostChain.RemoveAt(i);
|
||||
}
|
||||
|
||||
/// <summary> Getting helper bone marker used for animating last bone in chain </summary>
|
||||
public TailSegment GetGhostChild() { return GhostChild; }
|
||||
|
||||
/// <summary> Helper flag for basic animate physics mode </summary>
|
||||
bool fixedUpdated = false;
|
||||
|
||||
// Supporting second solution for fixed animate physics mode
|
||||
private bool lateFixedIsRunning = false;
|
||||
private bool fixedAllow = true;
|
||||
private IEnumerator LateFixed()
|
||||
{
|
||||
WaitForFixedUpdate fixedWait = new WaitForFixedUpdate();
|
||||
lateFixedIsRunning = true;
|
||||
|
||||
while (true)
|
||||
{
|
||||
yield return fixedWait;
|
||||
PreCalibrateBones();
|
||||
fixedAllow = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4eccae1c8b93bb74ab7e39c82b68bd06
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,130 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FIMSpace.FTail
|
||||
{
|
||||
/// <summary>
|
||||
/// POST POSITION PROCESSING - Deflection
|
||||
/// </summary>
|
||||
public partial class TailAnimator2
|
||||
{
|
||||
[Tooltip("Making tail segment deflection influence back segments")]
|
||||
[Range(0f, 1f)]
|
||||
public float Deflection = 0.0f;
|
||||
[FPD_Suffix(1f, 89f, FPD_SuffixAttribute.SuffixMode.FromMinToMaxRounded, "°")]
|
||||
public float DeflectionStartAngle = 10f;
|
||||
[Range(0f, 1f)]
|
||||
public float DeflectionSmooth = 0f;
|
||||
[FPD_FixedCurveWindow(0, 0f, 1f, 1f, .65f, 0.4f, 1f, 0.9f)]
|
||||
public AnimationCurve DeflectionFalloff = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);
|
||||
[Tooltip("Deflection can be triggered every time tail is waving but you not always would want this feature be enabled (different behaviour of tail motion)")]
|
||||
public bool DeflectOnlyCollisions = true;
|
||||
|
||||
// Deflection feature variables
|
||||
private List<TailSegment> _defl_source;
|
||||
private float _defl_treshold = 0.01f;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Searching for deflection points on stored segments position
|
||||
/// before post processing with deflection to avoid jitter
|
||||
/// </summary>
|
||||
void Deflection_BeginUpdate()
|
||||
{
|
||||
// Defining constants for segments
|
||||
_defl_treshold = DeflectionStartAngle / 90f;
|
||||
float smoothTime = DeflectionSmooth / 9f;
|
||||
|
||||
//for (int i = TailBones.Count-1; i >=_tc_startII; --i)
|
||||
for (int i = _tc_startII; i < TailSegments.Count; i++)
|
||||
{
|
||||
TailSegment ppChild = _pp_reference[i];
|
||||
|
||||
// Checking deflection state to detect bend amount
|
||||
bool cleared = ppChild.CheckDeflectionState(_defl_treshold, smoothTime, rateDelta);
|
||||
|
||||
// Detecting if deflection occured and adding as deflection source point
|
||||
if (!cleared)
|
||||
{
|
||||
bool dependenciesMeet = true;
|
||||
|
||||
if (DeflectOnlyCollisions)
|
||||
if (ppChild.CollisionContactRelevancy <= 0f)
|
||||
dependenciesMeet = false; // No collision - no deflection
|
||||
|
||||
// Adding to deflection points list
|
||||
if (dependenciesMeet)
|
||||
{
|
||||
Deflection_AddDeflectionSource(ppChild);
|
||||
}
|
||||
else
|
||||
Deflection_RemoveDeflectionSource(ppChild);
|
||||
}
|
||||
else
|
||||
{
|
||||
Deflection_RemoveDeflectionSource(ppChild);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Checking conditions to remove deflection source point
|
||||
/// </summary>
|
||||
void Deflection_RemoveDeflectionSource(TailSegment child)
|
||||
{
|
||||
if (child.DeflectionRestoreState() == null)
|
||||
if (_defl_source.Contains(child)) _defl_source.Remove(child);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Checking conditions to add deflection source point and sorting list by index
|
||||
/// </summary>
|
||||
void Deflection_AddDeflectionSource(TailSegment child)
|
||||
{
|
||||
if (child.DeflectionRelevant())
|
||||
if (!_defl_source.Contains(child)) _defl_source.Add(child);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changing position of segment for deflection pose if deflection points are detected
|
||||
/// </summary>
|
||||
void Deflection_SegmentOffsetSimple(TailSegment child, ref Vector3 position)
|
||||
{
|
||||
if (child.Index == _tc_startI) return; // We not affecting first bone
|
||||
|
||||
// We using greatest deflection so we must remember last one used in loop
|
||||
float lastDeflectionPower = 0f;
|
||||
|
||||
// Defining influence of further children deflection on this segment
|
||||
// Going through all detected deflection points in this loop
|
||||
for (int i = 0; i < _defl_source.Count; i++)
|
||||
{
|
||||
// When there is one deflection and another one in next index then deflection is cancelling
|
||||
if (child.Index > _defl_source[i].Index) continue; // When segment is further on tail than deflection point then don't do anything here
|
||||
if (child.Index == _defl_source[i].Index) continue; // Not deflecting deflection source point
|
||||
|
||||
// If we already used deflection with greater power
|
||||
if (_defl_source[i].DeflectionFactor < lastDeflectionPower) continue;
|
||||
lastDeflectionPower = _defl_source[i].DeflectionFactor;
|
||||
|
||||
// Using curve over segments from zero or previous deflection source towards current one
|
||||
float preI = 0; if (i > 0) preI = _defl_source[i].Index; // Index for falloff curve
|
||||
float timeOnCurve = Mathf.InverseLerp(preI, _defl_source[i].Index, child.Index); // Falloff from previous deflection point to next one over curve
|
||||
|
||||
// Direction from procedural position towards deflective position
|
||||
Vector3 towardDeflection = _defl_source[i].DeflectionWorldPosition - child.ParentBone.ProceduralPosition;
|
||||
|
||||
// Calculating position of segment directed towards deflection compensation
|
||||
Vector3 deflectedSegmentPos = child.ParentBone.ProceduralPosition;
|
||||
deflectedSegmentPos += towardDeflection.normalized * child.BoneLengthScaled; // Scale support
|
||||
|
||||
// Applying certain amount of deflection on segment position
|
||||
child.ProceduralPosition = Vector3.LerpUnclamped(child.ProceduralPosition, deflectedSegmentPos, Deflection * DeflectionFalloff.Evaluate(timeOnCurve) * _defl_source[i].DeflectionSmooth);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f9279b9459c57b248a52fb0f3d63e82e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,103 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FIMSpace.FTail
|
||||
{
|
||||
/// <summary>
|
||||
/// FC: In this parital class you will find methods useful for custom
|
||||
/// coding and dynamic tail hierarchy changes etc.
|
||||
/// </summary>
|
||||
public partial class TailAnimator2
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Re-initialize tail with new transforms chain
|
||||
/// </summary>
|
||||
public void User_SetTailTransforms(List<Transform> list)
|
||||
{
|
||||
StartBone = list[0];
|
||||
EndBone = list[list.Count - 1];
|
||||
_TransformsGhostChain = list;
|
||||
|
||||
StartAfterTPose = false;
|
||||
initialized = false;
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Putting additional tail transform in chain list (added to the end of tail)
|
||||
/// </summary>
|
||||
public TailSegment User_AddTailTransform(Transform transform)
|
||||
{
|
||||
TailSegment newSeg = new TailSegment(transform);
|
||||
TailSegment last = TailSegments[TailSegments.Count - 1];
|
||||
newSeg.ParamsFromAll(last);
|
||||
|
||||
newSeg.RefreshFinalPos(newSeg.transform.position);
|
||||
newSeg.RefreshFinalRot(newSeg.transform.rotation);
|
||||
newSeg.ProceduralPosition = newSeg.transform.position;
|
||||
newSeg.PosRefRotation = newSeg.transform.rotation;
|
||||
|
||||
_TransformsGhostChain.Add(transform);
|
||||
TailSegments.Add(newSeg);
|
||||
last.SetChildRef(newSeg);
|
||||
newSeg.SetParentRef(last);
|
||||
newSeg.SetChildRef(GhostChild);
|
||||
GhostChild.SetParentRef(newSeg);
|
||||
|
||||
// Resetting indexes for curves
|
||||
for (int i = 0; i < TailSegments.Count; i++)
|
||||
TailSegments[i].SetIndex(i, TailSegments.Count);
|
||||
|
||||
return newSeg;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Dynamically removing tail segments from chain
|
||||
/// </summary>
|
||||
/// <param name="fromLastTo"> Segment with this index will be removed too but used as ghosting child </param>
|
||||
public void User_CutEndSegmentsTo(int fromLastTo)
|
||||
{
|
||||
if (fromLastTo < TailSegments.Count)
|
||||
{
|
||||
GhostChild = TailSegments[fromLastTo];
|
||||
GhostChild.SetChildRef(null);
|
||||
|
||||
for (int i = TailSegments.Count - 1; i >= fromLastTo; i--)
|
||||
{
|
||||
TailSegments.RemoveAt(i);
|
||||
_TransformsGhostChain.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log("[Tail Animator Cutting] Wrong index, you want cut from end to " + fromLastTo + " segment but there are only " + TailSegments.Count + " segments!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Syncing tail with current transforms positions and rotations
|
||||
/// </summary>
|
||||
public void User_ReposeTail()
|
||||
{
|
||||
GhostParent.Reset();
|
||||
for (int i = 0; i < TailSegments.Count; i++)
|
||||
TailSegments[i].Reset();
|
||||
GhostChild.Reset();
|
||||
}
|
||||
|
||||
|
||||
bool _forceDisable = false;
|
||||
float _forceDisableElapsed = 0f;
|
||||
/// <summary>
|
||||
/// Disable tail animator with fade transition as "Max Distance" fade
|
||||
/// </summary>
|
||||
public void User_ForceDisabled(bool disable)
|
||||
{
|
||||
_forceDisable = disable;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d6bf5d257ea4a6e47bbe76c86d216ec6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,149 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FIMSpace.FTail
|
||||
{
|
||||
public partial class TailAnimator2 : UnityEngine.EventSystems.IDropHandler, IFHierarchyIcon
|
||||
{
|
||||
|
||||
#region Hierarchy Icon
|
||||
|
||||
public string EditorIconPath { get { if (PlayerPrefs.GetInt("AnimsH", 1) == 0) return ""; else return "Tail Animator/Tail Animator Icon Small"; } }
|
||||
public void OnDrop(UnityEngine.EventSystems.PointerEventData data) { }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Enums
|
||||
|
||||
public enum EFDeltaType { DeltaTime, SmoothDeltaTime, UnscaledDeltaTime, FixedDeltaTime, SafeDelta }
|
||||
public enum EAnimationStyle { Quick, Accelerating, Linear }
|
||||
|
||||
#endregion
|
||||
|
||||
public enum ETailCategory { Setup, Tweak, Features, Shaping }
|
||||
public ETailCategory _Editor_Category = ETailCategory.Setup;
|
||||
public enum ETailFeaturesCategory { Main, Collisions, IK, Experimental }
|
||||
public ETailFeaturesCategory _Editor_FeaturesCategory = ETailFeaturesCategory.Main;
|
||||
|
||||
public bool DrawGizmos = true;
|
||||
|
||||
[Tooltip("First bone of tail motion chain")]
|
||||
public Transform StartBone;
|
||||
[Tooltip("Finish bone of tail motion chain")]
|
||||
public Transform EndBone;
|
||||
|
||||
[Tooltip("Adjusting end point for end tail bone motion")]
|
||||
public Vector3 EndBoneJointOffset = Vector3.zero;
|
||||
|
||||
public List<Transform> _TransformsGhostChain;
|
||||
public int _GhostChainInitCount = -1;
|
||||
|
||||
/// <summary> Initialization method controll flag </summary>
|
||||
protected bool initialized = false;
|
||||
public bool IsInitialized { get { return initialized; } }
|
||||
[Tooltip("Target FPS update rate for Tail Animator.\n\nIf you want Tail Animator to behave the same in low/high fps, set this value for example to 60.\nIt also can help optimizing if your game have more than 60 fps.")]
|
||||
public int UpdateRate = 0;
|
||||
|
||||
[Tooltip("If your character Unity's Animator have update mode set to 'Animate Physics' you should enable it here too")]
|
||||
public EFixedMode AnimatePhysics = EFixedMode.None;
|
||||
public enum EFixedMode { None, Basic, Late }
|
||||
|
||||
[Tooltip("When using target fps rate you can interpolate coordinates for smoother effect when object with tail is moving a lot")]
|
||||
public bool InterpolateRate = false;
|
||||
|
||||
[Tooltip("Simulating tail motion at initiation to prevent jiggle start")]
|
||||
public bool Prewarm = false;
|
||||
|
||||
/// <summary> For custom coding if you want to manipulate tail motion weight in additional way </summary>
|
||||
internal float OverrideWeight = 1f;
|
||||
/// <summary> Multiplier for tail motion weight computed from different conditions (max distance, override weight etc.) </summary>
|
||||
protected float conditionalWeight = 1f;
|
||||
|
||||
protected bool collisionInitialized = false;
|
||||
protected bool forceRefreshCollidersData = false;
|
||||
Vector3 previousWorldPosition;
|
||||
|
||||
/// <summary> Parent transform of first tail transform </summary>
|
||||
protected Transform rootTransform;
|
||||
|
||||
protected bool preAutoCorrect = false;
|
||||
|
||||
|
||||
|
||||
void OnValidate()
|
||||
{
|
||||
if (UpdateRate < 0) UpdateRate = 0;
|
||||
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
RefreshSegmentsColliders();
|
||||
//lastCurving = Curving; lastCurving.x += 0.001f;
|
||||
if (UseIK) IK_ApplyLimitBoneSettings();
|
||||
//if (UseWind) TailAnimatorWind.Refresh(this);
|
||||
}
|
||||
|
||||
if (UsePartialBlend) { ClampCurve(BlendCurve, 0f, 1f, 0f, 1f); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Getting list of transform for Tail Animator using Start and End Bone Transform guides
|
||||
/// </summary>
|
||||
public void GetGhostChain()
|
||||
{
|
||||
if (_TransformsGhostChain == null) _TransformsGhostChain = new System.Collections.Generic.List<Transform>();
|
||||
|
||||
if (EndBone == null)
|
||||
{
|
||||
// Just traight forward path through children
|
||||
_TransformsGhostChain.Clear();
|
||||
|
||||
Transform tChild = StartBone;
|
||||
if (tChild == null) tChild = transform;
|
||||
|
||||
_TransformsGhostChain.Add(tChild);
|
||||
|
||||
while (tChild.childCount > 0)
|
||||
{
|
||||
tChild = tChild.GetChild(0);
|
||||
if (!_TransformsGhostChain.Contains(tChild)) _TransformsGhostChain.Add(tChild);
|
||||
}
|
||||
|
||||
//if (!_TransformsGhostChain.Contains(tChild))
|
||||
_GhostChainInitCount = _TransformsGhostChain.Count;
|
||||
}
|
||||
else // Going through parents of 'End Bone' to 'Start Bone'
|
||||
{
|
||||
|
||||
System.Collections.Generic.List<Transform> newTrs = new System.Collections.Generic.List<Transform>();
|
||||
|
||||
Transform sBone = StartBone; if (sBone == null) sBone = transform;
|
||||
Transform tParent = EndBone;
|
||||
|
||||
newTrs.Add(tParent);
|
||||
|
||||
while (tParent != null && tParent != StartBone)
|
||||
{
|
||||
tParent = tParent.parent;
|
||||
if (!newTrs.Contains(tParent)) newTrs.Add(tParent);
|
||||
}
|
||||
|
||||
if (tParent == null) // No parent of startbone!
|
||||
{
|
||||
Debug.Log("[Tail Animator Editor] " + EndBone.name + " is not child of " + sBone.name + "!");
|
||||
Debug.LogError("[Tail Animator Editor] " + EndBone.name + " is not child of " + sBone.name + "!");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!newTrs.Contains(tParent)) newTrs.Add(tParent);
|
||||
|
||||
_TransformsGhostChain.Clear();
|
||||
_TransformsGhostChain = newTrs;
|
||||
|
||||
_TransformsGhostChain.Reverse();
|
||||
_GhostChainInitCount = _TransformsGhostChain.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a2dc5b1e05e72e44e91c60a332e6b401
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0396bd88bfc90b24f8713f695263a0d3
|
||||
folderAsset: yes
|
||||
timeCreated: 1600118724
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e70277fbd3e17b54e91983280ca90b9a
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c8a319bfdaa465646b09cab5796d7fe7
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0a8cc58bf52c86a47b69e3e0d6a7029a
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7c44e8a3d238b4d4f8f36d7af88d25f6
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d5b3577c5e8a41c4ab0dd517d5d9737d
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||