Unity RTS Tutorial Part 1 - Improved mouse control

Share

I didn't intend to start with mouse movement, but while I was testing my game it bothered me how slow the mouse was. While I was thinking about uping the scroll speed I decided to add the ability to hold a button to make the mouse scroll faster.

Updating existing values

To start with I wanted to reposition my camera to be more over head. My main camera now has the following transform values;

Position - x0, y30, z-30
Rotation - x50, y0, z0

I also changed the camera limits and speed as follows by changine the values in "ResourceManager.cs";

        public static float ScrollSpeed { get { return 75; } }
        public static float MinCameraHeight { get { return 5; } }
        public static float MaxCameraHeight { get { return 100; } }

Next I wanted the camera movement to scroll in and out of the map more quickly. This requires us to edit "UserInput.cs". In the "MoveCamera()" method I updated

        movement.y -= ResourceManager.ScrollSpeed * Input.GetAxis("Mouse ScrollWheel");

to be

        movement.y -= ResourceManager.ScrollSpeed * Input.GetAxis("Mouse ScrollWheel")*3.0f;

The "f" on the end of the line is because I have used a float value. I could have just typed "3" instead of "3.0f", but I have left this format so the camera speed can be tweeked later. The float alows for fine control of this value.

I have also updated the code in "WorkManager.cs" for "FindHitPoint()" and " FindHitObject()". I have added limits to the raycast so the ray doesn;t search further than it needs to. First I added the following to "ResourceManager.cs"

        public static float RayCastLimit { get { return 100; } }

Both these methods have an if statement along the lines of;

        if (Physics.Raycast(ray, out hit)) return ...;

Update this to be;

        if (Physics.Raycast(ray, out hit, ResourceManager.RayCastLimit)) return ...;

I also added the following line just above the if statement in one of these methods;

        Debug.DrawRay(ray.origin, ray.direction * ResourceManager.RayCastLimit, Color.yellow);

This draws the ray in the scene so you can see exactly where it is going. It is only for development anbd will be commented out before building. It cannot be seen from the game view because it appears directly under the mouse, but it can be seen in the scene view while the game is running. If you run the game now you will see the ray being drawn and stopping under the ground somewhere. It is worth noting here that the ray will always be drawn to its full length, but the hit object is always the first object the ray find on that path.

Fast Scroll Button

At this point I realised my map was quite large and I do want to be able to use that size at some point. I need to give the player a button to press to scroll the mouse faster. We need a new variable at the top of our class

    public int ScrollMultiplier = 2; //making this public makes it available in the Unity editor

I have set the default value for this so it has a value when the script starts.

Then at the end of the "MoveCamera()" method when we apply our new position, the following line

            Camera.main.transform.position = Vector3.MoveTowards(origin, destination, Time.deltaTime * ResourceManager.ScrollSpeed);

becomes

            if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift) )
            {
                Camera.main.transform.position = Vector3.MoveTowards(origin, destination, Time.deltaTime * ResourceManager.ScrollSpeed * scrollMultiplier);
            }
            else
            {
                Camera.main.transform.position = Vector3.MoveTowards(origin, destination, Time.deltaTime * ResourceManager.ScrollSpeed);
            }

If you run the game now you should be able to hold down the left shift key to speed up the camera scrolling.

Adding Keyboard Scroll

Adding keyboard scroll is relatively simple. We just need to test for a key press and if the key press is detected we add the scroll speed to the camera movement we have already defined before assigning it to the transform. In the  "MoveCamera()" method add the following code to the end of the section defining the horizontal camera movement.

        if (Input.GetKey(KeyCode.LeftArrow))
        {
            movement.x += ResourceManager.ScrollSpeed * -1;
        }
        if (Input.GetKey(KeyCode.RightArrow))
        {
            movement.x += ResourceManager.ScrollSpeed;
        }

And the following code to the end of the section defining vertical movement.

        if (Input.GetKey(KeyCode.UpArrow))
        {
            movement.z += ResourceManager.ScrollSpeed;
        }
        if (Input.GetKey(KeyCode.DownArrow))
        {
            movement.z += ResourceManager.ScrollSpeed * -1;
        }

These can actually go further down the script, but this seems a logical place to put them to me. Run the game now and you should be able to scroll with the keyboard and the mouse.

Scroll Limits

The final thing to add here would be scroll limits at the edge of the map. This will require a few pieces of code. I am also setting the scroll limits by setting the value directly in code. To allow for differing size maps I will need to implement a way to update this when loading the scene. It will also need to be written into the save and load routines.

To start with add the following method to "UserInput.cs";

    public bool IsDesiredPositionOverBoundaries(Vector3 desiredPosition)
    {
        bool overBoundaries = false;

        if ((Camera.main.transform.position.x + desiredPosition.x) < controlLimits.leftLimit)
        {
            overBoundaries = true;
        }
        if ((Camera.main.transform.position.x + desiredPosition.x) > controlLimits.rightLimit)
        {
            overBoundaries = true;
        }
        if ((Camera.main.transform.position.z + desiredPosition.z) > controlLimits.topLimit)
        {
            overBoundaries = true;
        }
        if ((Camera.main.transform.position.z + desiredPosition.z) < controlLimits.bottomLimit)
        {
            overBoundaries = true;
        }
        return overBoundaries;
    }

This will require a few declarations at the top of the class.

    public struct BoxLimit
    {
        public float leftLimit;
        public float rightLimit;
        public float topLimit;
        public float bottomLimit;
    }

    public static BoxLimit controlLimits = new BoxLimit()
    public float leftLimit = -200f;
    public float rightLimit = 200f;
    public float topLimit = 200f;
    public float bottomLimit = -200f;

As well as the following adding to "Start()";

        controlLimits.leftLimit = leftLimit;
        controlLimits.rightLimit = rightLimit;
        controlLimits.topLimit = topLimit;
        controlLimits.bottomLimit = bottomLimit;

I set the default limits to 200, but made them public so they can be overridden from inside the Unity editor. It is worth noting here that if your start point is outside the limits defined here you will not be able to scroll the camera.

Finally, update the section of the "MoveCamera()" method that sets the camera transform to be;

        //if a change in position is detected perform the necessary update
        if (destination != origin)
        { 
            if (!IsDesiredPositionOverBoundaries(destination) )
            {
                if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))
                {
                    Camera.main.transform.position = Vector3.MoveTowards(origin, destination, Time.deltaTime * ResourceManager.ScrollSpeed * scrollMultiplier);
                }
                else
                {
                    Camera.main.transform.position = Vector3.MoveTowards(origin, destination, Time.deltaTime * ResourceManager.ScrollSpeed);
                }

            }
        }

Now run the game and you should be able to move the camera and it will stop at the defined limits.