Unity notes-29-ARPG game project-04-climbing system optimization and IK animation
IK was not mentioned in the previous article. This article supplements IK animation and some other optimization parts
Why add IK animation
First of all, if there is no IK animation, the action will wear the mold. The distance setting of the code can solve the problem to a certain extent, but it can not completely solve it. Therefore, IK animation is necessary. Secondly, especially when climbing to the top of the wall, without IK animation, the character's hands are usually floating, which is very bad for players, just like floating to the top. Is it strange
Secondly, some optimizations have been made, first about optimization, and then IK
Climbing code optimization
The detection code of climbing the top of the wall in the previous article has been optimized and is no longer detected by the auxiliary coordinates of the top of the head, which is prone to die piercing or floating bugs and is difficult to repair. Therefore, this article will change the way
lh = ani.GetBoneTransform(HumanBodyBones.LeftHand); rh = ani.GetBoneTransform(HumanBodyBones.RightHand);
First, find the left-hand and right-hand Transform components of the character model in Awake through the GetBoneTransform method. We use ray detection through the left-hand and right-hand of the character towards the wall to detect whether there is a wall. If no wall is detected, it means that we can climb the top, otherwise we can't;
/// <summary> ///Climbing wall top detection - optimized version 2.0 /// </summary> public void ClimbUpToLand_2() { if (!Physics.Linecast(lh.position-transform.forward.normalized*upCheckLength, lh.position + transform.forward.normalized * upCheckLength, environmentLayerMask)|| !Physics.Linecast(rh.position - transform.forward.normalized * upCheckLength, rh.position + transform.forward.normalized * upCheckLength, environmentLayerMask)) { canClimb = false; ani.CrossFade(GameConst.CLIMBTOUP_STATE, 0f); transform.position += transform.up.normalized * climbUpOffset; Invoke("ExitClimb", ani.GetCurrentAnimatorStateInfo(1).length); } }
However, I use line segment detection here, because in the actual test process, the ray will inexplicably fail to detect the wall, so it is no problem to replace it with line segment.
In this way, it will not lead to the problem of hanging hands when climbing the top.
IK animation settings
The IK settings for climbing involve left and right hands and feet, so you also need to get left and right feet
lf = ani.GetBoneTransform(HumanBodyBones.LeftFoot); rf = ani.GetBoneTransform(HumanBodyBones.RightFoot);
First, write the setting method of IK animation
public void SetIKPosition(Transform p,AvatarIKGoal goal,float weight,float offset) { RaycastHit hit; if (Physics.Raycast(p.position, transform.forward, out hit, fixedCheckLength, environmentLayerMask)) { ani.SetIKPositionWeight(goal,weight); ani.SetIKPosition(goal,hit.point+hit.normal.normalized*offset); } }
The parameters are: Transform, ikload, weight and offset of the corresponding part
Detect the wall currently climbed by hands and feet through radiographic testing, set the weight, and stick the hands and feet of the characters on the wall through offset debugging at the setting position.
Then call in OnAnimatorIK
public void OnAnimatorIK(int layerIndex) { if (ani.GetCurrentAnimatorStateInfo(1).shortNameHash == GameConst.CLIMB_STATE) { SetIKPosition(lh, AvatarIKGoal.LeftHand,handIKWeight,handIKOffset); SetIKPosition(rh, AvatarIKGoal.RightHand,handIKWeight,handIKOffset); SetIKPosition(lf, AvatarIKGoal.LeftFoot, footHopIKWeight, footHopIKOffset); SetIKPosition(rf, AvatarIKGoal.RightFoot, footHopIKWeight, footHopIKOffset); } else if (ani.GetCurrentAnimatorStateInfo(1).shortNameHash == GameConst.CLIMBHOP_STATE) { SetIKPosition(lh, AvatarIKGoal.LeftHand, handHopIKWeight, handHopIKOffset); SetIKPosition(rh, AvatarIKGoal.RightHand, handHopIKWeight, handHopIKOffset); SetIKPosition(lf, AvatarIKGoal.LeftFoot, footHopIKWeight, footHopIKOffset); SetIKPosition(rf, AvatarIKGoal.RightFoot, footHopIKWeight, footHopIKOffset); } else { ResetIKPositionWeight(AvatarIKGoal.LeftHand); ResetIKPositionWeight(AvatarIKGoal.RightHand); ResetIKPositionWeight(AvatarIKGoal.LeftFoot); ResetIKPositionWeight(AvatarIKGoal.RightFoot); } }
When the animation is playing climbing or jumping, set the IK animation of the left and right hands and feet, and reset the IK animation weight when not climbing
Reset weight
public void ResetIKPositionWeight(AvatarIKGoal goal) { ani.SetIKPositionWeight(goal, 0); }