/******************************************************************* * * アニメーションの処理 * *****************************************************************/ void AnimationState() { // 現在流れているanimationが前のアニメーションと違うなら処理 if (preAniState != AniState) { // アニメーション初期化 InitializeAnimation(); switch (AniState) { case ANIMATION_STATE._IDLE_ANIMATION: break; case ANIMATION_STATE._WALK_ANIMATION: animator.SetBool("WALK", true); break; case ANIMATION_STATE._RUN_ANIMATION: animator.SetBool("RUN", true); break; case ANIMATION_STATE._STOP_ANIMATION: animator.SetBool("STOP", true); break; case ANIMATION_STATE._CLEAR_ANIMATION: break; } this.preAniState = this.AniState; } }
/******************************************************************* * * 動きの処理 * *****************************************************************/ void PlayerMove() { // ロボットが空中にいたらこれ以降処理を読まない if (!isGround) { return; } this.cameraDirection = Vector3.Scale(mCamera.transform.forward, new Vector3(1, 0, 1)).normalized; // カメラの方向から、X-Z平面の単位ベクトルを取得 if (horizontal != 0 || vertical != 0) { this.moveDirection = (cameraDirection * vertical + mCamera.transform.right * horizontal).normalized; transform.rotation = Quaternion.LookRotation(moveDirection); // キャラクターの向きを進行方向に this.moveDirection *= walkSpeed; this.AniState = ANIMATION_STATE._WALK_ANIMATION; } else { this.AniState = ANIMATION_STATE._IDLE_ANIMATION; this.moveDirection = Vector3.zero; // 移動方向初期化 rigidBody.velocity = Vector3.zero; // 移動量初期化 } // Yボタンが押されたらロボットを稼働停止にさせる if (xboxInput.Check(XboxInput.KEYMODE.DOWN, XboxInput.PAD.KEY_Y)) { StopMove(); return; } this.rigidBody.velocity = moveDirection * Time.deltaTime; // 速度設定 }
[SerializeField] float fStabTorsoRotMulti = 40f; //multiplier value that decides how much the character's torso rotates // Start is called before the first frame update void Start() { eAnimState = ANIMATION_STATE.NONE; v3RightFootTarget = goRightFoot.transform.position; v3LeftFootTarget = goLeftFoot.transform.position; v3TorsoTarget = goChestEffector.transform.position; fStartHeight = goChestEffector.transform.position.y; Vector3 direction = goLeftFootStab.transform.position - goRightFootStab.transform.position; Vector3 left = Vector3.Cross(Vector3.up, direction); fStabTorsoRotation = left.x * fStabTorsoRotMulti; }
public void ToggleAnimation(ANIMATION_STATE newState) { if (newState == ANIMATION_STATE.IDLE) { animationState = ANIMATION_STATE.IDLE; animator.ResetTrigger("Walk"); animator.SetTrigger("Idle"); } else if (newState == ANIMATION_STATE.WALK) { animationState = ANIMATION_STATE.IDLE; animator.ResetTrigger("Idle"); animator.SetTrigger("Walk"); } }
private void Use(GameObject newAnimation, ANIMATION_STATE newState) { GameObject.Destroy(animation, 0); Vector3 pos = this.transform.position; pos.x = pos.x + animationSpawnOffset.x; pos.y = pos.y + animationSpawnOffset.y; pos.z = pos.z + animationSpawnOffset.z; Quaternion rotation; if (animation == null) { rotation = this.transform.rotation; } else { rotation = animation.transform.rotation; } animation = Instantiate(newAnimation, pos, rotation); animation.transform.parent = this.transform; animationState = newState; }
/// <summary> /// 애니메이션 변경 함수 /// </summary> /// <param name="state"></param> public void SetAnimation(ANIMATION_STATE state) { _animatorComp.SetInteger("AnimState", (int)state); }
public void Generate() { if (Application.isPlaying) { //delete any markers GameObject[] markers = GameObject.FindGameObjectsWithTag("Marker"); if (markers.Length != 0) { for (int i = 0; i < markers.Length; i++) { Destroy(markers[i]); } Debug.Log("Destroyed Markers"); } else { Debug.Log("No Markers To Destroy"); } //put feet into starting positions (arms are handled in the switch statement) v3RightFootTarget = goRightFootStart.transform.position; v3LeftFootTarget = goLeftFootStart.transform.position; goRightFoot.transform.position = v3RightFootTarget; goLeftFoot.transform.position = v3LeftFootTarget; switch (eAttackType) { case ATTACK_TYPE.THRUST: //set a number of random positions in front of the character (spread affected by skill) Vector3 stabCentre = goStabStart.transform.position + (fStabDistance * goCharacter.transform.forward); stabLocations = new Vector3[iNumOfAttacks]; if (fAttackSkill < 1) { for (int i = 0; i < iNumOfAttacks; i++) { //set to random location Vector2 randomPos = Random.insideUnitCircle * (1 / fAttackSkill) * fStabMultiplier; Vector3 randomPoint = stabCentre + new Vector3(randomPos.x, randomPos.y, 0); //convert to 3D point //rotate point around pivot Vector3 dir = randomPoint - stabCentre; dir = goCharacter.transform.rotation * dir; randomPoint = dir + stabCentre; stabLocations[i] = randomPoint; GameObject.Instantiate(goStabMarkerPrefab, stabLocations[i], goCharacter.transform.rotation); } } else { for (int i = 0; i < iNumOfAttacks; i++) { //set to stab position stabLocations[i] = stabCentre; GameObject.Instantiate(goStabMarkerPrefab, stabLocations[i], goCharacter.transform.rotation); } } //move left hand goOffHand.transform.position = goOffHandStab.transform.position; goOffHand.transform.rotation = goOffHandStab.transform.rotation; //move fingers goOffIndex.transform.position = goOffStabIndex.transform.position; goOffIndex.transform.rotation = goOffStabIndex.transform.rotation; goOffMiddle.transform.position = goOffStabMiddle.transform.position; goOffMiddle.transform.rotation = goOffStabMiddle.transform.rotation; goOffRing.transform.position = goOffStabRing.transform.position; goOffRing.transform.rotation = goOffStabRing.transform.rotation; goOffPinky.transform.position = goOffStabPinky.transform.position; goOffPinky.transform.rotation = goOffStabPinky.transform.rotation; goOffThumb.transform.position = goOffStabThumb.transform.position; goOffThumb.transform.rotation = goOffStabThumb.transform.rotation; iIndex = 0; startTime = Time.time; windupTime = 1f / (fAttackSpeed * fStabSpeedMultiplier); eAnimState = ANIMATION_STATE.WINDUP; break; case ATTACK_TYPE.SLASH: //plan slashing positions v3SlashCentre = goCharacter.transform.position + new Vector3(0, fSlashHeight * goCharacter.transform.up.y, 0) + (fSlashDistance * goCharacter.transform.forward); slashPoints = new GameObject[iNumOfAttacks]; tSlashStarts = new Transform[iNumOfAttacks]; tSlashEnds = new Transform[iNumOfAttacks]; tSlashWindups = new Transform[iNumOfAttacks]; for (int i = 0; i < iNumOfAttacks; i++) { slashPoints[i] = Instantiate(goSlashPointPrefab, v3SlashCentre, Quaternion.identity); slashPoints[i].transform.Rotate(Vector3.up, goCharacter.transform.rotation.eulerAngles.y); //If the user wants random directions, randomise some directions if (bRandomDirection) { int randomDirection = Random.Range(0, 359); iAttackDirection = randomDirection; slashPoints[i].transform.Rotate(Vector3.forward, iAttackDirection + 90f); //add 90 degrees to rotation so that 0 is vertically down } else //else, put all attacks in the same direction { slashPoints[i].transform.Rotate(Vector3.forward, iAttackDirection + 90f); //add 90 degrees to rotation so that 0 is vertically down } if (slashPoints[i].GetComponent <SlashPoint>() != null) //is there a slash point script? { if (slashPoints[i].GetComponent <SlashPoint>().slashLocations.Length == 2) //Are there two slash locations? { tSlashStarts[i] = slashPoints[i].GetComponent <SlashPoint>().slashLocations[0].transform; tSlashEnds[i] = slashPoints[i].GetComponent <SlashPoint>().slashLocations[1].transform; slashPoints[i].GetComponent <SlashPoint>().slashWindup.transform.position = new Vector3(slashPoints[i].GetComponent <SlashPoint>().slashWindup.transform.position.x, slashPoints[i].GetComponent <SlashPoint>().slashWindup.transform.position.y, fWindupDistance); if ((iAttackDirection + 90f) > fMinAvoidAngle && (iAttackDirection + 90f) < fMaxAvoidAngle) { //get windup position closest to windup of the slash point GameObject nearestWindup = null; float minDistance = Mathf.Infinity; foreach (GameObject windup in presetWindups) { float distance = Vector3.Distance(windup.transform.position, slashPoints[i].GetComponent <SlashPoint>().slashWindup.transform.position); if (distance < minDistance) { nearestWindup = windup; minDistance = distance; } } tSlashWindups[i] = nearestWindup.transform; Debug.Log(nearestWindup.name); } else { tSlashWindups[i] = slashPoints[i].GetComponent <SlashPoint>().slashWindup.transform; } } else { Debug.LogError("There must be two slash locations on the slash point"); } } else { Debug.LogError("Slash Point has no script!"); } } //put character in slashing stance goSwordHand.transform.position = goSlashIdle.transform.position; goSwordHand.transform.rotation = goSlashIdle.transform.rotation; //move fingers goOffIndex.transform.position = goOffSlashIndex.transform.position; goOffIndex.transform.rotation = goOffSlashIndex.transform.rotation; goOffMiddle.transform.position = goOffSlashMiddle.transform.position; goOffMiddle.transform.rotation = goOffSlashMiddle.transform.rotation; goOffRing.transform.position = goOffSlashRing.transform.position; goOffRing.transform.rotation = goOffSlashRing.transform.rotation; goOffPinky.transform.position = goOffSlashPinky.transform.position; goOffPinky.transform.rotation = goOffSlashPinky.transform.rotation; goOffThumb.transform.position = goOffSlashThumb.transform.position; goOffThumb.transform.rotation = goOffSlashThumb.transform.rotation; iIndex = 0; iSlashStage = 0; startTime = Time.time; windupTime = 1f / (fAttackSpeed); arcStart = goSlashIdle.transform.position; arcEnd = tSlashWindups[iIndex].position; eAnimState = ANIMATION_STATE.WINDUP; break; default: break; } } else { Debug.LogError("Animations can only be generated in Play Mode"); } }
// Update is called once per frame void Update() { //update left hand position while slashing if (eAttackType == ATTACK_TYPE.SLASH && eAnimState != ANIMATION_STATE.NONE) { goOffHand.transform.position = goSlashOffHandPoint.transform.position; goOffHand.transform.rotation = goSlashOffHandPoint.transform.rotation; } switch (eAnimState) { case ANIMATION_STATE.NONE: break; case ANIMATION_STATE.WINDUP: //move to start positions switch (eAttackType) { case ATTACK_TYPE.THRUST: fracComplete = (Time.time - startTime) / windupTime; //rotate hand back goSwordHand.transform.position = Vector3.Lerp(goSwordHand.transform.position, goStabStart.transform.position, fracComplete); if (goSwordHand.transform.position == goStabStart.transform.position) { if (iIndex > stabLocations.Length - 1) { startTime = Time.time; windupTime = 1f / (fAttackSpeed * fStabSpeedMultiplier); eAnimState = ANIMATION_STATE.RETURN; } else { startTime = Time.time; stabTime = 1f / (fAttackSpeed * fAttackWeight * fStabSpeedMultiplier); eAnimState = ANIMATION_STATE.ATTACK; } } break; case ATTACK_TYPE.SLASH: //plan arc Vector3 arcCentre = tSlashCentre.position; Vector3 arcStartRel = arcStart - arcCentre; Vector3 arcEndRel = arcEnd - arcCentre; fracComplete = (Time.time - startTime) / windupTime; //rotate chest to angle towards start point (based on fAttackSkill) Vector3 torsoCentre = new Vector3(v3SlashCentre.x, goChestEffector.transform.position.y, v3SlashCentre.z); //Vector3 for the centre of the torso's rotation (directly facing the direction of v3SlashCentre) Vector3 lookPoint = Vector3.Lerp(tSlashStarts[iIndex].position, torsoCentre, fAttackSkill); Vector3 direction = lookPoint - goChestEffector.transform.position; Quaternion toRotation = Quaternion.FromToRotation(goChestEffector.transform.forward, direction); goChestEffector.transform.rotation = Quaternion.Lerp(goChestEffector.transform.rotation, toRotation, fracComplete); //move/rotate right hand to windup point goSwordHand.transform.position = Vector3.Slerp(arcStartRel, arcEndRel, fracComplete); goSwordHand.transform.position += arcCentre; goSwordHand.transform.rotation = Quaternion.Lerp(goSwordHand.transform.rotation, tSlashWindups[iIndex].rotation, fracComplete); //move feet v3RightFootTarget = goRightFootStart.transform.position; v3LeftFootTarget = goLeftFootStart.transform.position; goRightFoot.transform.position = Vector3.Lerp(goRightFoot.transform.position, v3RightFootTarget, fracComplete); goLeftFoot.transform.position = Vector3.Lerp(goLeftFoot.transform.position, v3LeftFootTarget, fracComplete); if (goSwordHand.transform.position == tSlashWindups[iIndex].position && goRightFoot.transform.position == goRightFootStart.transform.position && goLeftFoot.transform.position == goLeftFootStart.transform.position) { iSlashStage = 1; startTime = Time.time; slashTime = 1f / (fAttackSpeed * fAttackWeight); arcStart = tSlashWindups[iIndex].position; arcEnd = tSlashStarts[iIndex].position; eAnimState = ANIMATION_STATE.ATTACK; } break; default: break; } break; case ANIMATION_STATE.ATTACK: switch (eAttackType) { case ATTACK_TYPE.SLASH: //move arms and chest to starting position of the slash if (iSlashStage == 1) { //plan arc Vector3 arcCentre = (arcStart + arcEnd) * 0.5f; arcCentre -= new Vector3(0, 1, 0); //adjust as necessary Vector3 arcStartRel = arcStart - arcCentre; Vector3 arcEndRel = arcEnd - arcCentre; fracComplete = (Time.time - startTime) / slashTime; //move chest towards centre? Vector3 torsoCentre = new Vector3(v3SlashCentre.x, goChestEffector.transform.position.y, v3SlashCentre.z); //Vector3 for the centre of the torso's rotation (directly facing the direction of v3SlashCentre) Vector3 direction = torsoCentre - goChestEffector.transform.position; Quaternion toRotation = Quaternion.FromToRotation(goChestEffector.transform.forward, direction); goChestEffector.transform.rotation = Quaternion.Lerp(goChestEffector.transform.rotation, toRotation, fracComplete); goSwordHand.transform.position = Vector3.Slerp(arcStartRel, arcEndRel, fracComplete); goSwordHand.transform.position += arcCentre; goSwordHand.transform.rotation = Quaternion.Lerp(goSwordHand.transform.rotation, tSlashStarts[iIndex].rotation, fracComplete); //move feet v3RightFootTarget = goRightFootSlashStart.transform.position; v3LeftFootTarget = goLeftFootSlashStart.transform.position; goRightFoot.transform.position = Vector3.Lerp(goRightFoot.transform.position, v3RightFootTarget, fracComplete); goLeftFoot.transform.position = Vector3.Lerp(goLeftFoot.transform.position, v3LeftFootTarget, fracComplete); if (goSwordHand.transform.position == tSlashStarts[iIndex].position && goRightFoot.transform.position == goRightFootSlashStart.transform.position && goLeftFoot.transform.position == goLeftFootSlashStart.transform.position) { iSlashStage = 2; startTime = Time.time; arcStart = tSlashStarts[iIndex].position; arcEnd = tSlashEnds[iIndex].position; slashTime = 1f / (fAttackSpeed * fAttackWeight); } } //once the arms get to starting position else if (iSlashStage == 2) { //plan arc Vector3 arcCentre = tSlashCentre.position; Vector3 arcStartRel = arcStart - arcCentre; Vector3 arcEndRel = arcEnd - arcCentre; fracComplete = (Time.time - startTime) / slashTime; //rotate chest to angle towards end point (based on fAttackSkill) Vector3 torsoCentre = new Vector3(v3SlashCentre.x, goChestEffector.transform.position.y, v3SlashCentre.z); //Vector3 for the centre of the torso's rotation (directly facing the direction of v3SlashCentre) Vector3 lookPoint = Vector3.Lerp(tSlashEnds[iIndex].position, torsoCentre, fAttackSkill); Vector3 direction = lookPoint - goChestEffector.transform.position; Quaternion toRotation = Quaternion.FromToRotation(goChestEffector.transform.forward, direction); goChestEffector.transform.rotation = Quaternion.Lerp(goChestEffector.transform.rotation, toRotation, fracComplete); //lerp hand positions and rotations, move chest to match goSwordHand.transform.position = Vector3.Slerp(arcStartRel, arcEndRel, fracComplete); goSwordHand.transform.position += arcCentre; goSwordHand.transform.rotation = Quaternion.Lerp(goSwordHand.transform.rotation, tSlashEnds[iIndex].rotation, fracComplete); //move feet v3RightFootTarget = goRightFootSlashEnd.transform.position; v3LeftFootTarget = goLeftFootSlashEnd.transform.position; goRightFoot.transform.position = Vector3.Lerp(goRightFoot.transform.position, v3RightFootTarget, fracComplete); goLeftFoot.transform.position = Vector3.Lerp(goLeftFoot.transform.position, v3LeftFootTarget, fracComplete); if (goSwordHand.transform.position == tSlashEnds[iIndex].position && goRightFoot.transform.position == goRightFootSlashEnd.transform.position && goLeftFoot.transform.position == goLeftFootSlashEnd.transform.position) { //after all positions, iterate iIndex++; startTime = Time.time; windupTime = 1f / (fAttackSpeed); arcStart = tSlashEnds[iIndex - 1].position; arcEnd = goSlashIdle.transform.position; eAnimState = ANIMATION_STATE.RETURN; } } else { Debug.LogError("Slash Stage Is Neither 1 or 2 During Attack State"); return; } break; case ATTACK_TYPE.THRUST: //get current attack currentAttack = stabLocations[iIndex]; //adjust for torso rotation Vector3 dir = currentAttack - goStabStart.transform.position; float rotation = (fStabTorsoRotation * -1) / 2; dir = Quaternion.Euler(0, rotation, 0) * dir; currentAttack = dir + goStabStart.transform.position; goSwordHand.transform.LookAt(currentAttack); goSwordHand.transform.rotation *= goStabStart.transform.localRotation; fracComplete = (Time.time - startTime) / stabTime; goSwordHand.transform.position = Vector3.Lerp(goSwordHand.transform.position, currentAttack, fracComplete); //move feet? fCentreOfMassDistribution = Mathf.Lerp(fCentreOfMassDistribution, 0.5f, fracComplete); v3RightFootTarget = goRightFootStab.transform.position; v3LeftFootTarget = goLeftFootStab.transform.position; goRightFoot.transform.position = Vector3.Lerp(goRightFoot.transform.position, v3RightFootTarget, fracComplete); goLeftFoot.transform.position = Vector3.Lerp(goLeftFoot.transform.position, v3LeftFootTarget, fracComplete); goLeftFoot.transform.rotation = Quaternion.Lerp(goLeftFoot.transform.rotation, goLeftFootStab.transform.rotation, fracComplete); if (goSwordHand.transform.position == currentAttack && goRightFoot.transform.position == goRightFootStab.transform.position && goLeftFoot.transform.position == goLeftFootStab.transform.position) { iIndex++; startTime = Time.time; windupTime = 1f / (fAttackSpeed * fStabSpeedMultiplier); eAnimState = ANIMATION_STATE.WINDUP; } break; default: break; } break; case ANIMATION_STATE.RETURN: //return to default position, delete all markers switch (eAttackType) { case ATTACK_TYPE.SLASH: //return to idle //plan arc Vector3 arcCentre = tSlashCentre.position; Vector3 arcStartRel = arcStart - arcCentre; Vector3 arcEndRel = arcEnd - arcCentre; fracComplete = (Time.time - startTime) / windupTime; //rotate chest to angle towards centre Vector3 torsoCentre = new Vector3(v3SlashCentre.x, goChestEffector.transform.position.y, v3SlashCentre.z); //Vector3 for the centre of the torso's rotation (directly facing the direction of v3SlashCentre) Vector3 direction = torsoCentre - goChestEffector.transform.position; Quaternion toRotation = Quaternion.FromToRotation(goChestEffector.transform.forward, direction); goChestEffector.transform.rotation = Quaternion.Lerp(goChestEffector.transform.rotation, toRotation, fracComplete); goSwordHand.transform.position = Vector3.Slerp(arcStartRel, arcEndRel, fracComplete); goSwordHand.transform.position += arcCentre; goSwordHand.transform.rotation = Quaternion.Lerp(goSwordHand.transform.rotation, goSlashIdle.transform.rotation, fracComplete); //move feet v3RightFootTarget = goRightFootStart.transform.position; v3LeftFootTarget = goLeftFootStart.transform.position; goRightFoot.transform.position = Vector3.Lerp(goRightFoot.transform.position, v3RightFootTarget, fracComplete); goLeftFoot.transform.position = Vector3.Lerp(goLeftFoot.transform.position, v3LeftFootTarget, fracComplete); if (goSwordHand.transform.position == goSlashIdle.transform.position && goRightFoot.transform.position == goRightFootStart.transform.position && goLeftFoot.transform.position == goLeftFootStart.transform.position) { if (iIndex > slashPoints.Length - 1) { eAnimState = ANIMATION_STATE.NONE; } else { startTime = Time.time; windupTime = 1f / (fAttackSpeed); arcStart = tSlashEnds[iIndex - 1].position; arcEnd = tSlashWindups[iIndex].position; v3RightFootTarget = goRightFootStart.transform.position; v3LeftFootTarget = goLeftFootStart.transform.position; eAnimState = ANIMATION_STATE.WINDUP; } } break; case ATTACK_TYPE.THRUST: //return to default fracComplete = (Time.time - startTime) / windupTime; //rotate hand back to normal goSwordHand.transform.position = Vector3.Lerp(goSwordHand.transform.position, goStabStart.transform.position, fracComplete); goSwordHand.transform.rotation = goStabStart.transform.rotation; //move left hand goOffHand.transform.position = Vector3.Lerp(goOffHand.transform.position, goOffHandStabIdle.transform.position, fracComplete); goOffHand.transform.rotation = goOffHandStabIdle.transform.rotation; //move feet back fCentreOfMassDistribution = Mathf.Lerp(fCentreOfMassDistribution, -0.5f, fracComplete); v3RightFootTarget = goRightFootStart.transform.position; v3LeftFootTarget = goLeftFootStart.transform.position; goRightFoot.transform.position = Vector3.Lerp(goRightFoot.transform.position, v3RightFootTarget, fracComplete); goLeftFoot.transform.position = Vector3.Lerp(goLeftFoot.transform.position, v3LeftFootTarget, fracComplete); goLeftFoot.transform.rotation = Quaternion.Lerp(goLeftFoot.transform.rotation, goLeftFootStart.transform.rotation, fracComplete); if (goSwordHand.transform.position == goStabStart.transform.position && goRightFoot.transform.position == goRightFootStart.transform.position && goLeftFoot.transform.position == goLeftFootStart.transform.position && goOffHand.transform.position == goOffHandStabIdle.transform.position) { eAnimState = ANIMATION_STATE.NONE; } break; default: break; } break; default: break; } //foot/chest placement //make sure feet stay on floor when not moving if (!bRightLegMoving) { goRightFoot.transform.position = new Vector3(goRightFoot.transform.position.x, fFootHeight, goRightFoot.transform.position.z); } if (!bLeftLegMoving) { goLeftFoot.transform.position = new Vector3(goLeftFoot.transform.position.x, fFootHeight, goLeftFoot.transform.position.z); } //get centre of mass based on foot position float ratio = fCentreOfMassDistribution + 1; //fix to get local direction instead of global Vector3 leftDistributed = goLeftFoot.transform.position * (2 - ratio); Vector3 rightDistributed = goRightFoot.transform.position * ratio; Vector3 midpoint = (leftDistributed + rightDistributed) / 2; v3TorsoTarget = midpoint; //torso follows to keep centre of mass balanced (within a range) goChestEffector.transform.position = v3TorsoTarget; //no need to lerp as the feet lerping will gradually change the target position instead. //calculate height to put torso at based on distance between feet float footDifference = Mathf.Abs(goLeftFoot.transform.localPosition.z - goRightFoot.transform.localPosition.z); float height = fStartHeight - footDifference / fCrouchRate; //move player to that height goChestEffector.transform.position = new Vector3(goChestEffector.transform.position.x, height, goChestEffector.transform.position.z); if (eAttackType == ATTACK_TYPE.THRUST) { //twist torso if thrusting sword Vector3 direction = goLeftFoot.transform.localPosition - goRightFoot.transform.localPosition; Vector3 left = Vector3.Cross(Vector3.up, direction); goChestEffector.transform.rotation = goCharacter.transform.rotation * Quaternion.Euler(0, left.x * fStabTorsoRotMulti, 0); } else { goChestEffector.transform.rotation = goCharacter.transform.rotation; } }