6
\$\begingroup\$

I am using the following code to make a zombie move towards me, but when playing the scene the zombie seems to be moving towards me, but also off the ground and not fixed on the y-axis

 public GameObject ThePlayer;
public float TargetDistance;
public float AllowedRange = 10;
public GameObject TheEnemy;
public float EnemySpeed;
public int AttackTrigger;
public RaycastHit Shot;

void Update()
{
    transform.LookAt(ThePlayer.transform);
    if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.forward), out Shot))
    {
        TargetDistance = Shot.distance;
        if (TargetDistance < AllowedRange)
        {
            EnemySpeed = 0.01f;
            if (AttackTrigger == 0)
            {
                //TheEnemy.GetComponent<Animation>().Play("Walking");
                transform.position = Vector3.MoveTowards(transform.position, ThePlayer.transform.position, EnemySpeed);
            }
        }
        else
        {
            EnemySpeed = 0;
            //TheEnemy.GetComponent<Animation>().Play("Idle");
        }
    }

    if (AttackTrigger == 1)
    {
        EnemySpeed = 0;
        //TheEnemy.GetComponent<Animation>().Play("Attacking");
    }
}

void OnTriggerEnter()
{
    AttackTrigger = 1;
}

void OnTriggerExit()
{
    AttackTrigger = 0;
}

What can i do to ensure that it is sticking to the y axis at all times

\$\endgroup\$
12
\$\begingroup\$

The reason this is happening is because Vector3.MoveTowards will move all axes toward the target.

You can specifically exclude changes to the Y axis by creating a new target Vector3 having the Y axis set to the value it should stay at.

transform.position = Vector3.MoveTowards(
    transform.position,
    new Vector3(
        ThePlayer.transform.position.x,
        transform.position.y,
        ThePlayer.transform.position.z
    ),
    EnemySpeed
);

The above code creates a new Vector3 target where the Y axis is the same as the current position instead of the target, preventing Vector3.MoveTowards from changing the Y axis at all.

\$\endgroup\$
4
  • \$\begingroup\$ This works perfectly thank you! But when the zombie gets into close contact with me it seems to lean back and fall into the floor (weird), is it possible to state when it gets within a certain distance of me, stop moving towards me? \$\endgroup\$
    – Gurdeep
    Mar 6 '19 at 16:24
  • 2
    \$\begingroup\$ Sure, you can use Vector3.Distance(a, b) to check the distance between two objects. docs.unity3d.com/ScriptReference/Vector3.Distance.html \$\endgroup\$
    – EstelS
    Mar 6 '19 at 16:27
  • \$\begingroup\$ Is there any benefit to this approach over calculating the move-towards vector as normal and then just maintaining the current Y position during the assignment? i.e. Vector3 moveTowards = Vector3.MoveTowards(transform.position, ThePlater.transform.position, EnemySpeed); transform.position = new Vector3(moveTowards.x, transform.position.Y, moveTowards.z); \$\endgroup\$
    – Abion47
    Mar 6 '19 at 23:41
  • 1
    \$\begingroup\$ @Abion47 yes. Doing it as shown in EstelS's answer (if you apply appropriate frame time adjustment to the speed parameter not made explicit here), you can ensure that the speed of movement is exactly consistent no matter the origin/destination. If you compute the MoveTowards vector first, then override the y coordinate, you might shorten the total distance travelled - making the character move slower when seeking a target that's above/below them than when seeking directly sideways. In EstelS's answer, the shortening of the offset vector occurs before we enforce our consistent speed. \$\endgroup\$
    – DMGregory
    Mar 13 '19 at 0:25
3
\$\begingroup\$

You can break out the Vector3 target parameter of Vector3.MoveTowards to prevent movement on the y-axis. Simply set the y value of the target position to the same y value as the current position. For example:

Vector3 currentPosition = transform.position;
Vector3 targetPosition = new Vector3(ThePlayer.transform.position.x, transform.position.y, ThePlayer.transform.position.z);

transform.position = Vector3.MoveTowards(currentPosition, targetPosition, EnemySpeed);
\$\endgroup\$
1
\$\begingroup\$

The other answers are great. But if you have a RigidBody attached, you can freeze the y rotation via constraints. Then no code change would be necessary.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Except that the current code is moving the object via transform.position, which completely bypasses the Rigidbody and ignores any locking on its axes. \$\endgroup\$
    – DMGregory
    Mar 7 '19 at 12:22
  • 1
    \$\begingroup\$ @DMGregory indeed. Thank you. I'll delete this answer when I get to a computer \$\endgroup\$
    – Evorlor
    Mar 7 '19 at 14:08
  • 2
    \$\begingroup\$ Instead of deleting it, you could show how to move the Rigidbody with velocity instead of transform.position so the locked axes are respected. \$\endgroup\$
    – DMGregory
    Mar 7 '19 at 20:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.