я в скриптописании нубоват, но со структурой знаю как работать (получил базовый курс предподготовки по программированию в школе)
есть еще такой скрипт (взял с вики)
- Код: Выделить всё
import UnityEngine
# AniMate animation helper class for Unity3D
# Version 1.6 - 28. June 2009
# Copyright (C) 2009 Adrian Stutz
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, see <http://www.gnu.org/licenses/>.
import System.Reflection
import System.Reflection.Emit
import System.Collections
# ---------------------------------------- #
# ANIMATION HELPER CLASS
enum AniType:
To
From
By
class Ani (MonoBehaviour):
# ---------------------------------------- #
# CONFIGURATION PROPERTIES
# Default delay
public defaultDelay as single = 0
# Default physics behaviour
public defaultPhysics as bool = false
# Default callback
public defaultCallback as callable = null
# Default easing
public defaultEasing as System.Type = LinearEasing
# Default easing direction
public defaultDirection as EasingType = EasingType.In
# Default animation drive
public defaultDrive as System.Type = RegularDrive
# Default frames per second (-1 for fullspeed)
public defaultFps as single = -1
# Remove existing animations for property
public defaultReplace as bool = false
# ---------------------------------------- #
# INTERNAL FIELDS
# List with
# 0: AniValue object
# 1: AniMator object
# 2: callback
# 3: fps
# 4: time since last frame (for fps)
animations as List = []
fixedAnimations as List = []
# ---------------------------------------- #
# SINGLETON
# Singleton instance
static Mate as Ani:
get:
# Create instance if none exists yet
if _mate == null:
# Create GameObject to attach to
go = GameObject("AniMate")
# Attach Ani to GameObject
_mate = go.AddComponent(Ani)
return _mate
static _mate as Ani
# Save instance
def Awake():
if Ani._mate:
raise System.Exception("Ani.Mate.ERROR: Multiple AniMate instances on "+Ani._mate.gameObject.name+" and "+gameObject.name)
Ani._mate = self
# ---------------------------------------- #
# CREATE NEW ANIMATION
def To (obj as System.Object, duration as single, properties as Hash):
properties = properties.Clone()
# Fill options with defaults
options = ExtractOptions(properties)
# Add to animations
CreateAnimations(obj, properties, duration, options, AniType.To)
# Return yield to chain animations
return WaitForSeconds(duration)
def To (obj as System.Object, duration as single, properties as Hashtable):
To (obj, duration, Hash(properties))
def To (obj as System.Object, duration as single, properties as Hash, options as Hash):
properties = properties.Clone()
options = options.Clone()
# Fill options with defaults
options = ExtractOptions(options)
# Add to animations
CreateAnimations(obj, properties, duration, options, AniType.To)
# Return yield to chain animations
return WaitForSeconds(duration)
def To (obj as System.Object, duration as single, properties as Hashtable, options as Hashtable):
To (obj, duration, Hash(properties), Hash(options))
def From (obj as System.Object, duration as single, properties as Hash):
properties = properties.Clone()
# Fill options with defaults
options = ExtractOptions(properties)
# Add to animations
CreateAnimations(obj, properties, duration, options, AniType.From)
# Return yield to chain animations
return WaitForSeconds(duration)
def From (obj as System.Object, duration as single, properties as Hashtable):
From (obj, duration, Hash(properties))
def From (obj as System.Object, duration as single, properties as Hash, options as Hash):
properties = properties.Clone()
options = options.Clone()
# Fill options with defaults
options = ExtractOptions(options)
# Add to animations
CreateAnimations(obj, properties, duration, options, AniType.From)
# Return yield to chain animations
return WaitForSeconds(duration)
def From (obj as System.Object, duration as single, properties as Hashtable, options as Hashtable):
From (obj, duration, Hash(properties), Hash(options))
def By (obj as System.Object, duration as single, properties as Hash):
properties = properties.Clone()
# Fill options with defaults
options = ExtractOptions(properties)
# Add to animations
CreateAnimations(obj, properties, duration, options, AniType.By)
# Return yield to chain animations
return WaitForSeconds(duration)
def By (obj as System.Object, duration as single, properties as Hashtable):
By (obj, duration, Hash(properties))
def By (obj as System.Object, duration as single, properties as Hash, options as Hash):
properties = properties.Clone()
options = options.Clone()
# Fill options with defaults
options = ExtractOptions(options)
# Add to animations
CreateAnimations(obj, properties, duration, options, AniType.By)
# Return yield to chain animations
return WaitForSeconds(duration)
def By (obj as System.Object, duration as single, properties as Hashtable, options as Hashtable):
By (obj, duration, Hash(properties), Hash(options))
# ---------------------------------------- #
# MANAGE ANIMATIONS
# Number of all aniamtions
def Count():
return (animations.Count + fixedAnimations.Count)
# Check if an animation exists for object
def Has(obj as System.Object):
return (Contains(obj,null,animations) or Contains(obj,null,fixedAnimations))
# Check if animation exists for object and proeperty
def Has(obj as System.Object, pName as string):
return (Contains(obj,pName,animations) or Contains(obj,pName,fixedAnimations))
# Check for object and property
private def Contains(obj as System.Object, pName as string, ref anims as List):
for anim as List in anims:
val = anim[0] as AniValue
if ((pName == null and val.Is(obj))
or
(pName != null and val.Is(obj,pName))):
return true
return false
# Stop all animations of an object
def StopAll(obj as System.Object):
# Regular Animations
Remove(obj, null, animations)
# Fixed Animations
Remove(obj, null, fixedAnimations)
# Stop all animations of an object for a property
def Stop(obj as System.Object, pName as string):
# Regular Animations
Remove(obj, pName, animations)
# Fixed Animations
Remove(obj, pName, fixedAnimations)
# Remove animations
private def Remove(obj as System.Object, pName as string, ref anims as List):
remove = []
for anim as List in anims:
val = anim[0] as AniValue
if ((pName == null and val.Is(obj))
or
(pName != null and val.Is(obj,pName))):
remove.Add(anim)
for anim in remove:
animations.Remove(anim)
# ---------------------------------------- #
# MAIN ANIMATION LOOPS
private def DoAnimation(ref anims as List):
finished = []
# Loop through animations
for anim as List in anims:
val = anim[0] as AniValue
mat = anim[1] as AniMator
callback = anim[2] as callable
spf = cast(single,anim[3])
# Check if animation has started
if not mat.Running():
continue
# Honor seconds per frame
if spf > 0:
timesince = cast(single,anim[4])
timesince += Time.deltaTime
# Not yet time, skip
if timesince < spf:
anim[4] = timesince
continue
# Update this frame
else:
anim[4] = timesince % spf
# Animate or call calback with value
try:
if (callback == null):
val.Set(mat.GetValue())
else:
callback(mat.GetValue())
except e as System.Exception:
finished.Add(anim)
continue
# Check if finished
if mat.Finished():
finished.Add(anim)
# Remove finished animations
for fin in finished:
anims.Remove(fin)
# Regular animations
def Update():
DoAnimation(animations)
# Physics animations
def FixedUpdate():
DoAnimation(fixedAnimations)
# ---------------------------------------- #
# INTERNAL METHODS
# Exctract options for Hash and fill defaults where needed
private def ExtractOptions(ref options as Hash):
exct = {}
# Delay
if (options["delay"] == null):
exct["delay"] = defaultDelay
else:
exct["delay"] = cast(single,options["delay"])
options.Remove("delay")
# Physics
if (options["physics"] == null):
exct["physics"] = defaultPhysics
else:
exct["physics"] = cast(bool,options["physics"])
options.Remove("physics")
# Callback
if (options["callback"] == null):
exct["callback"] = defaultCallback
else:
exct["callback"] = cast(callable,options["callback"])
options.Remove("callback")
# Easing
if (options["easing"] == null):
exct["easing"] = defaultEasing
else:
exct["easing"] = cast(System.Type,options["easing"])
options.Remove("easing")
# Easing Direction
if (options["direction"] == null):
exct["direction"] = defaultDirection
else:
exct["direction"] = cast(EasingType,options["direction"])
options.Remove("direction")
# Animation drive
if (options["drive"] == null):
exct["drive"] = defaultDrive
else:
exct["drive"] = cast(System.Type,options["drive"])
options.Remove("drive")
# Rigidbody animation
if (options["rigidbody"] == null):
exct["rigidbody"] = null
else:
exct["rigidbody"] = cast(Rigidbody,options["rigidbody"])
options.Remove("rigidbody")
# Color animation
if (options["colorName"] == null):
exct["colorName"] = null
else:
exct["colorName"] = cast(string,options["colorName"])
options.Remove("colorName")
# Fps (saved as seconds per frame)
if (options["fps"] == null):
exct["fps"] = 1 / defaultFps
else:
exct["fps"] = 1 / cast(single,options["fps"])
options.Remove("fps")
# Replace animation on property
if (options["replace"] == null):
exct["replace"] = defaultReplace
else:
exct["replace"] = cast(bool,options["replace"])
options.Remove("replace")
# Return hash with all values
return exct
# Extract animation properties from Hash
private def CreateAnimations(obj as System.Object, properties as Hash, duration as single, options as Hash, type as AniType):
for item in properties:
# Extract name and value
pName = cast(string,item.Key)
value as duck = item.Value
# Callback
callback as callable = options["callback"]
# Animation type
isFixedAnimation as bool = false
# Create value object
if options["colorName"]:
# Special handling for material color animation: pass color instead of material
aniv = AniValue((obj as Material).GetColor(options["colorName"]),pName)
else:
aniv = AniValue(obj,pName)
# Get current value
current = aniv.Get()
# Setup variables
if (type == AniType.To):
start = current
target = value
elif (type == AniType.From):
start = value
target = current
elif (type == AniType.By):
start = current
diff = value
# Calculate difference for To and From
if ((type == AniType.To or type == AniType.From) and DriveNeedsDiff(options["drive"])):
try:
diff = target - start
if (start + 0.1 * diff) == self:
pass
except e as System.Exception:
raise System.Exception("Ani.Mate.ERROR: Cannot animate "+aniv.ValueType()+
" with target "+value.GetType()+": Operation +, - or * not supported. ("+e+")")
# Create animation object
mat = AniMator(start, target, diff, duration,
options["delay"], options["easing"], options["direction"], options["drive"])
# Remove existing animations
if (options["replace"]):
Stop(obj,pName)
# Material color animtion
if (options["colorName"]):
if not obj isa Material:
raise System.Exception("Ani.Mate.ERROR: colorName can only be set on material objects.")
if not pName in ["r","g","b","a"]:
raise System.Exception("Ani.Mate.ERROR: colorName can only be used with r, g, b and a.")
callback = CreateMaterialColorCallback(obj,pName,options)
# Physics / Rigidbody animtion
if (options["physics"] == true or options["rigidbody"] != null):
# Animation will run in FixedUpdate
isFixedAnimation = true
# Rigidbody animation
if options["rigidbody"] != null and pName == "position":
callback = (options["rigidbody"] as Rigidbody).MovePosition
elif options["rigidbody"] != null and pName == "rotation":
callback = (options["rigidbody"] as Rigidbody).MoveRotation
# Print warning if callback was overwritten
if (options["callback"] != null and options["callback"] != callback):
Debug.Log("Ani.Mate.WARNING: callback option overwritten by rigidbody option.")
# Add animation to main list
if not isFixedAnimation:
# Regular animation
animations.Add([aniv,mat,callback,options["fps"], 0])
else:
# Physics animation
fixedAnimations.Add([aniv,mat,callback,options["fps"], 0])
# From: Set to starting value
if (type == AniType.From):
aniv.Set(mat.GetValue())
private def DriveNeedsDiff(drive as System.Type):
d as AnimationDrive = drive()
return d.CalculateDiff()
private def CreateMaterialColorCallback(obj as Material, pName as string, options as Hash):
return def (newValue as single):
material = (obj as Material)
newColor = material.GetColor(options["colorName"])
if pName == "r":
newColor.r = newValue
elif pName == "g":
newColor.g = newValue
elif pName == "b":
newColor.b = newValue
else:
newColor.a = newValue
material.SetColor(options["colorName"],newColor)
# ---------------------------------------- #
# WRAPPER FOR A SINGLE VALUE
class AniValue:
# ---------------------------------------- #
# CONFIGURATION
static bFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static
callable SetHandler(source as object, value as object) as void
# ---------------------------------------- #
# PRIVATE FIELDS
# Object a field or property is animated on
obj as System.Object
# Name of the field or property
name as string
# Type object
objType as System.Type
# FieldInfo object
fieldInfo as FieldInfo
# PropertyInfo object
propertyInfo as PropertyInfo
setter as SetHandler
# ---------------------------------------- #
# CONSTRUCTOR
def constructor(o as System.Object, n as string):
# Save
obj = o
name = n
# Get info objects
objType = obj.GetType()
# Get field or property info
fieldInfo = objType.GetField(n, AniValue.bFlags)
propertyInfo = objType.GetProperty(n, AniValue.bFlags)
# Check info objects
if (fieldInfo == null and propertyInfo == null):
raise System.MissingMethodException("Ani.Mate.ERROR: Property or field '"+n+"' not found on "+obj)
# Create dynamic method
if fieldInfo:
setter = FieldSetMethod(objType, fieldInfo)
else:
setter = PropertySetMethod(objType, propertyInfo)
# ---------------------------------------- #
# UTILITY METHODS
# Get type of field/property for debug purposes
def ValueType():
if (propertyInfo != null):
return propertyInfo.PropertyType
else:
return fieldInfo.FieldType
# Check if AniValue is from given object
def Is(checkObj as System.Object):
return (obj == checkObj)
# Check if AniValue is from given object and value
def Is(checkObject as System.Object, checkName as string):
return (Is(checkObject) and checkName == name)
# Create a dynamic set method for a PropertyInfo
def PropertySetMethod(type as System.Type, pInfo as PropertyInfo):
setMethodInfo = pInfo.GetSetMethod(true)
dynamicSet = DynamicMethod("SetHandler", void, (object, object), type, true)
setGenerator = dynamicSet.GetILGenerator()
setGenerator.Emit(OpCodes.Ldarg_0)
setGenerator.Emit(OpCodes.Ldarg_1)
if (setMethodInfo.GetParameters()[0].ParameterType.IsValueType):
setGenerator.Emit(OpCodes.Unbox_Any, setMethodInfo.GetParameters()[0].ParameterType)
setGenerator.Emit(OpCodes.Call, setMethodInfo)
setGenerator.Emit(OpCodes.Ret)
return dynamicSet.CreateDelegate(SetHandler) as SetHandler
# Create a dynamic set method for a FieldInfo
def FieldSetMethod(type as System.Type, fInfo as FieldInfo):
dynamicSet = DynamicMethod("SetHandler", void, (object, object), type, true)
setGenerator = dynamicSet.GetILGenerator()
setGenerator.Emit(OpCodes.Ldarg_0)
setGenerator.Emit(OpCodes.Ldarg_1)
if (fInfo.FieldType.IsValueType):
setGenerator.Emit(OpCodes.Unbox_Any, fInfo.FieldType)
setGenerator.Emit(OpCodes.Stfld, fInfo)
setGenerator.Emit(OpCodes.Ret)
return dynamicSet.CreateDelegate(SetHandler) as SetHandler
# ---------------------------------------- #
# GET AND SET VALUE
# Get field or property
def Get():
if (propertyInfo != null):
return propertyInfo.GetValue(obj, null)
else:
return fieldInfo.GetValue(obj)
# Set field or property
def Set(value):
if setter:
setter(obj, value)
elif (propertyInfo != null):
propertyInfo.SetValue(obj, value, null)
else:
fieldInfo.SetValue(obj, value)
# ---------------------------------------- #
# ANIMATOR CLASS
class AniMator:
# Initial value
startValue as duck
# End value
endValue as duck
# Change over duration
change as duck
# Time of animation start
startTime as single
# Length of animation
duration as single
# Easing class
easing as AnimationEasing
# Easing type
easingType as EasingType
# Animation drive
drive as AnimationDrive
# Fallback with dynamic typing
def constructor(sta as duck, end as duck, chg as duck, dur as single, delay as single, eas as System.Type, typ as EasingType, d as System.Type):
startValue = sta
endValue = end
change = chg
Setup(dur, delay, eas, typ, d)
# Create Animator
private def Setup(dur as single, delay as single, eas as System.Type, typ as EasingType, d as System.Type):
startTime = Time.time + delay
duration = dur
easing = eas()
easingType = typ
drive = d()
# Get easing with correct type
def GetEasing(time as single):
if easingType == EasingType.In:
return easing.In(time)
elif easingType == EasingType.Out:
return easing.Out(time)
elif easingType == EasingType.InOut:
return easing.InOut(time)
# Get current animation position (from 0 to 1)
def GetPosition():
return Mathf.Clamp01((Time.time - startTime) / duration)
# Check if animation is running
def Running():
return startTime < Time.time
# Check if aniamtion is finished
def Finished():
return (startTime + duration) < Time.time
# Get current animation value
def GetValue():
# Get eased position
easPos = GetEasing(GetPosition())
# Use drive to calculate value
return drive.Animate(startValue, endValue, change, easPos * duration, duration)
# ---------------------------------------- #
# INTERFACE FOR ANIMATION DRIVES
interface AnimationDrive:
def Animate(start as duck, end as duck, diff as duck, time as single, duration as single) as duck
def CalculateDiff () as bool
# ---------------------------------------- #
# REGULAR DRIVE
class RegularDrive (AnimationDrive):
def Animate(start as duck, end as duck, diff as duck, time as single, duration as single) as duck:
# Positon
easPos = time / duration
# Cast to known types for performance
startType = start.GetType()
# --- Builtin types
# Not matching start and change
if (startType != diff.GetType()):
return start + easPos * diff
# short
elif (startType == short):
return cast(short,start) + easPos * cast(short,diff)
# integer
elif (startType == int):
return cast(int,start) + easPos * cast(int,diff)
# long
elif (startType == long):
return cast(long,start) + easPos * cast(long,diff)
# single
elif (startType == single):
return cast(single,start) + easPos * cast(single,diff)
# double
elif (startType == double):
return cast(double,start) + easPos * cast(double,diff)
# decimal
elif (startType == decimal):
return cast(decimal,start) + easPos * cast(decimal,diff)
# --- Unity types
# Vector2
elif (startType == Vector2):
return cast(Vector2,start) + easPos * cast(Vector2,diff)
# Vector3
elif (startType == Vector3):
return cast(Vector3,start) + easPos * cast(Vector3,diff)
# Vector3
elif (startType == Vector4):
return cast(Vector4,start) + easPos * cast(Vector4,diff)
# Color
elif (startType == Color):
return cast(Color,start) + easPos * cast(Color,diff)
# Dynamic typed fallback
else:
return start + easPos * diff
def CalculateDiff() as bool:
return true
# ---------------------------------------- #
# SLERP DRIVE
class SlerpDrive (AnimationDrive):
def Animate(start as duck, end as duck, diff as duck, time as single, duration as single) as duck:
return Quaternion.Slerp(start, end, (time / duration))
def CalculateDiff() as bool:
return false
# ---------------------------------------- #
# LERP DRIVE
class LerpDrive (AnimationDrive):
def Animate(start as duck, end as duck, diff as duck, time as single, duration as single) as duck:
return Vector3.Lerp(start, end, (time / duration))
def CalculateDiff() as bool:
return false
# ---------------------------------------- #
# INTERFACE FOR EASING FUNCTIONS
enum EasingType:
In
Out
InOut
interface AnimationEasing:
def In (time as single) as single
def Out (time as single) as single
def InOut (time as single) as single
class EasingHelper:
static def InOut(eas as AnimationEasing, time as single) as single:
if time <= .5:
return eas.In(time * 2) / 2
else:
return (eas.Out((time - .5) * 2) / 2) + .5
# ---------------------------------------- #
# LINEAR EASING
class LinearEasing (AnimationEasing):
def In (time as single) as single:
return time
def Out (time as single) as single:
return time
def InOut (time as single):
return time
# ---------------------------------------- #
# QUADRATIC EASING
class QuadraticEasing (AnimationEasing):
def In (time as single) as single:
return (time * time)
def Out (time as single) as single:
return (time * (time - 2) * -1)
def InOut (time as single) as single:
return EasingHelper.InOut(self, time)
# ---------------------------------------- #
# CUBIC EASING
class CubicEasing (AnimationEasing):
def In (time as single) as single:
return (time * time * time)
def Out (time as single) as single:
return (Mathf.Pow(time-1,3) + 1)
def InOut (time as single) as single:
return EasingHelper.InOut(self, time)
# ---------------------------------------- #
# QUARTIC EASING
class QuarticEasing (AnimationEasing):
def In (time as single) as single:
return Mathf.Pow(time,4)
def Out (time as single) as single:
return (Mathf.Pow(time-1,4) - 1) * -1
def InOut (time as single) as single:
return EasingHelper.InOut(self, time)
# ---------------------------------------- #
# QUINTIC EASING
class QuinticEasing (AnimationEasing):
def In (time as single) as single:
return Mathf.Pow(time,5)
def Out (time as single) as single:
return (Mathf.Pow(time-1,5) + 1)
def InOut (time as single) as single:
return EasingHelper.InOut(self, time)
# ---------------------------------------- #
# SINUSOIDAL EASING
class SinusoidalEasing (AnimationEasing):
def In (time as single) as single:
return Mathf.Sin((time-1)*(Mathf.PI/2)) + 1
def Out (time as single) as single:
return Mathf.Sin(time*(Mathf.PI/2))
def InOut (time as single) as single:
return EasingHelper.InOut(self, time)
# ---------------------------------------- #
# EXPONENTIAL EASING
class ExponentialEasing (AnimationEasing):
def In (time as single) as single:
return Mathf.Pow(2,10*(time-1))
def Out (time as single) as single:
return (-1 * Mathf.Pow(2,-10*time) + 1)
def InOut (time as single) as single:
return EasingHelper.InOut(self, time)
# ---------------------------------------- #
# CIRCULAR EASING
class CircularEasing (AnimationEasing):
def In (time as single) as single:
return (-1 * Mathf.Sqrt(1 - time*time) + 1)
def Out (time as single) as single:
return Mathf.Sqrt(1 - Mathf.Pow(time-1,2))
def InOut (time as single) as single:
return EasingHelper.InOut(self, time)
# ---------------------------------------- #
# BACK EASING
class BackEasing (AnimationEasing):
s as single = 1.70158
s2 as single = 1.70158 * 1.525
def In (time as single) as single:
return time*time*((s+1)*time - s)
def Out (time as single) as single:
time = time - 1
return (time*time*((s+1)*time + s) + 1)
def InOut (time as single) as single:
time = time*2
if (time < 1):
return 0.5*(time*time*((s2+1)*time - s2))
else:
time -= 2
return 0.5*((time)*time*((s2+1)*time + s2) + 2)
# ---------------------------------------- #
# BOUNCE EASING
class BounceEasing (AnimationEasing):
def In (time as single) as single:
return 1 - Out(1-time)
def Out (time as single) as single:
if (time < (1/2.75)):
return (7.5625*time*time)
elif (time < (2/2.75)):
time -= (1.5/2.75)
return (7.5625*time*time + .75)
elif (time < (2.5/2.75)):
time -= (2.25/2.75)
return (7.5625*time*time + .9375)
else:
time -= (2.625/2.75)
return (7.5625*time*time + .984375)
def InOut (time as single) as single:
return EasingHelper.InOut(self,time)
# ---------------------------------------- #
# ELASTIC EASING
class ElasticEasing (AnimationEasing):
p as single = 0.3
a as single = 1
private def Calc(time as single, dir as EasingType) as single:
s as single
return time if time == 0 or time == 1
if (a < 1):
s = p/4
else:
s = p/(2*Mathf.PI) * Mathf.Asin(1/a)
if (dir == EasingType.In):
time -= 1
return -(a*Mathf.Pow(2,10*time)) * Mathf.Sin((time-s)*(2*Mathf.PI)/p)
else:
return a*Mathf.Pow(2,-10*time) * Mathf.Sin((time-s)*(2*Mathf.PI)/p) + 1
def In (time as single) as single:
return Calc(time,EasingType.In)
def Out (time as single) as single:
return Calc(time,EasingType.Out)
def InOut (time as single) as single:
return EasingHelper.InOut(self,time)
но как с ним работать я не знаю