How to use Mecanim's Target Matching?

Hi. To get straight to the point, I am attempting to use Mecanim to achieve a climbing system a la Assassin’s Creed, and as far as I can tell Target Matching is the way to go. My Climb.js script is as follows.

private var animator : Animator;
var nearestObj : Transform = null;
private var dist = 1.5;
var furthestPoint : float;
var bodyPart : AvatarTarget;
private var state : AnimatorStateInfo;
var Player : Transform;
var grabPoint : Transform;

var weightPosition : float = 1;
var weightRotation : float = 1;

// the tag to search for (set this value in the inspector)
var searchTag = "Climbable";

// the frequency with which to re-scane for new nearest target in seconds 
// (set in inspector)
var scanFrequency = 1.0;

// the current target
private var target : Transform;


function Start() {
    // set up repeating scan for new targets:
    InvokeRepeating("ScanForTarget", 0, scanFrequency );
    animator = GetComponent ("Animator");
    var Player = GameObject.FindGameObjectWithTag("Player");
}

function Update() {
    // we rotate to look at the target every frame (if there is one)
    if (target != null) {
		if (animator) {
			var distance = Vector3.Distance(Player.transform.position, nearestObj.transform.position);
			if (distance < furthestPoint) {
				animator.MatchTarget(grabPoint.position, grabPoint.rotation, AvatarTarget.bodyPart, new MatchTargetWeightMask(Vector3.one, 1f), animator.GetFloat("MatchStart"), animator.GetFloat("MatchEnd"));
			}
			animator.SetBool("Climbing", false);
		}
	}
}

function ScanForTarget() {
    // this should be called less often, because it could be an expensive
    // process if there are lots of objects to check against
    target = GetNearestTaggedObject();

}

function GetNearestTaggedObject() : Transform {
    // and finally the actual process for finding the nearest object:

    var nearestDistanceSqr = Mathf.Infinity;
    var taggedGameObjects = GameObject.FindGameObjectsWithTag(searchTag); 

    // loop through each tagged object, remembering nearest one found
    for (var obj : GameObject in taggedGameObjects) {

        var objectPos = obj.transform.position;
        var distanceSqr = (objectPos - transform.position).sqrMagnitude;

        if (distanceSqr < nearestDistanceSqr) {
            nearestObj = obj.transform;
            nearestDistanceSqr = distanceSqr;
        }
    }

    return nearestObj;
}

As I am sure you will realize when you read the code, it is finding a GameObject tagged “Climbable” and, if that GameObject is close enough, setting TargetMatching’s goal to that GameObject. If there is a problem with the script, let me know. I am a novice coder and the distance-finding code is cobbled together from other posts on Answers anyways.

Thanks for your assistance,
chazman124

How are you assigning a value to bodyPart? I assume by manually dragging a part of your model into it in the properties inspector?

Furthermore, in line 37, you’re calling bodyPart as if it were a property of AvatarTarget:

animator.MatchTarget(grabPoint.position, grabPoint.rotation, AvatarTarget.bodyPart, new MatchTargetWeightMask(Vector3.one, 1f), animator.GetFloat("MatchStart"), animator.GetFloat("MatchEnd"));

But AvatarTarget doesn’t have that property, so I wonder why you don’t get any compiler errors here.
AvatarTarget is an Enumeration (see http://docs.unity3d.com/Documentation/ScriptReference/AvatarTarget.html), which in my understanding (I may be wrong!!) is used statically (e.g. as “AvatarTarget.Root”, without assigning an arbitrary object to it beforehand).

I’ve tried to reproduce your logic in my code:

  • I could define a variable of type
    AvatarTarget, but it’s just not
    assignable. Instead, I automatically
    get a dropdown selector for choosing
    from “Root”, “Body”, “Left Hand”,
    “Right Hand” etc. This doesn’t seem
    to make any harm, but it doesn’t work
    to any positive effect either.
  • However, using
    “AvatarTarget.bodyPart” creates a
    compiler error in my scenario!

I’m struggling a bit with target matching myself, but I think you can fix your rotation problem by setting the last parameter in the MatchTargetWeightMask to 0. This will mask out the rotation part (I think)

animator.MatchTarget(target.position, target.rotation, AvatarTarget.RightHand, new MatchTargetWeightMask(Vector3.one, 0), start, end);