Tuesday, April 9, 2013

Camera Drag and Zoom with Mouse in Unity 3D

The script is easy and descriptive, it is the result of some searching and modification.

  • Press the left mouse button and drag to move, and use mouse scroll wheel to zoom in and out.
  • The zooming code can work for both orthogonal and perspective but I've been using and testing it in orthogonal mode. 
  • Modify the public values to fit in your game.

** Just drag the script to your camera and it will work! **

C# code
[CameraDragZoom.cs]
using UnityEngine;
using System.Collections;

public class CameraDragZoom : MonoBehaviour {
    
    public float dragSpeed = -10;
    public int minX = -892;
    public int maxX = 1111;
    public int minZ = -880;
    public int maxZ = 1145;
    
    public int bottomMargin = 80; // if you have some icons at the bottom (like an RPG game) this will help preventing the drag action at the bottom
    
    public float orthZoomStep = 10.0f;
    public int orthZoomMaxSize = 500;
    public int orthZoomMinSize = 300;
    
    private bool orthographicView = true;
    private Vector3 dragOrigin;
    
    // Update is called once per frame
    void Update () {
        moveCamera();
        zoomCamera();
    }
    
    void moveCamera()
    {
        if (Input.GetMouseButtonDown(0))
        {    
            dragOrigin = Input.mousePosition;
            return;
        }

        if (!Input.GetMouseButton(0)) return;
        
        if(dragOrigin.y <= bottomMargin) return;
        
        Vector3 pos = Camera.main.ScreenToViewportPoint(Input.mousePosition - dragOrigin);
        Vector3 move = new Vector3(pos.x * dragSpeed, 0, pos.y * dragSpeed);
                
        if(move.x > 0)
        {
            if(!isWithinRightBorder())
                move.x =0;
        }
        else
        {
            if(!isWithinLeftBorder())
                move.x=0;
        }
        
        if(move.z > 0)
        {
            if(!isWithinTopBorder())
                move.z=0;
        }
        else
        {
            if(!isWithinBottomBorder())
                move.z=0;
        }
            
        
        transform.Translate(move, Space.World);
    }
    
    void zoomCamera()
    {
        if(!isWithinBorders())
            return;
        
        // zoom out
        if (Input.GetAxis("Mouse ScrollWheel") <0)
        {
            if(orthographicView)
            {
                if (Camera.main.orthographicSize <=orthZoomMaxSize)
                    Camera.main.orthographicSize += orthZoomStep;
            }
            else
            {
                if (Camera.main.fieldOfView<=150)
                       Camera.main.fieldOfView +=5;
            }
        }
        // zoom in
        if (Input.GetAxis("Mouse ScrollWheel") > 0)
           {
            if(orthographicView)
            {
                if (Camera.main.orthographicSize >= orthZoomMinSize)
                     Camera.main.orthographicSize -= orthZoomStep;            
            }
            else
            {
                if (Camera.main.fieldOfView>2)
                    Camera.main.fieldOfView -=5;
            }
           }
    }
    
    bool isWithinBorders()
    {
        return ( isWithinLeftBorder() && isWithinBottomBorder() && isWithinRightBorder() && isWithinTopBorder() );
    }
    
    bool isWithinLeftBorder()
    {
        Vector3 currentTopLeftGlobal = Camera.main.ScreenToWorldPoint(new Vector3(0,0,0));
        if(currentTopLeftGlobal.x > minX)
            return true;
        else
            return false;
        
    }
    
    bool isWithinRightBorder()
    {
        Vector3 currentBottomRightGlobal = Camera.main.ScreenToWorldPoint(new Vector3(Screen.width,0,0));
        if(currentBottomRightGlobal.x < maxX)
            return true;
        else
            return false;
    }
    
    bool isWithinTopBorder()
    {
        Vector3 currentTopLeftGlobal = Camera.main.ScreenToWorldPoint(new Vector3(0,Screen.height,0));
        if(currentTopLeftGlobal.z < maxZ)
            return true;
        else
            return false;
    }
    
    bool isWithinBottomBorder()
    {
        Vector3 currentBottomRightGlobal = Camera.main.ScreenToWorldPoint(new Vector3(Screen.width,0,0));
        if(currentBottomRightGlobal.z > minZ)
            return true;
        else
            return false;
    }
}



5 comments:

  1. i am changing the value of the zoom in and out but it doesn't not effect............
    orthomaxzoom and orthominzoom

    thanks for the script

    ReplyDelete
  2. Well, I do not understand the question. But If you mean the zoom is not working, try to make sure that the current zoom (the the start of the game) is between the two values (min and max). Otherwise, it will not zoom in or out.

    ReplyDelete
  3. Nice script. I was curious how difficult it would be to add inertia after dragging so the camera comes to a smooth stop.

    ReplyDelete
    Replies
    1. Thank you.
      About the kinetic scrolling/dragging: I did not try it here, but it was not easy when I was implementing a list view in C++ a few years ago, and I ended up using someone else's library in my view. I think you can reuse any kinetic scrolling algorithm from any project: c, java, python.... The idea is the same: calculate the speed/acceleration of user drag, and use it in the speed-up then the slow-down times. I'm just not that good with math :)

      Delete
  4. I have placed this script on my camera but it does not work properly. It will drag screen to right and zoom out by left mouse but does nothing else. I am working through trying to see if another script is messing with it. Any suggestions or ideas?

    ReplyDelete