Initiative: Red Dawn

June 2, 2016

Making our character follow a path

In our game, the player creates floor tiles at will. There are a few pre existing tiles scattered around with mana and stamina potions. But the rest is up to the player. With that in mind, we need our character to be able to follow the user generated path as it moves. We decided to use a CharacterController earlier, so we have full control on our character movement, and also all responsibility to do so. We also want our character to move nicely over the middle of our path and stay there, and not bounce from wall to wall. To achieve that we are going to use Triggers. A trigger allows us to detect when an object enters a specific space without affecting its movement (i.e.: no collisions against a trigger). We can simply create a direction trigger. That basically is a trigger that we’ll make sure it will point towards the direction we want our character to face when it reaches it.
Screen Shot 2016-06-02 at 10.12.52 PM.png

The direction trigger

The code for that would be something like this:
    void OnTriggerEnter (Collider other) {         if (other.tag == DirectionTrigger) {             // Rotate towards the collider rotation             transform.eulerAngles = other.transform.eulerAngles;         }     }
This works fine when the rotation happens immediately, but most likely we want to animate our rotation. Let’s say we want our character to rotate in 500 ms (half a second). Then, during those 500 ms, our character will offset himself from the center of the path, because it moves while it rotates. And when it reaches its final rotation, he may be closer to the wall. Here you can see the concept

This slideshow requires JavaScript.

We can fix that, though. We can make our character, instead of simply rotate to the direction of the trigger, we can make him aim at the next trigger. We just have to make sure of two things:
  1. Our triggers are positioned in the middle of our path
  2. On the rotation tiles, the trigger needs to be on the actual rotation, not at the begining as that may cause our character to collide with the wall
That way, since our character will always face towards our next trigger, and since the trigger is in the middle of the path, our character will always move towards the middle of the path. It still drifts off the middle, but it self-adjusts. Here’s a sample. To perform the actual animation in our example we use iTween:
    void OnTriggerEnter (Collider other) {         if (other.tag == DirectionTrigger) {             // Now, turn towards our next DirectionTarget object             // The GetNextDirectionTrigger() returns the next trigger on our list             Transform directionTarget = GetNextDirectionTrigger(other.transform);             // Look at the trigger             transform.LookAt(directionTarget);             // And visually, animate the rotation             iTween.RotateFrom(gameObject, iTween.Hash(y, transform.eulerAngles.y, time, 1f, isLocal, true));             // Disable this collider             other.enabled = false;         }             }
There’s one more tweak we can do to further reduce the drift: we need to make sure our characer starts its rotation exactly at the position of our trigger. One way to achieve this would be to make our trigger very very tiny, and simply start our rotation OnTriggerEnter. But if the trigger is too small, we increase the chance our character will miss it if its going too fast. In Unity we have Continous Collision Detection to prevent these things. What it basically do is cast a ray from our character towards his forward vector, and set its length the soeed of the object. Essentially, we are checking where our character will be in the next frame, and check with a ray cast if we passed trough any colliders on the way. If we did, we only let our character advance as close as we can position him before the collision. But we are using triggers. Even if Unity’s Continous Collision Detection would work with triggers, we don’t want our character to be stopped at the trigger. That’s the whole point of using a trigger! There’s a nasty but simple solution between both worlds. We make our trigger not too big, but not to small either. Big enough to ensure our character will not pass it through in one frame to the next. And then, we keep track of the distance between the character and the trigger in OnTriggerStay. The frame that distance starts to increase, we execute our rotation and disable the trigger. It’s not the exact center of our trigger, but it’s pretty close and works wonderfully in our case. Here’s how:
    void OnTriggerStay (Collider other) {                  if (other.tag == DirectionTrigger) {             // Check the distance towards this trigger and store it             // If the distance is bigger than the last, then snap and rotate             float d = Vector3.Distance(transform.position, other.transform.position);             if (d > distanceToDirectionTrigger) {                                  // Make sure we dont come in here again                 distanceToDirectionTrigger = float.NegativeInfinity;                 // Since this distance is larger it means weve started to get away                 // Which means we are almost at the closest point                 // Now, turn towards our DirectionTarget object (child of the trigger)                 Transform directionTarget = other.transform;                 transform.LookAt(directionTarget);                 // And visually, animate the rotation                 iTween.RotateFrom(gameObject, iTween.Hash(y, transform.eulerAngles.y, time, 1f, isLocal, true));                 // Disable this collider                 other.enabled = false;             } else {                 // Store the new distance                 distanceToDirectionTrigger = d;             }         }             }
That’s it! We now have a character that follows the path the user creates, stays as close to the center as we can expect, and allows us to animate the rotation nicely. Remember to follow us for news about more articles and game development. Happy gaming! Don’t forget to follow us on twitter for news regarding articles and game development [twitter-follow screen_name=’indelvestudios’]

One Comment

  1. Spell Run – The backstage of a game | indelve
    June 3, 2016 @ 1:18 am

    […] Making our character follow the path […]


Leave a Reply