I am looking to create a script that would allow me to “teleport” to the nearest collider along the reticle’s path (center of the screen), with a limit of 200 meters.
I am aware of the basics of “teleporting” a player, but have no idea on how to do this with a path and limit its effects to a distance, I also will have to make sure the player does not end up inside the collider.
I was wondering if anyone else had attempted something like this.
Hello !
This is quite simple but there is multiple ways to do this.
First of all, we need to determine the position where the player will be teleported, if he can. For this one, you should use Raycasting from the Physics class. This class have some parameters that allows you to get rid of many of your questions In your case, with your pointer at the screen center, this code will look like this (C#) :
// Get a ray pointing from your main camera at the center of the screen
Ray worldRay = Camera.main.ScreenPointToRay(new Vector3(Screen.width / 2f, Screen.height / 2f, Camera.main.farClipPlane));
RaycastHit hit;
// Cast the ray to 200m maxi
if (Physics.Raycast(worldRay, out hit, 200))
targetPosition = hit.point;
else
// There's no collider before 200m
Physics.Raycast can have one more argument that specified the layermask. And so, on which items the ray should collide or pass through, as long as they are or not in these Unity layers. This is a bit complicated to use for a new user ^^
Then, you can calculate the real position for your player from targetPosition to be teleported at the right place and not into the collider, substracting the Camera.main.transform.forward * [Player_width] for example.
Or, you could use the CharacterController class of Unity and move your Player considering colliders with the Move function
This is the easiest way I know to do this with Unity functions
If you want some cool transitions or movements, you will have to implements some inertia to your Player movements
Sorry for my english, i’m french. Hope I helped you.
Avalion
So far, I have this.
I can get the location in the form of a Vector3, but am having a little trouble with getting the player.
using UnityEngine;
using System.Collections;
public class Teleport : MonoBehaviour {
public int Magica = 100;
public KeyCode useKey = KeyCode.BackQuote;
public Vector3 targetPosition;
public GameObject Player = this;
void Update ()
{
Ray worldRay = Camera.main.ScreenPointToRay(new Vector3(Screen.width / 2f, Screen.height / 2f, Camera.main.farClipPlane));
RaycastHit hit;
//Debug.DrawLine (worldRay.origin, targetPosition, Color.green);
if (Physics.Raycast (worldRay, out hit, 200))
{
targetPosition = hit.point;
}
else
{
}
if (Input.GetKeyDown (useKey))
{
Player.position = targetPosition;
}
}
}
Never mind, fixed it, stupid syntax mistake.
Now I just need to work out how to minus the player radius/size from the equation, I know how to minus it, just not how to get it.
using UnityEngine;
using System.Collections;
public class Teleport : MonoBehaviour {
public int Magica = 100;
public KeyCode useKey = KeyCode.BackQuote;
public Vector3 targetPosition;
void Update ()
{
Ray worldRay = Camera.main.ScreenPointToRay(new Vector3(Screen.width / 2f, Screen.height / 2f, Camera.main.farClipPlane));
RaycastHit hit;
//Debug.DrawLine (worldRay.origin, targetPosition, Color.green);
if (Physics.Raycast (worldRay, out hit, 200))
{
targetPosition = hit.point;
}
else
{
}
if (Input.GetKeyDown (useKey))
{
this.transform.position = targetPosition;
}
}
}
Just get the Bounds of your Collider
Little tip : targetPosition is a calculated variable it should be private ! it’s cleaner
Then, on your script, the ray cast should be in the if(KeyCode) statement. making raycast every frame will break some FPS. Doing it into the if statement, the ray will be cast only when the key is pressed.
The Player position have to be setted only if the raycast actually hit something.
Finally, to gets your Player radius, you can use “this.collider.bounds.center”
Be carfull to optimize your code. You should merge all your movement gestion scripts into one class and test if elements are not null before using it (as this.collider).
Good luck
@Avalion This was just set to private to test that it was in fact getting the variable.
I am now discounting the collider, but it is not changing a thing at all, doesn’t seem to have changed anything.
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class Teleport : MonoBehaviour {
public int Magica = 100;
//public Text MagicaText;
public KeyCode useKey = KeyCode.BackQuote;
public Vector3 targetPosition;
void Update ()
{
//MagicaText.text = "" + Magica;
if (Input.GetKeyDown (useKey))
{
//if (Magica =>10)
//{
Ray worldRay = Camera.main.ScreenPointToRay(new Vector3(Screen.width / 2f, Screen.height / 2f, Camera.main.farClipPlane));
RaycastHit hit;
//Debug.DrawLine (worldRay.origin, targetPosition, Color.green);
if (Physics.Raycast (worldRay, out hit, 200))
{
targetPosition = hit.point;
}
this.transform.position = targetPosition - this.GetComponent<Collider>().bounds.center;
Magica -= 10;
//}
}
}
}
Sorry I was thinking about something else ! you don’t have to use center but size / 2f. Be warned that size is a Vector3 and you only wants to move the Player on X & Z axis.
This means I would not be able to use this line, or is there another way to do it, I have never had to split a Vector3 into pieces before, and floats cannot be used on Bounds.
Actually just the extents Bounds.extents
Thanks passerbycmc for this precision. I’n not actually using bounds every day
This works for me
using UnityEngine;
using System.Collections;
public class Teleport : MonoBehaviour {
public int Magica = 100;
//public Text MagicaText;
public KeyCode useKey = KeyCode.BackQuote;
public Vector3 targetPosition;
void Update() {
//MagicaText.text = "" + Magica;
if (Input.GetKeyDown(useKey)) {
//if (Magica =>10)
//{
Ray worldRay = Camera.main.ScreenPointToRay(new Vector3(Screen.width / 2f, Screen.height / 2f, Camera.main.farClipPlane));
RaycastHit hit;
//Debug.DrawLine (worldRay.origin, targetPosition, Color.green);
if (Physics.Raycast(worldRay, out hit, 200)) {
Vector3 playerSize = this.collider.bounds.extents;
playerSize.y = 0;
// Substract from the camera angle a distance equal to the extent magnitude (It's possible to add an offset here)
targetPosition = hit.point - playerSize.magnitude * Camera.main.transform.forward;
}
this.transform.position = targetPosition;
Magica -= 10;
}
}
}
But this simple code is not really enough when you move your mainCamera with this…
the simple way to look at the ground will result into a Y position too low (alias too much into the ground) You have to think about it or use the CharacterController.
Thank you, this works for me too.
What exactly do you mean by: