All right, I'm sure this has been done before, but my searching on the Unity forums hasn't been particularly fruitful. I want to make a character move toward a location with a single mouse click. Pathfinding is not necessary, but it needs to be able to react properly to terrain (if the clicked point is on the other side of a hill, it would walk up the hill, and then react to gravity on the way back down). When the character reaches the destination, it stops. The character can use either a CharacterController or a Rigidbody, it doesn't really matter to me which (although there will hopefully be many characters onscreen, so if one is better on performance than the other, that would be good to know) Has this already been built, and if so, can someone provide a link for it?
Two basic things here.. facing your character towards a mouse position, and moving to that position The first subject was covered by another guys thread http://forum.unity3d.com/threads/101900-rotate-object-towards-mouse-position The second would be covered in the CharacterController.Move documentation http://unity3d.com/support/documentation/ScriptReference/CharacterController.Move.html you would need to write a Coroutine, that moves the character until he is within a certain distance of the mouse position you clicked. (say 0.2 units) The key would be to check his position in the X and Z directions, not the Y.
I had started with CharacterController.Move, but since that was built with keyboard input in mind, I didn't know what new value to give moveDirection in the example script. I'll have to check out iTween.
Look at the Penelope tutorial. Yes, it is for mobile, BUT, it has this exact feature, only for where you touch it does a ScreenToWorld raycast, etc.
Well... it sort of works... but it's really choppy. Code (csharp): var speed : float = 6.0; var gravity : float = 20.0; private var hit: RaycastHit; private var moveDirection : Vector3 = Vector3.zero; private var destination : Vector3; function Start() { destination = transform.position; } function Update() { if (Input.GetMouseButtonDown(0)){ // if the left mouse button is clicked var ray = Camera.main.ScreenPointToRay (Input.mousePosition); //cast a ray through the current mouse position from the camera if (Physics.Raycast (ray, hit, 100) hit.collider.gameObject.tag=="Ground") { //if the ray hits the ground Debug.Log (hit.point); destination = hit.point; } } var controller : CharacterController = GetComponent(CharacterController); if (destination != transform.position) { if ((destination-transform.position).sqrMagnitude > 1.0) { //yes, this is a choppy way of getting to the endpoint... I'll fix this later var relativePos = destination - transform.position; relativePos.y = transform.position.y; var rotation = Quaternion.LookRotation(relativePos); transform.rotation = rotation; if (controller.isGrounded) { moveDirection = Vector3.forward; moveDirection = transform.TransformDirection(moveDirection); moveDirection *= speed; } // Apply gravity moveDirection.y -= gravity * Time.deltaTime; // Move the controller controller.Move(moveDirection * Time.deltaTime); } else { transform.position = destination; } } } Ugh... sorry about the tabs being so huge. Copy and paste from MonoDevelop hasn't been my friend.
Tabs are fine. A little more elegant soloution... (coroutine) // make sure to debug it first. Code (csharp): var speed : float = 6.0; var gravity : float = 20.0; private var destination : Vector3; private var iClicked=false; function Start() { destination = transform.position; StartCoroutine(myCoroutine()); } function Update() { if (Input.GetMouseButtonDown(0)){ // if the left mouse button is clicked var hit: RaycastHit; var ray = Camera.main.ScreenPointToRay (Input.mousePosition); //cast a ray through the current mouse position from the camera if (Physics.Raycast (ray, hit, 100)) { //if the ray hits the ground if(hit.collider.gameObject.tag=="Ground"){ destination = hit.point; iClicked=true; } } } } function myCoroutine(){ var controller : CharacterController = GetComponent(CharacterController); while(true){ if(iClicked){ // if we click a mouse, look at the point we clicked transform.LookAt(destination); iClicked=false; } var moveDirection=Vector3.zero; // see if our destination is in front of us var z=transform.InverseTransformPoint(destination).z; if(z>0.2){ // if it is, see if we are on the ground if (controller.isGrounded) { // if we are, move moveDirection = transform.forward; } // Apply gravity moveDirection.y -= gravity * Time.deltaTime; controller.Move(moveDirection * speed * Time.deltaTime); } yield; } }
I'm pretty unfamiliar with Coroutines... how might this error be fixed? It says "No appropriate version of 'UnityEngine.MonoBehaviour.StartCoroutine' for the argument list '(void)' was found."
woops, forgot the yield. In Javascript a function will be defined as an IEnumerator, if you use a yield or yielding method within it's bounds. Since I forgot one, it wasn't thinking it was one. I corrected the code above
Well, it fixed the bug, and I greatly appreciate the help... but I still don't know why the script is producing such a choppy result. EDIT: Hmm... that's odd. When I put it in a new scene, it worked quite well. Perhaps something else I'd done in my old scene was causing it grief. I'll keep you posted.
Hi Screenhog, Any luck identifying the cause of the choppy issue? I'm always on the look out for practices to avoid.