I can't get Teleportation to work

I have been going crazy because I can’t figure out how to fix this code.

public class TeleportPlayer : MonoBehaviour
{
    public Transform target;

    void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Player"))
        {
            other.transform.position = target.position;
            Debug.Log("Teleported");
        }
    }
}

Basically it should teleport the player to a transform of a gameobject, the problem is that it does not work, I have put a Check to see if the player is colliding with the mesh collider (set to trigger) and it is in fact colliding, but for some reason the player does not teleport, the player has a charactercontroller attached and a script to make it move.

Time to start debugging! Here is how you can begin your exciting new debugging adventures:

You must find a way to get the information you need in order to reason about what the problem is.

Once you understand what the problem is, you may begin to reason about a solution to the problem.

What is often happening in these cases is one of the following:

  • the code you think is executing is not actually executing at all
  • the code is executing far EARLIER or LATER than you think
  • the code is executing far LESS OFTEN than you think
  • the code is executing far MORE OFTEN than you think
  • the code is executing on another GameObject than you think it is
  • you’re getting an error or warning and you haven’t noticed it in the console window

To help gain more insight into your problem, I recommend liberally sprinkling Debug.Log() statements through your code to display information in realtime.

Doing this should help you answer these types of questions:

  • is this code even running? which parts are running? how often does it run? what order does it run in?
  • what are the names of the GameObjects or Components involved?
  • what are the values of the variables involved? Are they initialized? Are the values reasonable?
    - are you meeting ALL the requirements to receive callbacks such as triggers / colliders (review the documentation)

Knowing this information will help you reason about the behavior you are seeing.

You can also supply a second argument to Debug.Log() and when you click the message, it will highlight the object in scene, such as Debug.Log("Problem!",this);

If your problem would benefit from in-scene or in-game visualization, Debug.DrawRay() or Debug.DrawLine() can help you visualize things like rays (used in raycasting) or distances.

You can also call Debug.Break() to pause the Editor when certain interesting pieces of code run, and then study the scene manually, looking for all the parts, where they are, what scripts are on them, etc.

You can also call GameObject.CreatePrimitive() to emplace debug-marker-ish objects in the scene at runtime.

You could also just display various important quantities in UI Text elements to watch them change as you play the game.

Visit Google for how to see console output from builds. If you are running a mobile device you can also view the console output. Google for how on your particular mobile target, such as this answer for iOS: https://discussions.unity.com/t/700551 or this answer for Android: https://discussions.unity.com/t/699654

If you are working in VR, it might be useful to make your on onscreen log output, or integrate one from the asset store, so you can see what is happening as you operate your software.

Another useful approach is to temporarily strip out everything besides what is necessary to prove your issue. This can simplify and isolate compounding effects of other items in your scene or prefab.

If your problem is with OnCollision-type functions, print the name of what is passed in!

Here’s an example of putting in a laser-focused Debug.Log() and how that can save you a TON of time wallowing around speculating what might be going wrong:

https://discussions.unity.com/t/839300/3

“When in doubt, print it out!™” - Kurt Dekker (and many others)

Note: the print() function is an alias for Debug.Log() provided by the MonoBehaviour class.

The character controller would not trigger any collision or trigger messages. Only a rigidbody can do this. The CharacterController has it’s own callback OnControllerColliderHit since the CC does not use the physics engine, at least not the rigidbody physics. The CC just uses the colliders to calculate collisions.

If you want your character controller to activate trigger messages, you have to attach a kinematic rigidbody to your CC. From the physics system’s point of view the character controller is just a static always up-right capsule collider. See this page for more information about collisions and trigger messages. Especially the two tables near the bottom.

Also, if you use a RigidBody component you are expected to only modify the rigidbody’s position/rotation rather than the GameObject’s transform, as the latter is updated by (synchronized with) the rigidbody and thus changes to transform may be either dismissed or lead to odd (physics) behaviour.

It’s the same with the CharacterController component. If you have a CharacterController then only move your player through the CharacterController’s methods.

public class TeleportPlayer : MonoBehaviour
{
    public Transform target;
    void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Player"))
        {
            other.GetComponent<CharacterController>().enabled=false;
            other.transform.position = target.position;
            other.GetComponent<CharacterController>().enabled=true;
            Debug.Log("Teleported");
        }
    }
}

Thank you all for your answers, though I eventually found a way to do this in another way, before, I wanted to make everything in one scene, but then I realised it would be way simpler to use more scenes so now instead of teleporting the player around a new scene loads in.

Actually when you use a kinematic rigidbody, you can actually change the transform as this is the main usage for kinematic rigidbodies. To quote the documentation:

Though note that kinematic rigidbodies can not detect collisions. They can cause trigger events and also “wake up” sleeping non-kinematic rigidbodies so they can detect collisions. Moving static colliders (which you should never do) into a sleeping rigidbody would not wake up the rigidbody and consequently not detect any collision. A kinematic rigidbody would wake up a sleeping rigidbody. Of course moving a kinematic rigidbody into a static (non-trigger) collider or another kinematic rigidbody would not detect any collisions either.

You don’t need any magic, just simple vector subtraction and the Move function, do not disable/enable components and whatnot.

using UnityEngine;

public class TeleportPlayer : MonoBehaviour
{
    public Transform target;

    void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Player"))
        {
            var characterController = other.GetComponent<CharacterController>();
            characterController.Move(target.position - characterController.transform.position);
        }
    }
}

Also, make sure, the target doesn’t have a similar trigger to trigger…

Warning!. This won’t work if there’s something like a wall between the teleporter and the target. Captain Kirk will just end up splatted across the wall.

That’s why you should consult Scotty when it comes to teleportations :slight_smile:

9429014--1321898--53173217-1fce-4a10-8f73-ce624393b03a_text.gif

The character controller will activate a trigger. The fact that you with all your experience don’t realize this just serves to demonstrate how confusing Unity really is. I’m back from a long break from Unity and it took weeks to re familiarize myself with Unity and all of its quirks. And even now I still keep forgetting!!.. :sweat_smile:

IDK, it is clear and simple on the docs page:

I just don’t see what is not understandable and straightforward in this text.

(I mean if people read attentively and see that CC is inheriting from Collider, so CC is nothing more than a special collider which doesn’t need a RigidBody to perform physical movement and to interact with other colliders)

Well, you’re right, I probably remembered it wrong :slight_smile: Yes the CharacterController can indeed issue OnTrigger messages. Though I wouldn’t call that “confusing”. Many systems use and incoperate external systems. The character controller was not an invention by Unity but it came with PhysX.

I haven’t used Unity in a long time and haven’t used the CharacterController for even longer, so my memory is a bit rusty. Some gotchas have always existed and they aren’t gotchas when you are familiar with them. A good example is the for / foreach loop variable when used in a closure. With C#5 they actually made a breaking change so that gotcha is removed for the foreach loop variable, but not the for-loop variable(s). While this change is certainly useful in a lot of situations, it’s just another thing you have to remember because the behaviour is now different for older versions of the language and unless you’re certain about the version you’re using, you can’t really rely on the new behaviour.

Anyways, that means the original code should actually work out of the box. If it doesn’t work I would assume that the object with the character controller is either not tagged “Player”, the script is not attached to the object, or the capsule of the player does not overlap with the trigger collider.

I don’t blame you for remembering it wrong. I imagine everybody remembers it wrong at some stage. I know I did. And I know I will continue to do so. That’s why it’s so confusing. Imagine being new to Unity and you google ‘character controller’ and ‘collision detection’ and you get link after link of people giving mixed messages because they all remembered wrong! :slight_smile:

The character controller and its quirks is destined to always be forgotten.

Only if people are too lazy to RTFM.

Its probably the wrong way to do it but disabling the character controller, moving it to the new position, and then re-enabling it seemed to do the trick for me at least. :+1:
Kind regards

It’s the correct way to do it.