Files

812 lines
27 KiB
C#
Raw Permalink Normal View History

using UnityEngine;
using System.Collections;
using System;
public class upperBodyRotationSystem : MonoBehaviour
{
[Header ("Main Settings")]
[Space]
public bool shakeUpperBodyEnabled = true;
[Space]
[Header ("Head Settings")]
[Space]
public Vector3 headLookVector = Vector3.forward;
public Vector3 headUpVector = Vector3.up;
[Space]
[Header ("Rotation Settings")]
[Space]
public float horizontalThresholdAngleDifference = 5;
public float verticalThresholdAngleDifference = 5;
public float horizontalBendingMultiplier = 1;
public float verticalBendingMultiplier = 1;
public float horizontalMaxAngleDifference = 90;
public float verticalMaxAngleDifference = 90;
public float maxBendingAngle = 90;
public float horizontalResponsiveness = 10;
public float verticalResponsiveness = 10;
public float upperBodyRotationSpeed = 5;
public float rotationSpeed = 5;
[Space]
[Space]
public bool chestRotationEnabled = true;
public bool spineRotationEnabled = true;
public bool extraHorizontalRotationEnabled = true;
public bool horizontalRotationEnabled = true;
public bool verticalRotationEnabled = true;
[Space]
public bool useSmoothRotationPointValue;
public float smoothRotationPointValue = 0.1f;
[Space]
[Header ("Chest Orientation Settings")]
[Space]
public Vector3 chestUpVector = new Vector3 (0, 0, 1);
[Space]
[Header ("Spine And Chest Transforms")]
[Space]
public Transform spineTransform;
public Transform chestTransform;
[Space]
[Header ("Other Settings")]
[Space]
public bool followFullRotationPointDirection;
public Vector3 followFullRotationPointMultipliers = Vector3.one;
public bool useFollowFullRotationClamp;
public Vector2 followFullRotationClampX;
public Vector2 followFullRotationClampY;
public Vector2 followFullRotationClampZ;
[Space]
[Header ("Debug")]
[Space]
public bool IKUpperBodyActive;
public float currentExtraRotation;
public bool usingWeaponRotationPoint;
public bool usingTemporalObjectToFollow;
public Transform temporalObjectToFollow;
public Transform currentWeaponRotationPoint;
public bool fullBodyAwarenessActive;
[Space]
[Header ("Components")]
[Space]
public Transform objectToFollow;
public Transform weaponRotationPointToFollow;
public playerController playerControllerManager;
bool usingDualWeapon;
float currentRotation;
float rotationXValue;
weaponRotationPointInfo rotationPointInfo;
int currentRotationDirection = 1;
Quaternion chestRotation;
Quaternion spineRotation;
float angleH;
float angleV;
Vector3 dirUp;
Vector3 referenceLookDir;
Vector3 referenceUpDir;
float originalAngleDifference;
Coroutine changeExtraRotation;
Vector3 extraRotation;
float auxCurrentExtraRotation;
Coroutine shakeUpperBodyRotationCoroutine;
Quaternion parentRot;
Quaternion parentRotInv;
Vector3 lookDirWorld;
Vector3 lookDirGoal;
Vector3 rightOfTarget;
Vector3 lookDirGoalinHPlane;
float hAngle;
float vAngle;
float hAngleThr;
float vAngleThr;
float hAngleABS;
float vAngleABS;
float hAngleSign;
float vAngleSign;
Vector3 referenceRightDir;
Vector3 upDirGoal;
Vector3 lookDir;
Quaternion lookRot;
Quaternion dividedRotation;
Quaternion finalLookRotation;
bool isPlayerDead;
Transform currentRightWeaponRotationPoint;
Transform currentLeftWeaponRotationPoint;
weaponRotationPointInfo rightRotationPointInfo;
weaponRotationPointInfo leftRotationPointInfo;
int currentRightRotationDirection = 1;
int currentLeftRotationDirection = 1;
bool weaponRotationPointToFollowLocated;
float originalHorizontalBendingMultiplier;
float originalVerticalBendingMultiplier;
float originalHorizontalMaxAngleDifference;
float originalVerticalMaxAngleDifference;
float currentTime;
float currentDeltatime;
void Start ()
{
parentRot = spineTransform.parent.rotation;
parentRotInv = Quaternion.Inverse (parentRot);
referenceLookDir = parentRotInv * transform.rotation * headLookVector.normalized;
referenceUpDir = parentRotInv * transform.rotation * headUpVector.normalized;
dirUp = referenceUpDir;
originalAngleDifference = maxBendingAngle;
weaponRotationPointToFollowLocated = weaponRotationPointToFollow != null;
originalHorizontalBendingMultiplier = horizontalBendingMultiplier;
originalVerticalBendingMultiplier = verticalBendingMultiplier;
originalHorizontalMaxAngleDifference = horizontalMaxAngleDifference;
originalVerticalMaxAngleDifference = verticalMaxAngleDifference;
}
void FixedUpdate ()
{
if (IKUpperBodyActive) {
isPlayerDead = playerControllerManager.isPlayerDead ();
if (isPlayerDead) {
return;
}
currentTime = Time.smoothDeltaTime;
parentRot = spineTransform.parent.rotation;
parentRotInv = Quaternion.Inverse (parentRot);
// Desired look direction in world space
if (usingTemporalObjectToFollow) {
lookDirWorld = (temporalObjectToFollow.position - chestTransform.position).normalized;
} else {
lookDirWorld = (objectToFollow.position - chestTransform.position).normalized;
}
// Desired look directions in neck parent space
lookDirGoal = (parentRotInv * lookDirWorld);
// Get the horizontal and vertical rotation angle to look at the target
hAngle = AngleAroundAxis (referenceLookDir, lookDirGoal, referenceUpDir);
rightOfTarget = Vector3.Cross (referenceUpDir, lookDirGoal);
lookDirGoalinHPlane = lookDirGoal - Vector3.Project (lookDirGoal, referenceUpDir);
vAngle = AngleAroundAxis (lookDirGoalinHPlane, lookDirGoal, rightOfTarget);
hAngleABS = Mathf.Abs (hAngle);
vAngleABS = Mathf.Abs (vAngle);
hAngleSign = Mathf.Sign (hAngle);
vAngleSign = Mathf.Sign (vAngle);
// Handle threshold angle difference, bending multiplier, and max angle difference here
hAngleThr = Mathf.Max (0, hAngleABS - horizontalThresholdAngleDifference) * hAngleSign;
vAngleThr = Mathf.Max (0, vAngleABS - verticalThresholdAngleDifference) * vAngleSign;
hAngle = Mathf.Max (Mathf.Abs (hAngleThr) * Mathf.Abs (horizontalBendingMultiplier), hAngleABS
- horizontalMaxAngleDifference) * hAngleSign * Mathf.Sign (horizontalBendingMultiplier);
vAngle = Mathf.Max (Mathf.Abs (vAngleThr) * Mathf.Abs (verticalBendingMultiplier), vAngleABS
- verticalMaxAngleDifference) * vAngleSign * Mathf.Sign (verticalBendingMultiplier);
// Handle max bending angle here
hAngle = Mathf.Clamp (hAngle, -maxBendingAngle, maxBendingAngle);
vAngle = Mathf.Clamp (vAngle, -maxBendingAngle, maxBendingAngle);
referenceRightDir = Vector3.Cross (referenceUpDir, referenceLookDir);
// Lerp angles
angleH = Mathf.Lerp (angleH, hAngle, currentTime * horizontalResponsiveness);
angleV = Mathf.Lerp (angleV, vAngle, currentTime * verticalResponsiveness);
if (!horizontalRotationEnabled) {
angleH = 0;
}
if (!verticalRotationEnabled) {
angleV = 0;
}
// Get direction
lookDirGoal = Quaternion.AngleAxis (angleH, referenceUpDir) *
Quaternion.AngleAxis (angleV, referenceRightDir) *
referenceLookDir;
// Make look and up perpendicular
upDirGoal = referenceUpDir;
Vector3.OrthoNormalize (ref lookDirGoal, ref upDirGoal);
// Interpolated look and up directions in neck parent space
lookDir = lookDirGoal;
dirUp = Vector3.Slerp (dirUp, upDirGoal, currentTime * 5);
Vector3.OrthoNormalize (ref lookDir, ref dirUp);
// Look rotation in world space
lookRot = ((parentRot * Quaternion.LookRotation (lookDir, dirUp)) *
Quaternion.Inverse (parentRot * Quaternion.LookRotation (referenceLookDir, referenceUpDir)));
if (upperBodyRotationSpeed > 0) {
finalLookRotation = Quaternion.Slerp (finalLookRotation, lookRot, currentTime * upperBodyRotationSpeed);
} else {
finalLookRotation = lookRot;
}
// Distribute rotation over all joints in segment
dividedRotation = Quaternion.Slerp (Quaternion.identity, finalLookRotation, 0.5f);
chestRotation = dividedRotation;
spineRotation = dividedRotation;
}
if (usingWeaponRotationPoint) {
checkWeaponRotationPoint ();
}
}
void LateUpdate ()
{
if (IKUpperBodyActive) {
if (!isPlayerDead) {
if (chestRotationEnabled) {
chestTransform.rotation = chestRotation * chestTransform.rotation;
}
if (spineRotationEnabled) {
spineTransform.rotation = spineRotation * spineTransform.rotation;
}
if (extraHorizontalRotationEnabled) {
if (currentExtraRotation != 0) {
extraRotation = chestUpVector * currentExtraRotation;
chestTransform.localEulerAngles = new Vector3 (chestTransform.localEulerAngles.x, chestTransform.localEulerAngles.y, chestTransform.localEulerAngles.z) + extraRotation;
}
}
}
}
}
void checkWeaponRotationPoint ()
{
currentDeltatime = Time.smoothDeltaTime;
if (IKUpperBodyActive && weaponRotationPointToFollowLocated) {
currentRotation = weaponRotationPointToFollow.localEulerAngles.x;
if (usingDualWeapon) {
if (currentRightWeaponRotationPoint != null) {
if (followFullRotationPointDirection) {
updateFullRotationPoint (weaponRotationPointToFollow, currentRightWeaponRotationPoint,
rightRotationPointInfo.rotationPointSpeed, currentDeltatime);
} else {
if (currentRotation > 180) {
rotationXValue = (360 - currentRotation) / rightRotationPointInfo.rotationUpPointAmountMultiplier;
if (rightRotationPointInfo.useRotationUpClamp) {
rotationXValue = Mathf.Clamp (rotationXValue, 0, rightRotationPointInfo.rotationUpClampAmount);
}
rotationXValue *= (-1) * currentRightRotationDirection;
} else {
rotationXValue = currentRotation / rightRotationPointInfo.rotationDownPointAmountMultiplier;
if (rightRotationPointInfo.useRotationDownClamp) {
rotationXValue = Mathf.Clamp (rotationXValue, 0, rightRotationPointInfo.rotationDownClamp);
}
rotationXValue *= currentRightRotationDirection;
}
Quaternion weaponRotationPointTarget = Quaternion.Euler (new Vector3 (rotationXValue, 0, 0));
currentRightWeaponRotationPoint.localRotation =
Quaternion.Lerp (currentRightWeaponRotationPoint.localRotation, weaponRotationPointTarget, currentDeltatime * rightRotationPointInfo.rotationPointSpeed);
}
}
if (currentLeftWeaponRotationPoint != null) {
if (followFullRotationPointDirection) {
updateFullRotationPoint (weaponRotationPointToFollow, currentLeftWeaponRotationPoint,
leftRotationPointInfo.rotationPointSpeed, currentDeltatime);
} else {
if (currentRotation > 180) {
rotationXValue = (360 - currentRotation) / leftRotationPointInfo.rotationUpPointAmountMultiplier;
if (leftRotationPointInfo.useRotationUpClamp) {
rotationXValue = Mathf.Clamp (rotationXValue, 0, leftRotationPointInfo.rotationUpClampAmount);
}
rotationXValue *= (-1) * currentLeftRotationDirection;
} else {
rotationXValue = currentRotation / leftRotationPointInfo.rotationDownPointAmountMultiplier;
if (leftRotationPointInfo.useRotationDownClamp) {
rotationXValue = Mathf.Clamp (rotationXValue, 0, leftRotationPointInfo.rotationDownClamp);
}
rotationXValue *= currentLeftRotationDirection;
}
Quaternion weaponRotationPointTarget = Quaternion.Euler (new Vector3 (rotationXValue, 0, 0));
currentLeftWeaponRotationPoint.localRotation =
Quaternion.Lerp (currentLeftWeaponRotationPoint.localRotation, weaponRotationPointTarget, currentDeltatime * leftRotationPointInfo.rotationPointSpeed);
}
}
} else {
if (followFullRotationPointDirection) {
updateFullRotationPoint (weaponRotationPointToFollow, currentWeaponRotationPoint,
rotationPointInfo.rotationPointSpeed, currentDeltatime);
} else {
if (currentRotation > 180) {
rotationXValue = (360 - currentRotation) / rotationPointInfo.rotationUpPointAmountMultiplier;
if (rotationPointInfo.useRotationUpClamp) {
rotationXValue = Mathf.Clamp (rotationXValue, 0, rotationPointInfo.rotationUpClampAmount);
}
rotationXValue *= (-1) * currentRotationDirection;
} else {
rotationXValue = currentRotation / rotationPointInfo.rotationDownPointAmountMultiplier;
if (rotationPointInfo.useRotationDownClamp) {
rotationXValue = Mathf.Clamp (rotationXValue, 0, rotationPointInfo.rotationDownClamp);
}
rotationXValue *= currentRotationDirection;
}
Quaternion weaponRotationPointTarget = Quaternion.Euler (new Vector3 (rotationXValue, 0, 0));
currentWeaponRotationPoint.localRotation =
Quaternion.Lerp (currentWeaponRotationPoint.localRotation, weaponRotationPointTarget, currentDeltatime * rotationPointInfo.rotationPointSpeed);
}
}
} else {
if (usingDualWeapon) {
bool rightWeaponIsReset = false;
bool leftWeaponIsReset = false;
if (currentRightWeaponRotationPoint != null) {
if (currentRightWeaponRotationPoint.localRotation != Quaternion.identity) {
currentRightWeaponRotationPoint.localRotation =
Quaternion.Lerp (currentRightWeaponRotationPoint.localRotation, Quaternion.identity, currentDeltatime * rightRotationPointInfo.rotationPointSpeed);
} else {
rightWeaponIsReset = true;
}
} else {
rightWeaponIsReset = true;
}
if (currentLeftWeaponRotationPoint != null) {
if (currentLeftWeaponRotationPoint.localRotation != Quaternion.identity) {
currentLeftWeaponRotationPoint.localRotation =
Quaternion.Lerp (currentLeftWeaponRotationPoint.localRotation, Quaternion.identity, currentDeltatime * leftRotationPointInfo.rotationPointSpeed);
} else {
leftWeaponIsReset = true;
}
} else {
leftWeaponIsReset = true;
}
if (rightWeaponIsReset && leftWeaponIsReset) {
usingWeaponRotationPoint = false;
}
} else {
if (currentWeaponRotationPoint != null) {
if (currentWeaponRotationPoint.localRotation != Quaternion.identity) {
currentWeaponRotationPoint.localRotation =
Quaternion.Lerp (currentWeaponRotationPoint.localRotation, Quaternion.identity, currentDeltatime * rotationPointInfo.rotationPointSpeed);
} else {
usingWeaponRotationPoint = false;
}
}
}
}
}
void updateFullRotationPoint (Transform rotationPointToFollow, Transform currentRotationPoint, float rotationPointSpeed, float currentDeltatime)
{
Quaternion weaponRotationPointTarget = Quaternion.LookRotation (rotationPointToFollow.forward, rotationPointToFollow.up);
Quaternion localRotation = Quaternion.Inverse (currentRotationPoint.parent.rotation) * weaponRotationPointTarget;
Vector3 localRotationEuler = localRotation.eulerAngles;
if (useFollowFullRotationClamp) {
float rotationClampX = localRotationEuler.x;
if (rotationClampX > 180) {
rotationClampX = (360 - rotationClampX) / followFullRotationPointMultipliers.x;
rotationClampX = Mathf.Clamp (rotationClampX, 0, followFullRotationClampX.x);
rotationClampX *= (-1) * currentRotationDirection;
} else {
rotationClampX = rotationClampX / followFullRotationPointMultipliers.x;
rotationClampX = Mathf.Clamp (rotationClampX, 0, followFullRotationClampX.y);
rotationClampX *= currentRotationDirection;
}
float rotationClampY = localRotationEuler.y;
if (rotationClampY > 180) {
rotationClampY = (360 - rotationClampY) / followFullRotationPointMultipliers.y;
rotationClampY = Mathf.Clamp (rotationClampY, 0, followFullRotationClampY.x);
rotationClampY *= (-1) * currentRotationDirection;
} else {
rotationClampY = rotationClampY / followFullRotationPointMultipliers.y;
rotationClampY = Mathf.Clamp (rotationClampY, 0, followFullRotationClampY.y);
rotationClampY *= currentRotationDirection;
}
float rotationClampZ = localRotationEuler.z;
if (rotationClampZ > 180) {
rotationClampZ = (360 - rotationClampZ) / followFullRotationPointMultipliers.z;
rotationClampZ = Mathf.Clamp (rotationClampZ, 0, followFullRotationClampZ.x);
rotationClampZ *= (-1) * currentRotationDirection;
} else {
rotationClampZ = rotationClampZ / followFullRotationPointMultipliers.z;
rotationClampZ = Mathf.Clamp (rotationClampZ, 0, followFullRotationClampZ.y);
rotationClampZ *= currentRotationDirection;
}
localRotationEuler = new Vector3 (rotationClampX, rotationClampY, rotationClampZ);
}
localRotation = Quaternion.Euler (localRotationEuler);
if (useSmoothRotationPointValue) {
currentRotationPoint.localRotation =
Quaternion.Lerp (currentRotationPoint.localRotation, localRotation, smoothRotationPointValue);
} else {
currentRotationPoint.localRotation =
Quaternion.Lerp (currentRotationPoint.localRotation, localRotation, currentTime * rotationPointSpeed);
}
}
// The angle between dirA and dirB around axis
public static float AngleAroundAxis (Vector3 dirA, Vector3 dirB, Vector3 axis)
{
// Project A and B onto the plane orthogonal target axis
dirA = dirA - Vector3.Project (dirA, axis);
dirB = dirB - Vector3.Project (dirB, axis);
// Find (positive) angle between A and B
float angle = Vector3.Angle (dirA, dirB);
return angle * (Vector3.Dot (axis, Vector3.Cross (dirA, dirB)) < 0 ? -1 : 1);
}
public void setCurrentBodyRotation (float bodyRotation)
{
currentExtraRotation = bodyRotation;
auxCurrentExtraRotation = currentExtraRotation;
}
public void enableOrDisableIKUpperBody (bool value)
{
if (value) {
IKUpperBodyActive = value;
}
checkSetExtraRotationCoroutine (value);
}
void checkSetExtraRotationCoroutine (bool state)
{
if (changeExtraRotation != null) {
StopCoroutine (changeExtraRotation);
}
if (gameObject.activeInHierarchy) {
changeExtraRotation = StartCoroutine (setExtraRotation (state));
} else {
if (state) {
maxBendingAngle = originalAngleDifference;
} else {
maxBendingAngle = 0;
IKUpperBodyActive = false;
}
}
}
IEnumerator setExtraRotation (bool state)
{
for (float t = 0; t < 1;) {
t += Time.deltaTime * rotationSpeed;
if (state) {
maxBendingAngle = Mathf.Lerp (maxBendingAngle, originalAngleDifference, t);
} else {
maxBendingAngle = Mathf.Lerp (maxBendingAngle, 0, t);
}
yield return null;
}
if (!state) {
IKUpperBodyActive = false;
}
}
public bool isIKUpperBodyActive ()
{
return IKUpperBodyActive;
}
public void checkShakeUpperBodyRotationCoroutine (float extraAngleValue, float speedValue)
{
if (!shakeUpperBodyEnabled || !IKUpperBodyActive) {
return;
}
stopShakeUpperBodyRotation ();
shakeUpperBodyRotationCoroutine = StartCoroutine (shakeUpperBodyRotation (extraAngleValue, speedValue));
}
public void stopShakeUpperBodyRotation ()
{
if (shakeUpperBodyRotationCoroutine != null) {
StopCoroutine (shakeUpperBodyRotationCoroutine);
}
}
IEnumerator shakeUpperBodyRotation (float extraAngleValue, float speedValue)
{
float angleTarget = auxCurrentExtraRotation + extraAngleValue;
for (float t = 0; t < 1;) {
t += Time.deltaTime * speedValue;
currentExtraRotation = Mathf.Lerp (currentExtraRotation, angleTarget, t);
yield return null;
}
for (float t = 0; t < 1;) {
t += Time.deltaTime * speedValue;
currentExtraRotation = Mathf.Lerp (currentExtraRotation, auxCurrentExtraRotation, t);
yield return null;
}
}
public void setCurrentWeaponRotationPoint (Transform newWeaponRotationPoint, weaponRotationPointInfo newRotationPointInfo, int newRotationDirection)
{
currentWeaponRotationPoint = newWeaponRotationPoint;
rotationPointInfo = newRotationPointInfo;
currentRotationDirection = newRotationDirection;
}
public void setUsingWeaponRotationPointState (bool state)
{
usingWeaponRotationPoint = state;
}
public void setUsingDualWeaponState (bool state)
{
usingDualWeapon = state;
}
public void setCurrentRightWeaponRotationPoint (Transform newWeaponRotationPoint, weaponRotationPointInfo newRotationPointInfo, int newRotationDirection)
{
currentRightWeaponRotationPoint = newWeaponRotationPoint;
rightRotationPointInfo = newRotationPointInfo;
currentRightRotationDirection = newRotationDirection;
}
public void setCurrentLeftWeaponRotationPoint (Transform newWeaponRotationPoint, weaponRotationPointInfo newRotationPointInfo, int newRotationDirection)
{
currentLeftWeaponRotationPoint = newWeaponRotationPoint;
leftRotationPointInfo = newRotationPointInfo;
currentLeftRotationDirection = newRotationDirection;
}
public void setTemporalObjectToFollow (Transform newObject)
{
temporalObjectToFollow = newObject;
usingTemporalObjectToFollow = temporalObjectToFollow != null;
}
public void setHorizontalBendingMultiplierValue (float newValue)
{
horizontalBendingMultiplier = newValue;
}
public void setOriginalHorizontalBendingMultiplier ()
{
setHorizontalBendingMultiplierValue (originalHorizontalBendingMultiplier);
}
public void setVerticalBendingMultiplierValue (float newValue)
{
verticalBendingMultiplier = newValue;
}
public void setOriginalVerticalBendingMultiplier ()
{
setVerticalBendingMultiplierValue (originalVerticalBendingMultiplier);
}
public void setFollowFullRotationPointDirectionState (bool state)
{
followFullRotationPointDirection = state;
}
public void setUseFollowFullRotationClampState (bool state)
{
useFollowFullRotationClamp = state;
}
public void setNewFollowFullRotationClampX (Vector2 newFollowFullRotationClampXValues)
{
followFullRotationClampX = newFollowFullRotationClampXValues;
}
public void setNewFollowFullRotationClampY (Vector2 newFollowFullRotationClampYValues)
{
followFullRotationClampY = newFollowFullRotationClampYValues;
}
public void setNewFollowFullRotationClampZ (Vector2 newFollowFullRotationClampZValues)
{
followFullRotationClampZ = newFollowFullRotationClampZValues;
}
public void setExtraHorizontalRotationEnabledState (bool state)
{
extraHorizontalRotationEnabled = state;
}
public void setHorizontalMaxAngleDifference (float newValue)
{
horizontalMaxAngleDifference = newValue;
}
public void setVerticalMaxAngleDifference (float newValue)
{
verticalMaxAngleDifference = newValue;
}
public void setOriginalHorizontalMaxAngleDifference ()
{
setHorizontalMaxAngleDifference (originalHorizontalMaxAngleDifference);
}
public void setOriginalVerticalMaxAngleDifference ()
{
setVerticalMaxAngleDifference (originalVerticalMaxAngleDifference);
}
public void setFullBodyAwarenessActiveState (bool state)
{
fullBodyAwarenessActive = state;
if (fullBodyAwarenessActive) {
if (currentWeaponRotationPoint != null) {
currentWeaponRotationPoint.localRotation = Quaternion.identity;
usingWeaponRotationPoint = false;
}
}
}
//EDITOR FUNCTIONS
public void setNewChestUpVectorValue (Vector3 newValue)
{
chestUpVector = newValue;
updateComponent ();
}
public void setSpineTransform (Transform newTransform)
{
spineTransform = newTransform;
updateComponent ();
}
public void setChestTransform (Transform newTransform)
{
chestTransform = newTransform;
updateComponent ();
}
public void updateComponent ()
{
GKC_Utils.updateComponent (this);
GKC_Utils.updateDirtyScene ("Update Upper Body Rotation System", gameObject);
}
}