Skip to main content

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;
    }
}



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

Post a Comment

Popular posts from this blog

Prayer Times Calculations: Pure C++ Code

[25-March-2017] Update: For brothers and sisters in Indonesia or any country below the equator, thanks to Reza's comment ,  the code now works correctly. [18-January-2012 Update: I refined the code to make it easier and more elegant to use] [06-July-2011 Update: I found this page http://praytimes.org/calculation#Implementation ] This idea came to me when a friend of mine was asking for an 'offline database' for prayer times. I searched for algorithms to make my own database and almost all search results lead to the same algorithm. And all codes are divided into two categories: a simple but approximate one, and a complicated but precise one. I tried with the complicated one to understand it but it needs more time because of its nested functions and -unfortunately- it is not a priority right now. So I went with the easy one as a start. One thing I noticed is that every person is trying to make the ultimate use of the framework he is working on (mostly dotNet). But co...

[Qt] Custom QListView delegate with word wrap

Using QListView with a custom item layout has been a very popular demand by many developers. The problem with using  a custom delegate was having some basic features like word wrap depending on the allowed list size. Here is a screenshot from a project prototype I've been working on. The text will wrap around to fit in multiple lines depending on text length and list view width. My custom delegate is about using two important methods: QFontMetrics::boundingRect() and QPainter::drawText() . The first method will return the minimum Rect needed to draw the given text using the given origin and font. The second method draws the given text within the given Rect. Note that the flag Qt::TextWordWrap is given to both methods when called. The code is simple: Get system default font. Process the font to suite your needs. In my case: I have a normal font and another bold one for the header. Create a QFontMetrics instance for each font. Use the QFontMetrics instances to cal...

Qt Folder Compression

I needed a compression module that does not depend on anything but Qt, and I mean a module to compress a complete folder with its children. This is because I wanted the compression module to work on any platform supported by Qt with no other dependencies. So I made this modules that only uses only qCompress() & qUncompress() methods plus some logic. It is mainly a recursive algorithm that serializes data into a single file, each with its relative path to the parent folder. And deserializing is just taking binary data, creating needed subfolders, and saving the file. Download: QtFolderCompressor.zip [FolderCompressor.h] #ifndef FOLDERCOMPRESSOR_H #define FOLDERCOMPRESSOR_H #include <QFile> #include <QObject> #include <QDir> class FolderCompressor : public QObject { Q_OBJECT public: explicit FolderCompressor(QObject *parent = 0); //A recursive function that scans all files inside the source folder //and serializes all files in a row of f...