Hey guys,
so I’ve been trying to setup a situation where the player clicks on an object and the character walks to that object, all third person
I’ve been digging through the racing tutorial, but I can’t figure out how to reconcile the differences between using a rigid body on the AI cars and a character controller on my character.
so far I’ve managed to get the character to turn instantly toward the target object, and had him moving ~50 units per click towards it. I thought maybe a loop would be the way to go, to check if he was there yet, but my first attempt at a loop just seems to freeze Unity. Almost certainly my fault.
this is the script I’ve got on the character currently:
var speed = 50.0;
var lookTarget : Transform;
private var activeWayPoint : WayPoint;
var nextWayPoint : Transform;
function Start () {
// Initialize the waypoint we drive towards!
activeWayPoint = WayPoint.start;
// nextWayPoint = WayPoint.next;
}
function GoToPoint () {
var controller : CharacterController = GetComponent (CharacterController);
var forward = transform.TransformDirection(Vector3.forward);
transform.LookAt(lookTarget);
// this loop crashes Unity, wheeee
while (transform.position != nextWayPoint) {
controller.Move (forward * speed);
}
}
any suggestions? (would of course be madly appreciated!)
Two problems:
First, you need to check for the position being within a certain distance instead of equaling the Vector; you’re almost definitely shooting past it into infinity.
Second, you need to yield in your loop, making it wait between frames before moving any more.
Also, you probably want to use SimpleMove rather than Move.
Yep…transform.position will never == nextWayPoint (unless you get stupendously lucky), hence your while loop runs forever within one frame, which is what freezes Unity.
–Eric
Plus, nextWayPoint is a transform so you should check against its position in specific. For example:
while (Vector3.Distance(transform.position, nextWayPoint.position) > someDistanceYouNeedToSet) {
controller.SimpleMove(forward * speed);
yield;
}
Edit: or if you later switch it to be a proper WayPoint then you’ll have to check against nextWayPoint.transform.position.
That works, but it’s not rock solid.
For instance, with a low frame rate, you may go right through the waypoint, and then the distance will still be greater (just on the other side) but it’ll keep moving forward. (If the object is always updated to face the waypoint this works fine, however.)
The most rock solid way I’ve seen for doing these things is to keep track of the distance needed to travel at the outset. That is, every time you are about to travel in a straight line.
initialDistanceToWayPoint = Vector3.Distance(transform.position, nextWayPoint.position);
Now, keep track of the distance travelled so far.
distanceTraveled += speed * Time.deltaTime;
Keep moving while the distance travelled is less than the distance initially recorded. Then, You can set the position to the waypoint.
while (distanceTraveled < initialDistanceToWayPoint)
warning: untested code ahead.
initialDistanceToWayPoint = Vector3.Distance(transform.position, nextWayPoint.position);
distanceTraveled = 0.0;
while (distanceTraveled < initialDistanceToWayPoint)
{
controller.SimpleMove(forward * speed * Time.deltaTime);
distanceTraveled += speed * Time.deltaTime;
yield;
}
transform.position = nextWayPoint.position;
Also, notice the multiplication times Time.deltaTime so the speed will be the same on any computer and any framerate. 
thanks everyone, much has been explained
a couple of quick questions:
Tom - what did you mean “switch it to be a proper WayPoint”?
and in reference to your suggestion Aaron, about keeping speed consistent across machines, I dig the idea, but multiplying speed * Time.deltaTime, made the character move painfully slow and tripling the speed didn’t seem to make much of a difference. Is there something else I should be tweaking to modify speed, or is that just the nature of Time.deltaTime that it slows things down?
Yes, it slows things tremendously.
It’s usually a small fraction of a second. Time.deltaTime would be 0.0167 if you were getting 60 frames per second. The easy way to think about it is how far do you want it to move over a the span of a second. That’s your speed value.
thats a good way of looking at, thanks
so i’ve now got my character moving to the way point, but he’s not walking, normally his locomotion animations would be triggered by player input, in conjunction with the “ComplexWalkBlend” and “SampleMoveScript” scripts.
They worked so nicely out of the box, I didn’t really look into them much, but in trying to trigger his walk animation when he’s moving to the waypoint, I’ve started to. And realized I don’t understand how the ComplexWalkBlend is actually starting animations, there aren’t any “animation.Play” commands, so I’m thinking maybe it’s by turning up speed? and then blending it in by turning up the weight?
so far I’ve been trying to trigger the animation a couple of different ways:
-
the first was simply adding "animation.Play(“walk”), into the “while” statement that was triggering movement to the waypoint
-
this seemed to start the animation, it never seemed to get past the first frame, probably because it was calling the animation every frame?
-
I also tried:
function Update () {
var controller : CharacterController = GetComponent (CharacterController);
var forwardVelocity = controller.velocity.magnitude;
if (forwardVelocity > 0.01){
animation.PlayQueued("walk", QueueMode.CompleteOthers);
}
}
but this didn’t seem to work at all, my meager knowledge has been exhausted, and I’m out of ideas
probably another situation, where I’m just not getting how the underlying stuff works :roll:
Meant that in reference to the way points used in the racing tutorial as your script seemed a bit familiar to what’s shown there (it’s a script used in that demo that you can drag attach to an empty GO). Like the one you have in your initial script:
private var activeWayPoint : WayPoint;