1
\$\begingroup\$

I wrote this script quickly just for moving across my map for testing purposes. I created a prefab with this script on it and gave it the Destination GameObject which works fine, it teleports me as it should. However when I attach this script to another object with an new destination, it still takes me to the one on the prefab. What am I doing wrong?

public class TeleportationDevice : MonoBehaviour {
    public Transform destination;
    public GameObject interaction;
    public GameObject model;

    private GameObject player;
    private bool isInRange = false;

    void Update()
    {
        if (isInRange)
        {
            if (Input.GetKeyDown(KeyCode.E))
            {
                Teleport();
            }
        }
    }

    void OnTriggerEnter(Collider other)
    {
        if (other.tag == "Player")
        {
            // Show the interaction canvas
            interaction.transform.position = model.transform.position;
            interaction.SetActive(true);

            // Set player GameObject
            player = other.gameObject;

            // Make sure the player is within range
            if (other.transform.position.x <= this.transform.position.x + 20f)
            {
                isInRange = true;
            }
            else
            {
                isInRange = false;
            }
        }
    }

    void OnTriggerExit(Collider other)
    {
        if (other.tag == "Player")
        {
           interaction.SetActive(false);
        }
    }

    void Teleport()
    {
        player.transform.position = destination.position;
    }
  }
\$\endgroup\$
  • \$\begingroup\$ It doesn't look like you set isInRange to false anytime except OnTriggerEnter - so if you're in range when you approach Teleporter 1, and in range when you approach Teleporter 2, and Teleporter 3... now ALL the teleporters think you're in range no matter how far you've gone away. Now when you press E, whichever one Update()s last will win, overriding all the previous destinations. \$\endgroup\$ – DMGregory Apr 13 '16 at 1:12
  • \$\begingroup\$ If that solved your problem, let me know and I'll write it up as an answer, so this question can have closure. ;) \$\endgroup\$ – DMGregory Apr 13 '16 at 2:31
  • \$\begingroup\$ Yep it did solve my problem. \$\endgroup\$ – Casey Clayton Apr 15 '16 at 1:59
0
\$\begingroup\$

Rather than checking whether the player is in range when the player presses the activation button, this script has each teleporter remember whether the player is in range.

It does this by remembering isInRange = true when the player enters its trigger volume, and then trusting that this memory still accurately reflects the state of the world sometime later when the player presses the activation button.

The trouble is, after the player has entered the trigger, it doesn't check their range again and update their isInRange value to false if they wander away (either still inside the trigger, or exiting it and not re-entering - isInRange only gets changed within OnTriggerEnter)

So if I visit two teleporters in a row, entering each one's trigger volume within range and then exiting it, both teleporters think I'm in range.

If I press the activation button, both will teleport me to their destination. Whichever one happens to update later will be the result I observe, since it stomps over the changes made by the earlier one.

There are a number of ways to fix this:

  • Have each teleporter/activatable object check the range every time the player presses the activate button. This is blunt, but range checks are cheap, especially if you avoid square roots. (As an aside, your range checks here look... unorthodox - you're only checking distance along one half-axis? Is this deliberate?)

  • Move the activation check out of Update and into a coroutine that you start OnTriggerEnter() and stop in OnTriggerExit. That way, only things whose trigger volumes the player is in will listen to key presses.

  • Flip it around, so instead of every object listening for input and checking if the player is near, the player object listens for input then checks its vicinity for something to activate. This player script can either use a Physics query to find them each time, or keep a list of nearby objects that it updates in its trigger enter/exit methods.

\$\endgroup\$
0
\$\begingroup\$

I made some changes and simplified the code for you. You will need to set the collider on the Teleporter as a trigger and then drag in the object that you want your destination to be as well as your player character.

using UnityEngine;
using System.Collections;

public class playerTeleport : MonoBehaviour {

  bool isInRange = false; 
  public Transform destination;
  public GameObject player;


  void Update()
  {
    if (isInRange && Input.GetKeyDown(KeyCode.E))
      Teleport();
  }

  void OnTriggerEnter (Collider other)
  {
    if(other.gameObject == player)
      isInRange = true;
  }

  void OnTriggerExit (Collider other)
  {
    if(other.gameObject == player)
      isInRange = false;
  }

  void Teleport()
  {
    player.transform.position = destination.position;
  }
}
\$\endgroup\$

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.