It is very simple.
I tryied a lot from different forum topics and Unity Answers, but cannot make it to work. Dunno where I’m missing.
Here’s what I need:
Click on the terrain and make the character move to that point.
I’m using the standard First Person Controller and just repositioned the Main Camera away to fit my needs.
This topic (3rd person click to move; issues following terrain) in Unity Answers is very close to what I want, as I have a terrain.
But when I click, the character (which I guess is not the standard FPS but it is a box with rigidbody) moves to that position, and when it stops, the camera goes crazy.
When following the Click to Move topic, I kept instantiating the ballFab and the character didn’t move at all.
I tryied Vector3.Lerp and transform.Translate.
How can I simply make my character move to where I click on the terrain? This must be so simple that I can’t see at all.
Attach it to the gameobject you want to move to a clicked position. I’ve tried it with a simple cube that has a char controller attached. Issue with this is that it moves the center of the gameobject to the exact point you clicked (i’e it’ll probably half bury your character in the ground). You could alter the hit.point.y bit to make it always end up say 1 unit above the ground (as per the commented out line in the below code). Match that to the height of your character and it may suffice…
var speed = 2;
function Update () {
if (Input.GetButtonDown ("Fire1"))
{
var ray = Camera.main.ScreenPointToRay (Input.mousePosition);
if (Physics.Raycast (ray, hit, 100)) {
move =true;
}
}
Debug.DrawLine (Camera.main.transform.position, hit.point, Color.blue);
Debug.Log(hit.point);
if(move){
var wantedPosition= Vector3(hit.point.x, hit.point.y, hit.point.z);
// var wantedPosition= Vector3(hit.point.x, (hit.point.y + 1), hit.point.z);
transform.LookAt(wantedPosition);
transform.Translate(Vector3.forward * Time.deltaTime * speed);
if(Vector3.Distance(transform.position, wantedPosition) < 0.01){
move = false;
}
}
}
Sounds like something’s up with your camera script. Can you post it? I assume it uses LookAt, so I’m wondering what else is in it that might cause a problem.
One possibility, of course, is that the camera’s position is the same as the character’s position, so it can’t look AT the character since there’s no distance between them.
Thanks for sharing this.
I had to add “var hit : RaycastHit;” outside the Update function because Unity was asking where “hit” came from.
I also changed the Input.GetButtonDown to Input.GetButton, so I just had to keep holding the button to translate the character.
In my game, the camera needs to follow the character, as it’s third person camera-like. With this script that you shared, if the Main Camera remains a child of First Person Controller, the camera gets crazy as soon as I click on the terrain.
However, even with this temporary solution, the movement that I had in mind was something like this, where you just click and the character moves to that potiion. I think they used Vector3.Lerp, but I don’t know how.
I added my scene so you guys can have a better look.
The only difference between the Main Camera that comes with the FPC with the one I’m using is that mine has a script to make 2 Gui.Labels, and the camera is positioned at: Pos x:0, y:18, z:-16,0633 | Rot x:32, y:0, z:0 | Scale x:1, y:1, z:1
The Time.time value is the time since the start of the game, so it will probably not be correct for what you are doing. A good way to go is to store the value of the time at the start of the move and then subtract that from the current time each frame (there’s a class in this thread that handles this neatly for you). Also, you don’t seem to have declared the move variable outside the Update function, although I guess this could be a copy/paste error.
Thank you! The character finally started to move when I declared the missing “move” variable. I had forgotten that
Could you give me any instructions n how to use that Class? I’m a bit confused.
Should I add “Timekeeper.startTime = Time.time;” right in the beginning of the Move boolean block?
I tryied to add “Timekeeper.Reset;” but had no success.
Also, here’s what I have and tryied:
var speed = 2;
var hit : RaycastHit;
var toHere : GameObject;
var move : boolean = false;
function Update ()
{
if (Input.GetButtonDown ("Move"))
{
var ray = Camera.main.ScreenPointToRay (Input.mousePosition);
if (Physics.Raycast (ray, hit, 100))
{
move = true;
Destroy (GameObject.FindWithTag("toHere"));
var instHere = Instantiate (toHere, hit.point, transform.rotation);
}
}
Debug.DrawLine (Camera.main.transform.position, hit.point, Color.blue);
Debug.Log(hit.point);
if(move)
{
Timekeeper.Reset;
var wantedPosition= Vector3(hit.point.x, (hit.point.y + 1), hit.point.z);
transform.LookAt(wantedPosition);
//transform.Translate(Vector3.forward * Time.deltaTime * speed);
//transform.position = Vector3.Lerp(transform.position, wantedPosition, Time.time/200);
transform.position = Vector3.Lerp(transform.position, wantedPosition, Timekeeper.elapsed);
if(Vector3.Distance(transform.position, wantedPosition) < 0.01 || Vector3.Distance(transform.position, wantedPosition) >= 10)
{
move = false;
}
}
}
Firstly, place the Timekeeper.cs script into your Standard Assets folder. Then, in your script, declare an object of type Timekeeper. You can call the Reset function on this object at the point you want to start timing:-
var tk: Timekeeper;
function Start() {
tk = Timekeeper(1);
}
function Update() {
if (move) {
tk.Reset();
}
}
The Timekeeper’s scale variable is useful for controlling animations. Before you start the move, set the scale equal to the length of time you want it to take. You can use the normalized variable to get a value from 0 to 1 which you can pass to Lerp functions, etc:-
if (move) {
tk.scale = 5; // ie, we want the move to take 5 seconds.
tk.Reset();
}
// The "normalized" value indicates how far through the 5 seconds we are.
Vector3.Lerp(startPt, endPt, tk.normalized);
I did this, and added the “transform.position” before the “Vector3.Lerp~”, but the character didn’t move.
My terrain is not flat, there are some high reliefs. So, maybe using Vector3.Lerp to move is not a good idea, since the player would ignore the relief and would fluctuate to a below position… I may use “transform.Translate(Vector3.forward * Time.deltaTime * speed);”, but with this I wouldn’t get the smooth movement which Lerp gets.
if(moving)
{
// Setting the Move to take 5 seconds:
tk.scale = 3;
// Calling the Reset function at this point, to start timing:
tk.Reset();
var wantedPosition= Vector3(hit.point.x, (hit.point.y + 1), hit.point.z);
transform.LookAt(wantedPosition);
// The "normalized" value indicates how far through the 5 seconds we are.
transform.position = Vector3.Lerp(transform.position, wantedPosition, tk.normalized);