Maintaining speed after teleportation [c#]

In my game i have portals that the player can walk through and i want him to maintain his speed like if he falls. How do i do that?

script:

public GameObject otherPortal;
void OnTriggerEnter(Collider other) {
		Debug.Log ("something hit the portal");
		other.transform.position = otherPortal.transform.position + otherPortal.transform.forward * 1;
		other.transform.rotation = otherPortal.transform.rotation;
	}

Okay, so, I’m about 90% sure this will work… And I don’t really have a chance to test it at the moment, but here goes:

// Version 1: A rewrite to maintain relative facing without snapping to an exit angle from the destination

// This should give the relative rotation of the destination portal to the current one
Quaternion relativeRotation = Quaternion.Inverse(transform.rotation) * otherPortal.transform.rotation;
other.transform.rotation *= relativeRotation;
// Whatever way velocity is being maintained, I'm simplifying it here
// This should rotate the velocity vector in the same manner as the character is rotated
other.velocity = relativeRotation * other.velocity;

or, alternatively,

// Version 2: Snap to exit destination angle

// Get relative rotation from object entering portal rather than each end of the portal
Quaternion relativeRotation = Quaternion.Inverse(other.transform.rotation) * otherPortal.transform.rotation;
other.velocity = relativeRotation * other.velocity;

Again, I’m not 100% certain I have all the math organized properly. Non-commutative math always seems to love giving me thoroughly confusing results.

Additionally, if the same object type is being used for portal entrances and exits and a different orientation is needed for the exit, it may be necessary to create an offset rotation in order to correct the exit, especially for two-way portals.

// Ideally, replace 90 degrees with a variable and replace the Vector's direction as needed
Quaternion offset = Quaternion.AngleAxis(90.0f, Vector3.up);

I would go about it in the following way;

Have a rigidbody component attached to the player. Then you can access the player’s velocity vector.

On entering portal one, save that vector.

Transfer the player to the position of the other portal and change the velocity vector of the ridigbody to be the velocity vector from before but pointing in the new direction, depending on how the other portal is orientated.

How exactly to do that I will leave to those better versed in code, but I can do the mathematics for you!

This is an example portal script I did a few years ago, from the BergZergArcade.net tutorials. you can see how it takes the rigidbody velocity when the the portal ‘sends’ and then uses it when it moves the object to the recieving portal. Now, this was just something I threw together from the tutorial, it probably has some bugs to work out, and may not be perfect. It’s just a code example of what we mean by getting the velocity.

using UnityEngine;
using System.Collections;

public class Portal : MonoBehaviour {

    public Portal Destination;

    public bool Transporting = false;
	// Use this for initialization
	void Start () {
	}

    private bool IsActive
    {
        get
        {
            return (Destination != null);
        }
    }

    private void Send(Collider other)
    {
        Transporting = true;
        Destination.Transporting = true;
        Rigidbody rb = other.gameObject.GetComponent<Rigidbody>();
        if (other.transform.CompareTag("Player"))
        {
            Destination.Recieve(other.gameObject, rb);
        }
    }

    private void Recieve(GameObject go, Rigidbody cc)
    {
        go.transform.position = transform.position;
        go.transform.rotation = new Quaternion(0, transform.rotation.y, 0, transform.rotation.w);
        cc.AddForce(cc.velocity);
    }

    public void OnTriggerEnter(Collider other)
    {
        if (!IsActive || Transporting) return; // either we have no desination, or we are the destination and somebody is coming.  Either way, no collision counts
        Send(other);
    }

    public void OnTriggerExit(Collider other)
    {
        Transporting = false;
    }
}

Firstly, to anyone reading this wondering how I know @EitanCreate 's code so well - that’s because I answered his other question here and he then asked me to answer this one.


So first of all you need to make a new script called TrackVelocity and put this code in there:

using UnityEngine;
using System.Collections;

public class TrackVelocity : MonoBehaviour {

    private Rigidbody rgBody;
    private Vector3 velocity = Vector3.zero;

    public Vector3 Velocity { get { return velocity; } }

	void Start()
    {
        rgBody = gameObject.GetComponent<Rigidbody>();
        if (rgBody == null)
            rgBody = gameObject.AddComponent<Rigidbody>();
	}
	
	void LateUpdate()
    {
        velocity = rgBody.velocity;
	}
}

Then you need to go to your StepThroughPortal script and add this code to the bottom of the Interact() function:

TrackVelocity velocityScript = obj.GetComponent<TrackVelocity>();
        if (velocityScript != null)
            obj.GetComponent<Rigidbody>().velocity = Quaternion.FromToRotation(transform.forward, -otherPortal.transform.forward) * velocityScript.Velocity;

Then just make sure that every object that you want/need to be able to go through the portal has the TrackVelocity script attached. As long as it has that script then it’ll keep it’s velocity after teleporting - but if an object without that script goes through it shouldn’t break anything either, it just won’t remember it’s velocity.

Note: After they go through, they will keep their velocity but will start spinning a bit from the impact. I hope this doesn’t affect your gameplay - but if it does then I might be able to fix it.

@dhore Hi! i found a bug in the TrackVelocity script and hoped you could help me:
when the player goes through one portal to the other his velocity becomes 0 again.
I have an idea of what the problem could be: should the player be kinematic?
if not then when he’s not he sinks into the ground… lol.
thanks in advance.