- Home /
Diablo 3 like move to mouse (w/o click) - efficient?
I'm working on a Diablo like, topdown view and want the player to have the option of rotating/moving without having to click anything by using mousePosition. I'm not much of a programmer but I've read some of the Expert answers to similar questions and put together the following C# based on those, and it's working fine. Since there are (frequently) times where I don't really understand the code, my question is: Does this look efficient?
using UnityEngine;
using System.Collections;
public class xLookMoveMouse : MonoBehaviour
{
private Transform thisTransform;
public CharacterController cc; // drag in editor
public float rotSpeed; // set in editor
public float walkSpeed; // set in editor
public float runSpeed; // set in editor
public float distIdle; // set in editor; baseline 14 (~200)
public float distWalk; // set in editor; baseline 22 (~500)
// distRun need not be declared
void Start () {
thisTransform = transform;
}
void FixedUpdate ()
{
// If Left Shift is down none of this occurs; modify to suit
if(!Input.GetKey (KeyCode.LeftShift)) {
// Generate a plane that intersects the transform's position with an upwards normal.
Plane playerPlane = new Plane(Vector3.up, thisTransform.position);
Vector3 mousePos = Input.mousePosition;
// Generate a ray from the cursor position
Ray ray = Camera.main.ScreenPointToRay (mousePos);
// Determine the point where the cursor ray intersects the plane.
// This will be the point that the object must look towards to be looking at the mouse.
// Raycasting to a Plane object only gives us a distance, so we'll have to take the distance,
// then find the point along that ray that meets that distance. This will be the point
// to look at.
float hitdist = 0.0f;
// If the ray is parallel to the plane, Raycast will return false.
if (playerPlane.Raycast (ray, out hitdist))
{
// Get the point along the ray that hits the calculated distance.
Vector3 targetPoint = ray.GetPoint(hitdist);
// Determine the target rotation. This is the rotation if the transform looks at the target point.
Quaternion targetRotation = Quaternion.LookRotation(targetPoint - thisTransform.position);
// Smoothly rotate towards the target point.
transform.rotation = Quaternion.Slerp(thisTransform.rotation, targetRotation, rotSpeed * Time.deltaTime);
Vector3 forward = thisTransform.TransformDirection(Vector3.forward);
// Determine distance from mouse for idle/walk/run
Vector3 mouseDistance=(thisTransform.position - targetPoint);
float mouseSqr = mouseDistance.sqrMagnitude;
if(mouseSqr < distIdle*distIdle) {
// do nothing, play idle animation, etc
}
if(mouseSqr>=(distIdle*distIdle) && mouseSqr < (distWalk*distWalk)){
// play walk animation, etc
cc.SimpleMove(forward * walkSpeed);
}
if(mouseSqr>=(distWalk*distWalk)) {
// play run animation, etc
cc.SimpleMove(forward * runSpeed);
}
}
}
}
}
The main camera is not a child of the player, the default MouseLook scripts have been removed from the player/camera, Camera Field of View is 35 with rot 60,0,0, a RigidBody is assigned to player with rot/pos locked & no gravity, and this script is attached to the main camera:
using UnityEngine;
using System.Collections;
public class xLook : MonoBehaviour {
public Transform playerTransform;
public Vector3 cameraOrientationVector = new Vector3 (0, 130, -72f); // change in editor to suit
private Transform thisTransform;
void Start () {
thisTransform = transform;
}
void LateUpdate () {
thisTransform.position = playerTransform.position + cameraOrientationVector;
}
}
Almost none of this is my work instead it's pulled from other sources (wish I had kept URL as references/credit). I did see many posts asking for help on something like this usually wanting to move via mouse click. However, since I'm not using a mouseclick I am concerned about the performance of all that stuff going on in FixedUpdate.
Added Camera fov/rot info.
Answer by Armored13 · Jan 26, 2014 at 10:53 PM
Efficiency depends a lot on how the code is going to be used, too. In this application you're only going to be calling this script once every so often (fifty times per second) from using FixedUpdate(). The most expensive part of this is probably the raycasting, and it's trivial to add a single raycast each FixedUpdate().
If your platform requires a lot of optimization (if it's for a mobile device) you would probably get the biggest optimization boost by trimming out how often it gets activated. There's more than one way to set a repeating timer, but I'm partial to InvokeRepeating().
Thanks. I've learned a few things since Aug that would help this out a little more too.