I’m making sort of a portal clone. When the player hits one of the portals I have a script that makes the player’s transform.position equal to the other portal’s transform.position. The problem is that if the player had momentum going into one of the portals, that momentum will be lost when it comes out the other. Could I get a script that would make it so that the player will come out (or teleport) with the same momentum it had going in?
You could try getting the player’s rigidbody velocity as it enters the portal and then add it again in the new position.
You’d need to adjust the velocity based on any direction change, though. For example, if the player was walking straight along the Z-axis (0, 0, 1) and you wanted it to appear as though you were walking out of a portal on the same wall, the new velocity would need to be (0, 0, -1) - back in the direction you were coming from.
That’s a very simple solution. I’ve no doubt there would be a million and one problems doing it that way!
Thats another problem though. The player’s rotation is also not relative to the portal it’s coming out of. If the player was facing a certain way going in, it will be facing the same way coming out.
you could get the difference in orientation by doing
Quaternion newRotation = Quaternion.FromToRotation(player.transform.forward, portal.transform.forward);
and use that to adjust both the orientation of the player as well as the velocity
transform.rotation *= newRotation; //turn the player's orientation
rigidbody.velocity = newRotation * velocity; //transform the velocity
Here is my current code:
player.transform.position = otherPortal.transform.position;
Quaternion newRotation = Quaternion.FromToRotation(player.transform.forward, otherPortal.transform.forward);
player.transform.rotation *= newRotation;
rigidbody.velocity = newRotation * velocity;
It still only changes the transform.position and it gives me an error saying "the name ‘velocity’ does not exist in the current context. The script attached to the Portal object, not the player.
I’m just brainstorming here, but it seems to me you should, upon entry, get the orientation and velocity of the object in the portal’s local coordinate system. E.g., use Transform.TransformDirection on the player’s velocity, forward vector, and up vector. Then on the way out, use the inverse methods (e.g. InverseTransformDirection) to convert back into world space, relative to the second portal.
Alright so I found that the problem was in the player movement script. Now the player does have velocity coming out of the portal, but that velocity isn’t relative to the portal. If you enter a portal with downward motion, you will still have that downward motion as you come out. If you enter a portal looking to the left, you will still be looking to the left as you come out.
I’ve not read this thread closely, but theoretically you should just store the speed of the player (length of velocity vector) when you enter a portal, then set the players new velocity as the new portals forward facing vector * speed
@Pantomorphic , if that happens then you’re not following my suggestion.
The downward motion when you enter a portal should get converted to a velocity relative to that portal, and then converted from a portal-relative velocity (with respect to the output portal) back into the proper world velocity when you come out.
@A.Killingbeck , your approach would always have you coming straight out of the portal. That’s not quite how portals are supposed to work; if you jump in at an angle, you should come out at an angle.
What do you mean? A portal isn’t a real thing, how do you know how it works? Or am I missing something?
Not sure why you’re guessing when they did several articles on how they got it to work in the game around its release…
Try looking at Gamasutra’s “Portal Demystified” article
@A.Killingbeck , it sounds to me like the OP is trying to mimic the behavior of the portals in the game Portal. Maintaining your velocity relative to the input and output sides is an important feature of the portals in that game, without which many of the puzzles would be unsolvable.
Oh! I didn’t realise it was already a game. I didn’t even read the part about it being a portal clone in OP’s post. My bad. Ha.
Here is my code:
public GameObject otherPortal;
public GameObject cameraObject;
void OnTriggerEnter(Collider other)
{
if (other.tag == "Player")
{
other.transform.position = otherPortal.transform.position;
cameraObject.transform.rotation = otherPortal.transform.rotation;
}
}
The reason I use a camera object for the rotation is because the player rigid body’s rotation is locked. For some reason the rotation never changes when you walk through a portal, even if I set it to (0,0,0) As it is, I’m not sure how I would implement your code @JoeStrout
OK, well I don’t think I can write the whole thing out of my head, but let’s start with position: you shouldn’t come out the center of the portal, you should come out whatever position within the portal you popped in, so:
Vector3 localPos = transform.InverseTransformPoint(other.transform.position);
other.transform.position = otherPortal.TransformPoint(localPos);
So this takes the world position of the object, and converts into coordinates local to the portal. Then we convert those local coordinates back to world coordinates, relative to the other portal.
Rotation is a little trickier. What you need to do is transform the forward and up vectors, something like:
Vector3 localUp = transform.InverseTransformDirection(cameraObject.transform.up);
Vector3 localForward = transform.InverseTransformDirection(camera.transform.forward);
cameraObject.transform.rotation.SetLookRotation(otherPortal.TransformDirection(localForward),
otherPortal.TransformDirection(localUp));
Hopefully this gets you going in the right direction (har har, see what I did there)!
It still doesn’t work for some reason. The rotation just never changes. I fiddled around and not even setting the camera’s rotation to (0,0,0) works! The player object nor the camera rotate at all. Also, two errors come up. One says “UnityEngine.GameObject does not contain a definition for ‘TransformPoint’” and the other says the same thing but with ‘TransformDirection’ instead.
TransformPoint and TransformDirection are called on transforms, not gameObjects.
What could be the problem with the camera not rotating at all? No matter what I put after ‘cameraObject.transform.rotation =’ it never rotates at all.
Could it be some other script that sets the rotation of the camera on every frame?
Oh that could be the problem. Not sure how to fix it.