添加插件

This commit is contained in:
2025-11-10 00:08:26 +08:00
parent 4059c207c0
commit 76f80db694
2814 changed files with 436400 additions and 178 deletions

View File

@@ -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

View File

@@ -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)

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 511704c08bd35394ea37e60b93d63513
folderAsset: yes
timeCreated: 1603290412
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 8504e6f0ad3ec1040b6c91b589b00907
folderAsset: yes
timeCreated: 1532351210
licenseType: Store
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 7df895321e8326c49996143255a443cd
folderAsset: yes
timeCreated: 1553950449
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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:

View File

@@ -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:

View File

@@ -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:

View File

@@ -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:

View File

@@ -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:

View File

@@ -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:

View File

@@ -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:

View File

@@ -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:

View File

@@ -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:

View File

@@ -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:

View File

@@ -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:

View File

@@ -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 &amp; 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>

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: a7eb67ced331ec24b845911cd4ae82d1
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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:

Binary file not shown.

After

Width:  |  Height:  |  Size: 790 B

View File

@@ -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:

View File

@@ -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;
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: bcf1a74f343e94f4d83b39f22572bd73
timeCreated: 1532131583
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 25475a529738d084d8d042e096cb2fe1
timeCreated: 1532131583
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 0e79d23b98435d54d93ae9b83395b629
timeCreated: 1532131583
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 9b613e7438d9e79458f122cd8fa5236b
timeCreated: 1532131583
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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(); }
}
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a05f6e8e06329674a85c95a70ca37780
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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(); }
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 34cebb73f9f145b4b90276859fe48429
timeCreated: 1532131583
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 4353b07ef84cbd14faeef2a48497adf6
timeCreated: 1532131583
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 96a57e14ee3d2d546828fba97946e597
timeCreated: 1532131583
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 202e9deb41375844daf2c8a489b596d5
folderAsset: yes
timeCreated: 1532283218
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6e3d55ec0583b8f458db21ee51c4ead3
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4c0f1ecbfe3d7aa458e3e48da5898b29
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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);
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d17f10109a8683944b551359096896ac
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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; } }
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 18157dba56a9a3f42a851b679615af5d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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());
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: adf0396b6095c7c4f93a78f8ee022984
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9655b675af6b2334ea694f30ff189f44
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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; }
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9d872664813634c49b522c82ee361f4c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fcfde61a5f0bcac4fac26bf2152d6a2e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dfa827566ed68c5469e8b78e674d1d89
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 516e3bfcbbd526a419d62b47bb170926
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e3b722fb0fe3ed44685a7cfc9ad05ac8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bfe18301d3b8b4e49b7767eb91d25c7e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d1f8936842303b74dbace3df066c79d2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 94df3f76d7ce99142bd705f911882f19
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 90e74887a690e1c44b4c416583a50f76
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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
{
}
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6fd7b67b43fe5784cb55474315c6c30e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4eccae1c8b93bb74ab7e39c82b68bd06
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f9279b9459c57b248a52fb0f3d63e82e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d6bf5d257ea4a6e47bbe76c86d216ec6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a2dc5b1e05e72e44e91c60a332e6b401
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 0396bd88bfc90b24f8713f695263a0d3
folderAsset: yes
timeCreated: 1600118724
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: e70277fbd3e17b54e91983280ca90b9a
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: c8a319bfdaa465646b09cab5796d7fe7
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 0a8cc58bf52c86a47b69e3e0d6a7029a
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 7c44e8a3d238b4d4f8f36d7af88d25f6
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: d5b3577c5e8a41c4ab0dd517d5d9737d
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Some files were not shown because too many files have changed in this diff Show More