/// <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> /// 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; }
/// <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> /// 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); 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; } }
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); } } }
/// <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> /// 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; }
/// <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; }
/// <summary> /// Preparing motion parameters for individual segment settings /// </summary> void TailSegment_PrepareMotionParameters(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; //// 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); }
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; } } } }
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_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_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_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; } } } }
public void SetChildRef(TailSegment child) { ChildBone = child; }
public void SetParentRef(TailSegment parent) { ParentBone = parent; BoneLength = (ProceduralPosition - ParentBone.ProceduralPosition).magnitude; }
void UpdateTailAlgorithm() { TailCalculations_Begin(); // Root definition 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); // 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; } } // 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 { } } } }
public override void Update() { base.Update(); if (this.culled) { return; } for (int i = 0; i < this.danglers.Length; i++) { this.danglers[i].Update(); } if (this.fish.Consious) { this.swim -= Custom.LerpMap(this.fish.swimSpeed, 1.6f, 5f, 0.0333333351f, 0.06666667f); } this.tail[0].connectedPoint = new Vector2?(this.fish.bodyChunks[1].pos); this.wings[0, 0].connectedPoint = new Vector2?(this.fish.bodyChunks[0].pos); this.wings[1, 0].connectedPoint = new Vector2?(this.fish.bodyChunks[0].pos); Vector2 vector = Custom.DirVec(this.fish.bodyChunks[1].pos, this.fish.bodyChunks[0].pos); Vector2 a = Custom.PerpendicularVector(vector); this.lastZRotation = this.zRotation; if (Mathf.Abs(vector.x) > 0.5f && this.fish.Consious) { this.zRotation = Vector2.Lerp(this.zRotation, new Vector2((vector.x <= 0f) ? 1f : -1f, 0f), 0.2f); } else { this.zRotation = Vector2.Lerp(this.zRotation, -vector, 0.5f); } this.zRotation = this.zRotation.normalized; if (this.fish.Consious) { float num = 1f - this.fish.bodyChunks[1].submersion; if (this.airEyes < num) { this.airEyes = Mathf.Min(this.airEyes + 0.1f, num); } else { this.airEyes = Mathf.Max(this.airEyes - 0.0333333351f, num); } } for (int i = 0; i < 2; i++) { this.flippers[i].Update(); this.flippers[i].ConnectToPoint(this.fish.bodyChunks[1].pos, (this.flipperGraphWidth + 7f) * this.fish.iVars.flipperSize, false, 0f, this.fish.bodyChunks[1].vel, 0.3f, 0f); Vector2 vector2 = a * this.zRotation.y * ((i != 0) ? 1f : -1f); vector2 += new Vector2(0f, -0.5f) * Mathf.Abs(this.zRotation.x); vector2 += vector * this.fish.iVars.flipperOrientation * 1.5f; if (this.fish.Consious) { if (i == 0 == this.zRotation.x < 0f) { vector2 += vector * Mathf.Sin(this.swim * 3.14159274f * 2f) * 0.3f * (1f - this.fish.jetActive); } else { vector2 += vector * Mathf.Cos(this.swim * 3.14159274f * 2f) * 0.3f * (1f - this.fish.jetActive); } vector2 = Vector2.Lerp(vector2, -vector, this.fish.jetActive * this.fish.jetWater); } this.flippers[i].vel += (this.fish.bodyChunks[1].pos + vector2 * (this.flipperGraphWidth + 7f) * this.fish.iVars.flipperSize - this.flippers[i].pos) / ((!this.fish.Consious) ? 16f : 8f); if (this.fish.room.PointSubmerged(this.flippers[i].pos)) { this.flippers[i].vel *= 0.9f; } else { GenericBodyPart genericBodyPart = this.flippers[i]; genericBodyPart.vel.y = genericBodyPart.vel.y - 0.6f; } if (this.fish.iVars.whiskers > 0) { for (int j = 0; j < this.fish.iVars.whiskers; j++) { this.whiskers[i, j].vel += this.whiskerDir(i, j, this.zRotation, vector) * this.whiskerProps[j, 2]; if (this.fish.room.PointSubmerged(this.whiskers[i, j].pos)) { this.whiskers[i, j].vel *= 0.8f; } else { GenericBodyPart genericBodyPart2 = this.whiskers[i, j]; genericBodyPart2.vel.y = genericBodyPart2.vel.y - 0.6f; } this.whiskers[i, j].Update(); this.whiskers[i, j].ConnectToPoint(this.fish.bodyChunks[2].pos - vector * 5f + this.whiskerDir(i, j, this.zRotation, vector) * 5f, this.whiskerProps[j, 0], false, 0f, this.fish.bodyChunks[2].vel, 0f, 0f); } } for (int x = 0; x < 2; x++) { for (int k = 0; k < this.wings.GetLength(1); k++) { Vector2 look = Custom.PerpendicularVector(Custom.DirVec(this.fish.bodyChunks[1].pos, this.fish.bodyChunks[0].pos)); if (x == 0) { look = -look; } float push = Custom.AimFromOneVectorToAnother(this.fish.bodyChunks[0].pos + look, this.fish.bodyChunks[0].pos); this.wings[x, k].Update(); float num2 = Mathf.InverseLerp(0f, (float)(this.wings.GetLength(1) - 1), (float)k); if (!Custom.DistLess(this.wings[x, k].pos, this.fish.bodyChunks[1].pos, 15f * (float)(k + 1))) { this.wings[x, k].pos = this.fish.bodyChunks[1].pos + Custom.DirVec(this.fish.bodyChunks[1].pos, this.wings[x, k].pos) * 15f * (float)(k + 1); } float num3 = this.fish.jetActive; if (this.fish.room.PointSubmerged(this.wings[x, k].pos)) { this.wings[x, k].vel *= 0.7f; num3 = Mathf.Lerp(num3, 0f, 0.5f); } else { TailSegment wingSegment = this.wings[x, k]; wingSegment.vel.y = wingSegment.vel.y - 0.9f * Mathf.Pow((float)k / (float)(this.wings.GetLength(1) - 1), 3f); } this.wings[x, k].vel += a * Mathf.Sin((this.swim + (float)k / 5f) * 3.14159274f * 2f) * ((i != 0) ? -1f : 1f) * Mathf.Pow(1f - num2, 2f) * Custom.LerpMap(this.fish.swimSpeed, 1.6f, 5f, 8f, 16f) * (1f - num3); this.wings[x, k].vel -= look * (0.2f * (1f - num3) + Mathf.Pow(Mathf.InverseLerp(0.5f, 0f, num2), 2f) * Mathf.Lerp(27f, 11f, num3)); float num4 = 30f + Mathf.Sin(Mathf.Pow(num2, 1f) * 3.14159274f * -2f) * -100f; this.wings[x, k].vel -= Custom.DegToVec(push + num4 * ((i != 0) ? -1f : 1f)) * Mathf.Lerp(12f, 6f, num2) * num3; this.wings[x, k].connectionRad = Mathf.Lerp(10f, 0.5f, Mathf.Lerp(0f, num3, Mathf.Pow(num2, 0.2f))) * Mathf.Lerp(0.5f, 1.5f, this.fish.iVars.tentacleLength); this.wings[x, k].rad = Mathf.Lerp(this.TentacleContour(num2, k), Mathf.Lerp(8f, 2f, num2) * (0.5f + 0.5f * this.fish.jetWater), num3) * Mathf.Lerp(0.7f, 1.2f, this.fish.iVars.tentacleFatness); } } for (int k = 0; k < this.tail.Length; k++) { this.tail[k].Update(); float num2 = Mathf.InverseLerp(0f, (float)(this.tail.Length - 1), (float)k); if (!Custom.DistLess(this.tail[k].pos, this.fish.bodyChunks[1].pos, 15f * (float)(k + 1))) { this.tail[k].pos = this.fish.bodyChunks[1].pos + Custom.DirVec(this.fish.bodyChunks[1].pos, this.tail[k].pos) * 15f * (float)(k + 1); } float num3 = this.fish.jetActive; if (this.fish.room.PointSubmerged(this.tail[k].pos)) { this.tail[k].vel *= 0.7f; num3 = Mathf.Lerp(num3, 0f, 0.5f); } else { TailSegment tailSegment = this.tail[k]; tailSegment.vel.y = tailSegment.vel.y - 0.9f * Mathf.Pow((float)k / (float)(this.tail.Length - 1), 3f); } this.tail[k].vel += a * Mathf.Sin((this.swim + (float)k / 5f) * 3.14159274f * 2f) * ((i != 0) ? -1f : 1f) * Mathf.Pow(1f - num2, 2f) * Custom.LerpMap(this.fish.swimSpeed, 1.6f, 5f, 8f, 16f) * (1f - num3); this.tail[k].vel -= vector * (0.2f * (1f - num3) + Mathf.Pow(Mathf.InverseLerp(0.5f, 0f, num2), 2f) * Mathf.Lerp(27f, 11f, num3)); float num4 = 30f + Mathf.Sin(Mathf.Pow(num2, 1f) * 3.14159274f * -2f) * -100f; this.tail[k].vel -= Custom.DegToVec(Custom.AimFromOneVectorToAnother(this.fish.bodyChunks[1].pos, this.fish.bodyChunks[0].pos) + num4 * ((i != 0) ? -1f : 1f)) * Mathf.Lerp(12f, 6f, num2) * num3; this.tail[k].connectionRad = Mathf.Lerp(10f, 0.5f, Mathf.Lerp(0f, num3, Mathf.Pow(num2, 0.2f))) * Mathf.Lerp(0.5f, 1.5f, this.fish.iVars.tentacleLength); this.tail[k].rad = Mathf.Lerp(this.TentacleContour(num2, k), Mathf.Lerp(8f, 2f, num2) * (0.5f + 0.5f * this.fish.jetWater), num3) * Mathf.Lerp(0.7f, 1.2f, this.fish.iVars.tentacleFatness); } } }
/// <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); } // 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(this); } 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> /// Tracks the tailsegments on the supplied image and returns /// the angles and distances of each segment from the tailstart /// </summary> /// <param name="image">The image on which to id the tail</param> /// <returns>NSegments number of TailPoints</returns> public TailSegment[] TrackTail(Image8 image) { lock (_regionLock) { //CURRENTLY ONLY DOWNWARD FACING TAILS ARE PROPERLY VERIFIED!!! //Generate background by morphology operation - 10 times a second or whenever our coordinates changed //in the default case where the tail is darker than the background, using closing operation otherwise opening if (_frameNumber % (_frameRate / 10) == 0 || !_bgValid) { if (!_bgValid) { //if our regions changed, reblank our images! ip.ippiSet_8u_C1R(0, _background.Image, _background.Stride, _background.Size); ip.ippiSet_8u_C1R(0, _foreground.Image, _foreground.Stride, _foreground.Size); ip.ippiSet_8u_C1R(0, _thresholded.Image, _thresholded.Stride, _thresholded.Size); } if (_lightOnDark) { BWImageProcessor.Open(image, _background, _calc1, _strel, _trackRegionOuter); } else { BWImageProcessor.Close(image, _background, _calc1, _strel, _trackRegionOuter); } _bgValid = true; } //Compute foreground IppHelper.IppCheckCall(cv.ippiAbsDiff_8u_C1R(_background[_trackRegionInner.TopLeft], _background.Stride, image[_trackRegionInner.TopLeft], image.Stride, _foreground[_trackRegionInner.TopLeft], _foreground.Stride, _trackRegionInner.Size)); //Threshold BWImageProcessor.Im2Bw(_foreground, _thresholded, _trackRegionInner, _threshold); //Fill small holes BWImageProcessor.Close3x3(_thresholded, _thresholded, _calc1, _trackRegionOuter); } //Tracking concept: We track the angle of each segment end (TailStart+SegmentLength:TailEnd) //as the angular displacement from the previous segment end //To do this we define one full-circle with radius SegmentLength and an angle step corresponding //to ~1 Pixel. Then for each angle we pre-compute in InitializeScanPoints the corresponding x //and y offsets. From the full circle set we track -90 to +90 degrees around the angle of the //previous segment - for the initial segment that angle will be 0. For each segment we will return //the segment angle and its associated end-point coordinate var retval = new TailSegment[_nSegments]; lock (_scanPointLock) { //The index of the absolute angle of the previous segment in our angle sweep array //determines which angles we sweep over for the next segment int prevAngleIndex = _scanAngles.Length / 2; int nAnglesPerHalfPi = prevAngleIndex / 2;//this is the number of entries in the array that we have to walk to cover 90 degrees //we scan beginning with one segment length away from tail start and then walk //down the tail rather than using circles fixed arount the tailstart IppiPoint prevSegmentEnd = TailStart; //loop over tail segments for (int i = 0; i < _nSegments; i++) { //loop over scan-points from -pi/2 to +pi/2 (i.e. nAnglesPerHalfPi) around previous segment angle //interpreting the scan points as offsets around the previous tail segment //end point //then find tail angle of this segment int pointsFound = 0;//the number of non-zero pixels identified for (int j = -1 * nAnglesPerHalfPi; j < nAnglesPerHalfPi + 1; j++) { //Determine the index to scan - usually this will simply be "prevAngleIndex+j" however we //have to loop around our angle array properly in case we screen more extreme angles int currIndex = prevAngleIndex + j; if (currIndex >= _scanAngles.Length) { currIndex = currIndex % _scanAngles.Length; } else if (currIndex < 0) { currIndex = currIndex + _scanAngles.Length; } //If current point is outside of the image, ignore it IppiPoint pt = new IppiPoint(_coordinateOffsets[currIndex].x + prevSegmentEnd.x, _coordinateOffsets[currIndex].y + prevSegmentEnd.y); if (pt.x < 0 || pt.y < 0 || pt.x >= _imageSize.width || pt.y >= _imageSize.height) { continue; } //if the value at the current point >0 we mark that angle as valid //by storing the index in our anglestore if (*_thresholded[pt] > 0) { _angleStore[pointsFound] = currIndex; pointsFound++; } } //find the median point in our angle store if we have more than 2 points stored //the value in our angle store will directly give us the absolute screen angle of the segment //as well as the coordinate offset which we can used together with the previous segment endpoint //to compute the tail segment end coordinate - to get the delta angle we need to get the difference //between the stored index and the previously stored index, prevAngleIndex //after computing the appropriate return values we update prevAngleIndex with the index from the angle store //and prevSegmentEnd with the returned coordinate of the current tail segment double deltaTailAngle; IppiPoint coordinate; int pos; //the index in the angle store that we determine to be the tail-center if (pointsFound == 0) //we have lost the tail - no reason to keep tracking - fill remaining positions in array with NaNs for their angle { for (int k = i; k < _nSegments; k++) { deltaTailAngle = double.NaN; coordinate = new IppiPoint(); retval[k] = new TailSegment(deltaTailAngle, coordinate); } break; } else if (pointsFound < 3) { pos = _angleStore[0]; } else { //we want the angle at the median position of valid points //we don't compute intermediate positions however (we should be able to afford this since our angle step is so small), so in case //of an even number of points, the top of the lower half currently //wins - since array indexing is zero based, we have to subtract 1 //from the computed median position pos = _angleStore[(int)(Math.Ceiling(pointsFound / 2.0) - 1)]; } coordinate = new IppiPoint(prevSegmentEnd.x + _coordinateOffsets[pos].x, prevSegmentEnd.y + _coordinateOffsets[pos].y); deltaTailAngle = (pos - prevAngleIndex) * _angleStep; //the condition above of wrapping around the "angle circle":if (currIndex >= _scanAngles.Length).... //results in one very large (close to +360 or -360) angle of opposite sign at the switch point //however, since we usually only scan over offsets from +90 to -90 this case is easy to spot //and remedy: if (deltaTailAngle > 90) { deltaTailAngle = deltaTailAngle - 360;//this should create the appropriate tail angle btw. 0 and -90 } else if (deltaTailAngle < -90) { deltaTailAngle = 360 + deltaTailAngle;//this should create the appropriate tail angle btw. 0 and +90 } prevAngleIndex = pos; prevSegmentEnd = coordinate; retval[i] = new TailSegment(deltaTailAngle, coordinate); }//loop over tail segments } _frameNumber++; return(retval); }
private static void PlayerGraphics_Update(On.PlayerGraphics.orig_Update orig, PlayerGraphics self) { //Super.Update() self.lastCulled = self.culled; self.culled = self.ShouldBeCulled; if (!self.culled && self.lastCulled) { self.Reset(); } //Update() self.lastMarkAlpha = self.markAlpha; if (!self.player.dead && self.player.room.game.session is StoryGameSession && (self.player.room.game.session as StoryGameSession).saveState.deathPersistentSaveData.theMark) { self.markAlpha = Custom.LerpAndTick(self.markAlpha, Mathf.Clamp(Mathf.InverseLerp(30f, 80f, (float)self.player.touchedNoInputCounter) - Random.value * Mathf.InverseLerp(80f, 30f, (float)self.player.touchedNoInputCounter), 0f, 1f) * self.markBaseAlpha, 0.1f, 0.033333335f); } else { self.markAlpha = 0f; } if (self.player.input[1].x != self.player.input[0].x || self.player.input[1].y != self.player.input[0].y) { self.flail = Mathf.Min(1f, self.flail + 0.33333334f); } else { self.flail = Mathf.Max(0f, self.flail - 0.0125f); } self.lastBreath = self.breath; if (!self.player.dead) { if (self.player.Sleeping) { self.breath += 0.0125f; } else { self.breath += 1f / Mathf.Lerp(60f, 15f, Mathf.Pow(self.player.aerobicLevel, 1.5f)); } } if (self.lightSource != null) { self.lightSource.stayAlive = true; self.lightSource.setPos = new Vector2?(self.player.mainBodyChunk.pos); if (self.lightSource.slatedForDeletetion || self.player.room.Darkness(self.player.mainBodyChunk.pos) == 0f) { self.lightSource = null; } } else if (self.player.room.Darkness(self.player.mainBodyChunk.pos) > 0f && self.player.glowing) { self.lightSource = new LightSource(self.player.mainBodyChunk.pos, false, Color.Lerp(new Color(1f, 1f, 1f), PlayerGraphics.SlugcatColor(self.player.playerState.slugcatCharacter), 0.5f), self.player); self.lightSource.requireUpKeep = true; self.lightSource.setRad = new float?(300f); self.lightSource.setAlpha = new float?(1f); self.player.room.AddObject(self.lightSource); } if (self.malnourished > 0f && !self.player.Malnourished) { self.malnourished = Mathf.Max(0f, self.malnourished - 0.005f); } if (self.player.bodyMode == Player.BodyModeIndex.Stand && self.player.input[0].x != 0) { self.spearDir = Mathf.Clamp(self.spearDir + (float)self.player.input[0].x * 0.1f, -1f, 1f); } else if (self.spearDir < 0f) { self.spearDir = Mathf.Min(self.spearDir + 0.05f, 0f); } else if (self.spearDir > 0f) { self.spearDir = Mathf.Max(self.spearDir - 0.05f, 0f); } if (self.player.room.world.rainCycle.RainApproaching < 1f && Random.value > self.player.room.world.rainCycle.RainApproaching && Random.value < 0.009803922f && (self.player.room.roomSettings.DangerType == RoomRain.DangerType.Rain || self.player.room.roomSettings.DangerType == RoomRain.DangerType.FloodAndRain)) { self.objectLooker.LookAtPoint(new Vector2(self.player.room.PixelWidth * Random.value, self.player.room.PixelHeight + 100f), (1f - self.player.room.world.rainCycle.RainApproaching) * 0.6f); } float num = 0f; if (self.player.Consious && self.objectLooker.currentMostInteresting != null && self.objectLooker.currentMostInteresting is Creature) { CreatureTemplate.Relationship relationship = self.player.abstractCreature.creatureTemplate.CreatureRelationship((self.objectLooker.currentMostInteresting as Creature).abstractCreature.creatureTemplate); if (relationship.type == CreatureTemplate.Relationship.Type.Afraid && !(self.objectLooker.currentMostInteresting as Creature).dead) { float from = Mathf.Lerp(40f, 250f, relationship.intensity); num = Mathf.InverseLerp(from, 10f, Vector2.Distance(self.player.mainBodyChunk.pos, self.objectLooker.mostInterestingLookPoint) * ((!self.player.room.VisualContact(self.player.mainBodyChunk.pos, self.objectLooker.mostInterestingLookPoint)) ? 1.5f : 1f)); if ((self.objectLooker.currentMostInteresting as Creature).abstractCreature.abstractAI != null && (self.objectLooker.currentMostInteresting as Creature).abstractCreature.abstractAI.RealAI != null) { num *= (self.objectLooker.currentMostInteresting as Creature).abstractCreature.abstractAI.RealAI.CurrentPlayerAggression(self.player.abstractCreature); } } } if (!self.player.Consious) { self.objectLooker.LookAtNothing(); self.blink = 10; } if (self.DEBUGLABELS != null) { self.DEBUGLABELS[0].label.text = self.player.bodyMode.ToString() + " " + self.player.animation.ToString(); self.DEBUGLABELS[1].label.text = string.Concat(new object[] { "XPOS: ", self.player.mainBodyChunk.pos.x, " YPOS: ", self.player.mainBodyChunk.pos.y }); self.DEBUGLABELS[2].label.text = string.Concat(new object[] { "XPOS: ", self.player.bodyChunks[1].pos.x, " YPOS: ", self.player.bodyChunks[1].pos.y }); } for (int i = 0; i < self.owner.bodyChunks.Length; i++) { self.drawPositions[i, 1] = self.drawPositions[i, 0]; } self.drawPositions[0, 0] = self.owner.bodyChunks[0].pos; self.drawPositions[1, 0] = self.owner.bodyChunks[1].pos; int num2 = 0; bool flag = false; float num3 = 1f; switch (self.player.bodyMode) { case Player.BodyModeIndex.Default: if (self.player.animation == Player.AnimationIndex.AntlerClimb) { num2 = 2; } else if (self.player.animation == Player.AnimationIndex.LedgeGrab) { self.legsDirection.y = self.legsDirection.y - 1f; self.drawPositions[0, 0].x -= (float)self.player.flipDirection * 5f; } else { num3 = 0f; } break; case Player.BodyModeIndex.Crawl: { num2 = 1; float num4 = Mathf.Sin((float)self.player.animationFrame / 21f * 2f * 3.1415927f); float num5 = Mathf.Cos((float)self.player.animationFrame / 14f * 2f * 3.1415927f); float num6 = (self.player.superLaunchJump <= 19) ? 1f : 0f; self.drawPositions[0, 0].x += num5 * (float)self.player.flipDirection * 2f; self.drawPositions[0, 0].y -= num4 * -1.5f - 3f; GenericBodyPart genericBodyPart = self.head; genericBodyPart.vel.y = genericBodyPart.vel.y - (num4 * -0.5f - 0.5f); GenericBodyPart genericBodyPart2 = self.head; genericBodyPart2.vel.x = genericBodyPart2.vel.x + ((self.owner.bodyChunks[0].pos.x >= self.owner.bodyChunks[1].pos.x) ? 1f : -1f); self.drawPositions[1, 0].x += -3f * num4 * (float)self.player.flipDirection; self.drawPositions[1, 0].y -= num5 * 1.5f - 7f + 3f * num6; break; } case Player.BodyModeIndex.Stand: self.drawPositions[0, 0].x += (float)self.player.flipDirection * 6f * Mathf.Clamp(Mathf.Abs(self.owner.bodyChunks[1].vel.x) - 0.2f, 0f, 1f); self.drawPositions[0, 0].y += Mathf.Cos((float)self.player.animationFrame / 6f * 2f * 3.1415927f) * 2f; self.drawPositions[1, 0].x -= (float)self.player.flipDirection * (1.5f - (float)self.player.animationFrame / 6f); self.drawPositions[1, 0].y += 2f + Mathf.Sin((float)self.player.animationFrame / 6f * 2f * 3.1415927f) * 4f; flag = (Mathf.Abs(self.owner.bodyChunks[0].vel.x) > 2f && Mathf.Abs(self.owner.bodyChunks[1].vel.x) > 2f); num3 = 1f - Mathf.Clamp((Mathf.Abs(self.owner.bodyChunks[1].vel.x) - 1f) * 0.5f, 0f, 1f); break; case Player.BodyModeIndex.WallClimb: { num2 = 1; self.legsDirection.y = self.legsDirection.y - 1f; self.drawPositions[0, 0].y += 2f; self.drawPositions[0, 0].x -= (float)self.player.flipDirection * ((self.owner.bodyChunks[1].ContactPoint.y >= 0) ? 5f : 3f); GenericBodyPart genericBodyPart3 = self.head; genericBodyPart3.vel.y = genericBodyPart3.vel.y - (float)self.player.flipDirection * 5f; break; } case Player.BodyModeIndex.ClimbingOnBeam: num2 = 2; switch (self.player.animation) { case Player.AnimationIndex.GetUpOnBeam: self.disbalanceAmount = 70f; break; case Player.AnimationIndex.StandOnBeam: num2 = 0; self.drawPositions[1, 0].y += 3f; flag = (Mathf.Abs(self.owner.bodyChunks[0].vel.x) > 2f && Mathf.Abs(self.owner.bodyChunks[1].vel.x) > 2f); num3 = 1f - Mathf.Clamp((Mathf.Abs(self.owner.bodyChunks[1].vel.x) - 1f) * 0.3f, 0f, 1f); if (flag) { TailSegment tailSegment = self.tail[0]; tailSegment.vel.x = tailSegment.vel.x - self.owner.bodyChunks[0].vel.x * 2f; TailSegment tailSegment2 = self.tail[0]; tailSegment2.vel.y = tailSegment2.vel.y + 1.5f; TailSegment tailSegment3 = self.tail[1]; tailSegment3.vel.x = tailSegment3.vel.x - self.owner.bodyChunks[0].vel.x * 0.2f; TailSegment tailSegment4 = self.tail[1]; tailSegment4.vel.y = tailSegment4.vel.y + 0.5f; } break; case Player.AnimationIndex.ClimbOnBeam: self.drawPositions[0, 0].x += (float)self.player.flipDirection * 2.5f + (float)self.player.flipDirection * 0.5f * Mathf.Sin((float)self.player.animationFrame / 20f * 3.1415927f * 2f); self.drawPositions[1, 0].x += (float)self.player.flipDirection * 2.5f * Mathf.Cos((float)self.player.animationFrame / 20f * 3.1415927f * 2f); break; case Player.AnimationIndex.GetUpToBeamTip: self.disbalanceAmount = 120f; break; } break; case Player.BodyModeIndex.Swimming: if (self.player.animation == Player.AnimationIndex.DeepSwim || self.player.input[0].x != 0) { self.drawPositions[1, 0] += Custom.PerpendicularVector(Custom.DirVec(self.player.bodyChunks[0].pos, self.player.bodyChunks[1].pos)) * Mathf.Sin(self.player.swimCycle * 2f * 3.1415927f) * 5f; } break; case Player.BodyModeIndex.ZeroG: self.disbalanceAmount = Mathf.Max(self.disbalanceAmount, 70f * Mathf.InverseLerp(0.8f, 1f, self.flail)); break; } switch (self.player.animation) { case Player.AnimationIndex.CorridorTurn: self.drawPositions[0, 0] += Custom.DegToVec(Random.value * 360f) * 3f * Random.value; self.drawPositions[1, 0] += Custom.DegToVec(Random.value * 360f) * 2f * Random.value; self.blink = 5; break; case Player.AnimationIndex.Roll: case Player.AnimationIndex.Flip: { float num7 = 6f; Vector2 a = Custom.DirVec(self.player.bodyChunks[0].pos, self.player.bodyChunks[1].pos); for (int j = 0; j < self.tail.Length; j++) { self.tail[j].vel += a * num7; num7 /= 1.7f; } break; } } if (self.player.bodyMode == Player.BodyModeIndex.Default && self.player.animation == Player.AnimationIndex.None && self.owner.bodyChunks[0].ContactPoint.x == 0 && self.owner.bodyChunks[0].ContactPoint.y == 0 && self.owner.bodyChunks[1].ContactPoint.x == 0 && self.owner.bodyChunks[1].ContactPoint.y == 0) { self.airborneCounter += self.owner.bodyChunks[0].vel.magnitude; } else { self.airborneCounter = 0f; } if (self.player.bodyMode == Player.BodyModeIndex.ClimbingOnBeam && (self.player.animation == Player.AnimationIndex.BeamTip || self.player.animation == Player.AnimationIndex.StandOnBeam)) { if (Mathf.Abs(self.owner.bodyChunks[0].vel.x) > 2f) { self.disbalanceAmount += ((self.player.animation != Player.AnimationIndex.BeamTip) ? 3f : 17f); } else { self.disbalanceAmount -= 1f; } self.disbalanceAmount = Mathf.Clamp(self.disbalanceAmount, 0f, 120f); self.balanceCounter += 1f + self.disbalanceAmount / 40f * (1f + Random.value); if (self.balanceCounter > 300f) { self.balanceCounter -= 300f; } float num8 = Mathf.Sin(self.balanceCounter / 300f * 3.1415927f * 2f) / (Mathf.Abs(self.owner.bodyChunks[1].vel.x) + 1f); self.drawPositions[0, 0].x += num8 * (self.disbalanceAmount + 20f) * 0.08f; self.drawPositions[0, 0].y += num8 * self.disbalanceAmount * 0.02f; TailSegment tailSegment5 = self.tail[0]; tailSegment5.vel.x = tailSegment5.vel.x + num8 * (self.disbalanceAmount + 20f) * 0.1f; TailSegment tailSegment6 = self.tail[1]; tailSegment6.vel.x = tailSegment6.vel.x + num8 * (self.disbalanceAmount + 20f) * 0.04f; } if (self.player.bodyMode == Player.BodyModeIndex.ZeroG) { self.disbalanceAmount -= 1f; self.disbalanceAmount = Mathf.Clamp(self.disbalanceAmount, 0f, 120f); self.balanceCounter += 1f + self.disbalanceAmount / 40f * (1f + Random.value); if (self.balanceCounter > 300f) { self.balanceCounter -= 300f; } float d = Mathf.Sin(self.balanceCounter / 300f * 3.1415927f * 2f); Vector2 vector = Custom.DirVec(self.player.bodyChunks[1].pos, self.player.mainBodyChunk.pos); Vector2 a2 = Custom.PerpendicularVector(vector); self.drawPositions[0, 0] += a2 * d * (self.disbalanceAmount + 20f) * 0.08f; self.tail[0].vel -= a2 * d * (self.disbalanceAmount + 20f) * 0.1f + vector * self.disbalanceAmount * 0.1f; self.tail[1].vel -= a2 * d * (self.disbalanceAmount + 20f) * 0.04f + vector * self.disbalanceAmount * 0.04f; } if (self.player.Consious && self.player.standing && num > 0.5f) { self.drawPositions[0, 0] += Custom.DirVec(self.objectLooker.mostInterestingLookPoint, self.player.bodyChunks[0].pos) * 3.4f * Mathf.InverseLerp(0.5f, 1f, num); self.head.vel += Custom.DirVec(self.objectLooker.mostInterestingLookPoint, self.head.pos) * 1.4f * Mathf.InverseLerp(0.5f, 1f, num); } if (num > 0f) { self.tail[0].vel += Custom.DirVec(self.objectLooker.mostInterestingLookPoint, self.drawPositions[1, 0]) * 5f * num; self.tail[1].vel += Custom.DirVec(self.objectLooker.mostInterestingLookPoint, self.drawPositions[1, 0]) * 3f * num; self.player.aerobicLevel = Mathf.Max(self.player.aerobicLevel, Mathf.InverseLerp(0.5f, 1f, num) * 0.9f); } Vector2 vector2 = self.owner.bodyChunks[0].pos; if (flag) { vector2 = self.owner.bodyChunks[1].pos; vector2.y -= 4f; vector2.x += (float)self.player.flipDirection * 16f * Mathf.Clamp(Mathf.Abs(self.owner.bodyChunks[1].vel.x) - 0.2f, 0f, 1f); } Vector2 pos = self.owner.bodyChunks[1].pos; float num9 = 28f; self.tail[0].connectedPoint = new Vector2?(self.drawPositions[1, 0]); for (int k = 0; k < self.tail.Length; k++) { self.tail[k].Update(); self.tail[k].vel *= Mathf.Lerp(0.75f, 0.95f, num3 * (1f - self.owner.bodyChunks[1].submersion)); TailSegment tailSegment7 = self.tail[k]; tailSegment7.vel.y = tailSegment7.vel.y - Mathf.Lerp(0.1f, 0.5f, num3) * (1f - self.owner.bodyChunks[1].submersion) * self.owner.room.gravity; num3 = (num3 * 10f + 1f) / 11f; if (!Custom.DistLess(self.tail[k].pos, self.owner.bodyChunks[1].pos, 9f * (float)(k + 1))) { self.tail[k].pos = self.owner.bodyChunks[1].pos + Custom.DirVec(self.owner.bodyChunks[1].pos, self.tail[k].pos) * 9f * (float)(k + 1); } self.tail[k].vel += Custom.DirVec(vector2, self.tail[k].pos) * num9 / Vector2.Distance(vector2, self.tail[k].pos); num9 *= 0.5f; vector2 = pos; pos = self.tail[k].pos; } if (self.player.swallowAndRegurgitateCounter > 15 && self.player.swallowAndRegurgitateCounter % 10 == 0) { self.blink = Math.Max(self.blink, Random.Range(-5, 8)); } if (self.swallowing > 0) { self.swallowing--; self.blink = 5; self.drawPositions[0, 0] = Vector2.Lerp(self.drawPositions[0, 0], self.drawPositions[1, 0], 0.4f * Mathf.Sin((float)self.swallowing / 12f * 3.1415927f)); } else if ((self.player.objectInStomach != null || KarmaAppetite_ExtraInventory.HasSomethingInInventory(self.player)) && self.player.swallowAndRegurgitateCounter > 0) //Head movement on spit { if (self.player.swallowAndRegurgitateCounter > 30) { self.blink = 5; } float num10 = Mathf.InverseLerp(0f, 110f, (float)self.player.swallowAndRegurgitateCounter); float num11 = (float)self.player.swallowAndRegurgitateCounter / Mathf.Lerp(30f, 15f, num10); if (self.player.standing) { self.drawPositions[0, 0].y += Mathf.Sin(num11 * 3.1415927f * 2f) * num10 * 2f; self.drawPositions[1, 0].y += -Mathf.Sin((num11 + 0.2f) * 3.1415927f * 2f) * num10 * 3f; } else { self.drawPositions[0, 0].y += Mathf.Sin(num11 * 3.1415927f * 2f) * num10 * 3f; self.drawPositions[0, 0].x += Mathf.Cos(num11 * 3.1415927f * 2f) * num10 * 1f; self.drawPositions[1, 0].y += Mathf.Sin((num11 + 0.2f) * 3.1415927f * 2f) * num10 * 2f; self.drawPositions[1, 0].x += -Mathf.Cos(num11 * 3.1415927f * 2f) * num10 * 3f; } } self.blink--; if (self.blink < -Random.Range(2, 1800)) { self.blink = Random.Range(3, Random.Range(3, 10)); } if (!self.player.dead) { if (self.player.exhausted) { if (self.player.aerobicLevel > 0.8f) { self.blink = Math.Max(self.blink, 1); } else if (Random.value < 0.02f) { self.blink = Math.Max(self.blink, Random.Range(10, 20)); } } if (self.player.lungsExhausted || self.player.exhausted) { self.objectLooker.LookAtNothing(); GenericBodyPart genericBodyPart4 = self.head; genericBodyPart4.vel.y = genericBodyPart4.vel.y + Mathf.Sin(self.player.swimCycle * 3.1415927f * 2f) * ((!self.player.lungsExhausted) ? 0.25f : 1f); self.drawPositions[0, 0].y += Mathf.Sin(self.player.swimCycle * 3.1415927f * 2f) * ((!self.player.lungsExhausted) ? 0.75f : 2.5f); self.blink = 1; } } if (Random.value < 0.1f) { self.objectLooker.Update(); } if (Random.value < 0.0025f) { self.objectLooker.LookAtNothing(); } self.lastLookDir = self.lookDirection; if (self.player.Consious && self.objectLooker.looking) { self.lookDirection = Custom.DirVec(self.head.pos, self.objectLooker.mostInterestingLookPoint); } else { self.lookDirection *= 0f; } if (num > 0.86f) { self.blink = 5; self.lookDirection *= -1f; } if (self.player.grasps[0] != null && self.player.grasps[0].grabbed is JokeRifle) { self.lookDirection = (self.player.grasps[0].grabbed as JokeRifle).aimDir; } if (self.player.standing) { if (self.player.input[0].x == 0) { self.head.vel -= self.lookDirection * 0.5f; } self.drawPositions[0, 0] -= self.lookDirection * 2f; } else { self.head.vel += self.lookDirection; } Vector2 b = Custom.DirVec(self.drawPositions[1, 0], self.drawPositions[0, 0]) * 3f; if (self.player.bodyMode == Player.BodyModeIndex.Crawl) { b.x *= 2.5f; } else if (self.player.bodyMode == Player.BodyModeIndex.CorridorClimb && b.y < 0f) { b.y *= 2f; } self.head.Update(); self.head.ConnectToPoint(Vector2.Lerp(self.drawPositions[0, 0], self.drawPositions[1, 0], 0.2f) + b, (self.player.animation != Player.AnimationIndex.HangFromBeam) ? 3f : 0f, false, 0.2f, self.owner.bodyChunks[0].vel, 0.7f, 0.1f); self.legs.Update(); if (self.player.bodyMode == Player.BodyModeIndex.CorridorClimb) { self.legs.ConnectToPoint(self.owner.bodyChunks[1].pos + Custom.DirVec(self.owner.bodyChunks[0].pos, self.owner.bodyChunks[1].pos) * 4f, 2f, false, 0.25f, self.owner.bodyChunks[1].vel, 0.5f, 0.1f); int num12 = Mathf.RoundToInt((270f - Custom.AimFromOneVectorToAnother(self.owner.bodyChunks[1].pos, self.owner.bodyChunks[0].pos)) / 45f); int num13 = 10; int num14 = 0; for (int l = 0; l < 4; l++) { if (self.owner.room.GetTile(self.owner.room.GetTilePosition(self.owner.bodyChunks[1].pos) + Custom.eightDirections[(l + num12 + 10) % 8]).Terrain == Room.Tile.TerrainType.Solid && self.owner.room.GetTile(self.owner.room.GetTilePosition(self.owner.bodyChunks[1].pos) + Custom.eightDirections[(l + num12 + 14) % 8]).Terrain == Room.Tile.TerrainType.Solid) { int num15 = 0; if (l == 1) { num15 = ((self.player.flipDirection != -1) ? 2 : 1); } else if (l == 3) { num15 = ((self.player.flipDirection != 1) ? 2 : 1); } else if (l == 2) { num15 = 3; } if (num15 < num13) { num13 = num15; switch (l) { case 0: num14 = 0; break; case 1: num14 = 45; break; case 2: num14 = ((self.player.flipDirection != -1) ? 90 : -90); break; case 3: num14 = -45; break; } } } } self.legsDirection += Custom.DegToVec(Custom.AimFromOneVectorToAnother(self.owner.bodyChunks[0].pos, self.owner.bodyChunks[1].pos) + (float)num14); } else if (self.owner.bodyChunks[1].ContactPoint.y == -1 || self.player.animation == Player.AnimationIndex.StandOnBeam) { self.legs.ConnectToPoint(self.owner.bodyChunks[1].pos + new Vector2(self.legsDirection.x * 8f, 1f), 5f, false, 0.25f, new Vector2(self.owner.bodyChunks[1].vel.x, -10f), 0.5f, 0.1f); self.legsDirection.x = self.legsDirection.x - (float)self.owner.bodyChunks[1].onSlope; self.legsDirection.y = self.legsDirection.y - 1f; } else if (self.player.animation == Player.AnimationIndex.BeamTip) { self.legs.ConnectToPoint(self.owner.bodyChunks[1].pos + new Vector2(0f, -8f), 0f, false, 0.25f, new Vector2(0f, -10f), 0.5f, 0.1f); self.legsDirection += Custom.DirVec(self.drawPositions[0, 0], self.owner.room.MiddleOfTile(self.owner.bodyChunks[1].pos) + new Vector2(0f, -10f)); } else if (self.player.animation == Player.AnimationIndex.ClimbOnBeam) { Vector2 b2 = new Vector2((float)(-(float)self.player.flipDirection) * (5f - Mathf.Sin((float)self.player.animationFrame / 20f * 3.1415927f * 2f)), -16f - 5f * Mathf.Cos((float)self.player.animationFrame / 20f * 3.1415927f * 2f)); self.legs.ConnectToPoint(self.owner.bodyChunks[0].pos + b2, 0f, false, 0.25f, new Vector2(0f, 0f), 0.5f, 0.1f); self.legsDirection.y = self.legsDirection.y - 1f; } else if (self.player.animation == Player.AnimationIndex.ZeroGSwim || self.player.animation == Player.AnimationIndex.ZeroGPoleGrab) { self.legs.ConnectToPoint(self.owner.bodyChunks[1].pos + Custom.DirVec(self.owner.bodyChunks[0].pos, self.owner.bodyChunks[1].pos) * 4f, 4f, false, 0f, self.owner.bodyChunks[1].vel, 0.2f, 0f); self.legsDirection = Custom.DirVec(self.owner.bodyChunks[0].pos, self.owner.bodyChunks[1].pos); self.legs.vel += self.legsDirection * 0.2f; } else { self.legs.ConnectToPoint(self.owner.bodyChunks[1].pos + new Vector2(self.legsDirection.x * 8f, (self.player.animation != Player.AnimationIndex.HangFromBeam) ? -2f : -5f), 4f, false, 0.25f, new Vector2(self.owner.bodyChunks[1].vel.x, -10f), 0.5f, 0.1f); self.legsDirection += self.owner.bodyChunks[1].vel * 0.01f; self.legsDirection.y = self.legsDirection.y - 0.05f; } self.legsDirection.Normalize(); if (self.player.Consious) { if (self.throwCounter > 0 && self.thrownObject != null) { self.hands[self.handEngagedInThrowing].reachingForObject = true; self.hands[self.handEngagedInThrowing].absoluteHuntPos = self.thrownObject.firstChunk.pos; if (Custom.DistLess(self.hands[self.handEngagedInThrowing].pos, self.thrownObject.firstChunk.pos, 40f)) { self.hands[self.handEngagedInThrowing].pos = self.thrownObject.firstChunk.pos; } else { self.hands[self.handEngagedInThrowing].vel += Custom.DirVec(self.hands[self.handEngagedInThrowing].pos, self.thrownObject.firstChunk.pos) * 6f; } self.hands[1 - self.handEngagedInThrowing].vel -= Custom.DirVec(self.hands[self.handEngagedInThrowing].pos, self.thrownObject.firstChunk.pos) * 3f; self.throwCounter--; } else if (self.player.handOnExternalFoodSource != null) { int num16 = (self.player.handOnExternalFoodSource.Value.x >= self.player.mainBodyChunk.pos.x) ? 1 : 0; self.hands[num16].reachingForObject = true; if (self.player.eatExternalFoodSourceCounter < 3) { self.hands[num16].absoluteHuntPos = self.head.pos; self.blink = Math.Max(self.blink, 3); } else { self.hands[num16].absoluteHuntPos = self.player.handOnExternalFoodSource.Value; } self.drawPositions[0, 0] += Custom.DirVec(self.drawPositions[0, 0], self.player.handOnExternalFoodSource.Value) * 5f; self.head.vel += Custom.DirVec(self.drawPositions[0, 0], self.player.handOnExternalFoodSource.Value) * 2f; } else if ((self.player.grasps[0] != null && self.player.grasps[0].grabbed is TubeWorm) || (self.player.grasps[1] != null && self.player.grasps[1].grabbed is TubeWorm)) { for (int m = 0; m < self.player.grasps.Length; m++) { if (self.player.grasps[m] != null && self.player.grasps[m].grabbed is TubeWorm) { self.hands[m].mode = Limb.Mode.HuntRelativePosition; self.hands[m].relativeHuntPos = new Vector2(5f * ((m != 0) ? 1f : -1f), -10f); } } } else if (self.player.spearOnBack != null && self.player.spearOnBack.counter > 5) { int num17 = -1; int num18 = 0; while (num18 < 2 && num17 == -1) { if ((self.player.spearOnBack.HasASpear && self.player.grasps[num18] == null) || (!self.player.spearOnBack.HasASpear && self.player.grasps[num18] != null && self.player.grasps[num18].grabbed is Spear)) { num17 = num18; } num18++; } if (num17 > -1) { if (self.player.grasps[num17] != null && self.player.grasps[num17].grabbed is Weapon) { (self.player.grasps[num17].grabbed as Weapon).ChangeOverlap(false); } self.hands[num17].reachingForObject = true; self.hands[num17].mode = Limb.Mode.HuntRelativePosition; if (self.player.spearOnBack.HasASpear) { self.hands[num17].relativeHuntPos = Vector3.Slerp(new Vector2(((num17 != 0) ? 1f : -1f) * 20f, -30f) * Mathf.Sin(Mathf.InverseLerp(9f, 20f, (float)self.player.spearOnBack.counter) * 3.1415927f), new Vector2(0f, 1f), Mathf.InverseLerp(9f, 20f, (float)self.player.spearOnBack.counter)); } else { self.hands[num17].relativeHuntPos = Vector3.Slerp(new Vector2(((num17 != 0) ? 1f : -1f) * 30f, -20f) * Mathf.Lerp(1f, 0.2f, Mathf.Abs(self.player.spearOnBack.flip)), new Vector2(1f, 1f), Mathf.InverseLerp(14f, 20f, (float)self.player.spearOnBack.counter)); } self.drawPositions[0, 0] += Custom.DirVec(self.hands[num17].absoluteHuntPos, self.drawPositions[0, 0]) * 0.7f; self.head.vel += Custom.DirVec(self.hands[num17].absoluteHuntPos, self.head.pos) * 1.5f; } } else if (self.player.FoodInStomach < self.player.MaxFoodInStomach && self.objectLooker.currentMostInteresting != null && num2 < 2 && ((self.objectLooker.currentMostInteresting is Fly && (self.objectLooker.currentMostInteresting as Fly).PlayerAutoGrabable) || num > 0.8f) && Custom.DistLess(self.player.mainBodyChunk.pos, self.objectLooker.mostInterestingLookPoint, 80f) && self.player.room.VisualContact(self.player.mainBodyChunk.pos, self.objectLooker.mostInterestingLookPoint)) { int num19 = -1; for (int n = 0; n < 2; n++) { if (self.player.grasps[n] == null && self.hands[1 - n].reachedSnapPosition) { num19 = n; } } if (self.objectLooker.currentMostInteresting is Fly && (self.objectLooker.currentMostInteresting as Fly).PlayerAutoGrabable && self.player.input[0].x != 0 && self.objectLooker.currentMostInteresting.bodyChunks[0].pos.x < self.player.mainBodyChunk.pos.x == self.player.input[0].x > 0) { num19 = -1; } if (num19 > -1) { self.hands[num19].reachingForObject = true; self.hands[num19].absoluteHuntPos = self.objectLooker.mostInterestingLookPoint; if (num == 0f) { self.drawPositions[0, 0] += Custom.DirVec(self.drawPositions[0, 0], self.objectLooker.mostInterestingLookPoint) * 5f; self.head.vel += Custom.DirVec(self.drawPositions[0, 0], self.objectLooker.mostInterestingLookPoint) * 2f; } } } } for (int num20 = 0; num20 < 2; num20++) { self.hands[num20].Update(); } if (self.player.sleepCurlUp > 0f) { float num21 = Mathf.Sign(self.player.bodyChunks[0].pos.x - self.player.bodyChunks[1].pos.x); Vector2 vector3 = (self.player.bodyChunks[0].pos + self.player.bodyChunks[1].pos) / 2f; self.drawPositions[0, 0] = Vector2.Lerp(self.drawPositions[0, 0], vector3, self.player.sleepCurlUp * 0.2f); self.drawPositions[1, 0] = Vector2.Lerp(self.drawPositions[1, 0], vector3, self.player.sleepCurlUp * 0.2f); self.drawPositions[0, 0].y += 2f * self.player.sleepCurlUp; self.drawPositions[1, 0].y += 2f * self.player.sleepCurlUp; self.drawPositions[1, 0].x -= 3f * num21 * self.player.sleepCurlUp; for (int num22 = 0; num22 < self.tail.Length; num22++) { float num23 = (float)num22 / (float)(self.tail.Length - 1); self.tail[num22].vel *= 1f - 0.2f * self.player.sleepCurlUp; self.tail[num22].pos = Vector2.Lerp(self.tail[num22].pos, self.drawPositions[1, 0] + new Vector2((Mathf.Sin(num23 * 3.1415927f) * 25f - num23 * 10f) * -num21, Mathf.Lerp(5f, -15f, num23)), 0.1f * self.player.sleepCurlUp); } self.head.vel *= 1f - 0.4f * self.player.sleepCurlUp; self.head.pos = Vector2.Lerp(self.head.pos, vector3 + new Vector2(num21 * 5f, -3f), 0.5f * self.player.sleepCurlUp); if (self.player.sleepCurlUp == 1f || Random.value < 0.033333335f) { self.blink = Math.Max(2, self.blink); } for (int num24 = 0; num24 < 2; num24++) { self.hands[num24].absoluteHuntPos = vector3 + new Vector2(num21 * 10f, -20f); } } if (self.player.Adrenaline > 0f) { float d2 = Mathf.Pow(self.player.Adrenaline, 0.2f); self.drawPositions[0, 0] += Custom.RNV() * Random.value * d2 * 2f; self.drawPositions[0, 1] += Custom.RNV() * Random.value * d2 * 2f; self.head.pos += Custom.RNV() * Random.value * d2 * 1f; if (Random.value < 0.05f) { self.blink = Math.Max(self.blink, 3); } } }
/// <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); } }
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 while (child != GhostChild) { // Preparing parameter values adapted to stiff and slithery character and blended TailSegment_PrepareMotionParameters(child); // Velocity changes detection TailSegment_PrepareVelocity(child); child = child.ChildBone; } } // Udpate for artificial end bone 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]; while (child != GhostChild) { 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; } } // Applying processing for artificial child bone without transform TailCalculations_UpdateArtificialChildBone(GhostChild); #endregion }