Camera moves when mouse on edge of screen.

How to make the camera to move my mouse hit the edge of the screen? (like warcraft camera system)

It’s very simple:

  • Check if the mouse is in one of the borders.
  • Move the camera in the direction of the border.

So, im assuming you want some classes and functions to investigate?

  • Input.mousePosition
  • Screen.width and Screen.height
  • Transform.right and Transform.up

The borders will be at:

  • Left: x = 0
  • Right: x = Screen.width
  • Up: y = Screen.height
  • Down: y = 0

Happy coding!

Omar Rojo

5 Likes

Sure… this script attached to a camera would work on an edge, it’s up to you to create the behavior for the other edges.

// Attach to a camera

var mDelta = 10; // Pixels. The width border at the edge in which the movement work
var mSpeed = 3.0; // Scale. Speed of the movement

private var mRightDirection = Vector3.right; // Direction the camera should move when on the right edge

function Update ()
{
	// Check if on the right edge
	if ( Input.mousePosition.x >= Screen.width - mDelta )
	{
		// Move the camera
		transform.position += mRightDirection * Time.deltaTime * mSpeed;
	}
}

Omar Rojo

1 Like

sorry omar, i tried applying the code to my main camera…but it seems when i move my mouse to the edge when on test play, it wont move as well…

here’s another script im using besides the one u gave me.

 var target : Transform;
var distance = 5.0;
var xSensitivity = 5.0;
var ySensitivity = 5.0;
var xAngle = 0.0;
var yAngle = 0.0;

function LateUpdate ()
{
      // Only if there is a target
   if (target)

      {
        if (Input.GetMouseButton(1) )
      
      // Update x, y angle with the mouse delta
      yAngle -= Input.GetAxis ("Mouse Y") * ySensitivity;
      
      
      if (Input.GetMouseButton(1) )

      
      xAngle += Input.GetAxis ("Mouse X") * xSensitivity;

      yAngle = Mathf.Clamp(yAngle, 0, 90);

      // Initialize the position to be distance units along the z axis
      // away from the target
      transform.position = Vector3.forward * distance + target.position;

      // Initialize the rotation to look at the target
      transform.LookAt (target.position);
      
      // Rotate around the world up axis by the accumulated delta mouse x
      transform.RotateAround (target.position, Vector3.up, xAngle);

      // Rotate around our own right vector by the accumulated delta mouse y
      worldRight = transform.TransformDirection (Vector3.right);
      transform.RotateAround (target.position, worldRight, yAngle);
   }
}

this script only allows me to move my camera when i click on my right mouse button, and so i included the script you gave me as well but i did not put the codings together in a script. I seperated them, but i think its not the cause of seperating them right?

In Omar’s script, he changes the position of the camera with this line:

transform.position += mRightDirection * Time.deltaTime * mSpeed;

However, if the “target” variable of your other script is set to something other than “none”, it will set the position of the camera relative to that target, completely ignoring any changes that Omar’s script made. One of lines that affect the position is this (there are more):

transform.position = Vector3.forward * distance + target.position;

So, to get Omar’s script to work, try switching the other script off for now. (There is a checkmark in the inspector where the script is attached to the camera)

You are probably using the other script, because you want some of the behaviour it has. But you can’t have both scripts setting the position to something different and have it work.

oh, its working. How bout any idea that combine that 2 scripts together ?
i want to combine them to make a better camera movements.

Depends on what it precisely is you want the camera to do.
Apparently you do not want the camera’s position to be locked to a specific target. So what behaviour from “script B” is it that you want to combine with Omar’s script?

yes…i would like to combine my script with omar’s script.

Yes, I understood that, but to do what?

Since Omar’s script does something like:
“Set position to X”

and the other script does something like:
“Set position to Y”

they cannot just be “mixed”

Please describe in human terms, how you want the camera to move. It’s been a while since I played Warcraft, so I am not clear on what it is you are trying to achieve.

In my script you can move the camera to whatever position you want by setting the movement vectors correctly, it can even move reverse, or random, or arbitrarily defined directions.

Try using the camera vectors.

private var mRightDirection = transform.right;

Changing Vector3 to transform (if attached to a camera) will give you the axes of the camera in World Space. To get the left direction multiply transform.right by -1.

I did it this way since i don’t know what is the “Right direction” of your camera (cameras can be looking at any angle).

Thanks Omar and Cblarsen!

var mDelta = 10; // Pixels. The width border at the edge in which the movement work
var mSpeed = 3.0; // Scale. Speed of the movement

var xSensitivity = 5.0;
var ySensitivity = 5.0;
var xAngle = 0.0;
var yAngle = 0.0;


private var mForwardDirection : Vector3; // What direction does our camera start looking at
private var mRightDirection : Vector3; // The inital "right" of the camera
private var mUpDirection : Vector3; // The inital "up" of the camera

function Start()
{
   mForwardDirection = transform.forward;
   mRightDirection = transform.right;
   mUpDirection = transform.up;
}

function LateUpdate ()
{

   // Omars "change position part"
   // Check if on the right edge
   if ( Input.mousePosition.x >= Screen.width - mDelta )
   {
      // Move the camera
      transform.position += mRightDirection * Time.deltaTime * mSpeed;
   }


   if ( Input.mousePosition.x <= 0 + mDelta )
   {
      // Move the camera
      transform.position -= mRightDirection * Time.deltaTime * mSpeed;
   }


   if ( Input.mousePosition.y >= Screen.width - mDelta )
   {
      // Move the camera
      transform.position += mUpDirection * Time.deltaTime * mSpeed;
   }

   if ( Input.mousePosition.y <= 0 + mDelta )
   {
      // Move the camera
      transform.position -= mUpDirection * Time.deltaTime * mSpeed;
   }


    // Changing an angle, if mouse button is held   
    if (Input.GetMouseButton(1) )
    {
      // Update x, y angle with the mouse delta
      xAngle += Input.GetAxis ("Mouse X") * xSensitivity;
      yAngle -= Input.GetAxis ("Mouse Y") * ySensitivity;

      xAngle = Mathf.Clamp(xAngle, -45, 45);
      yAngle = Mathf.Clamp(yAngle, 0, 90);
    

      // Initialize the rotation to look in our preferred direction
      transform.rotation = Quaternion.LookRotation( mForwardDirection, mUpDirection);
     
      // Rotate around the current up direction by the accumulated delta mouse x
      transform.RotateAround (transform.position, transform.up, xAngle);

      // Rotate around our own right vector by the accumulated delta mouse y
      transform.RotateAround (transform.position, transform.right, yAngle);
   }
}

When you run the above code, when you rotate the camera you notice that your camera turn in a 45 degree way…how to make it turn straight instead of like slanting view? and also, would like to make it able to look to the sky.

Secondly,when the mouse are moves to the edge, the camera only move to a limit of space, means when u rotate to the right and u put ur left mouse to the edge, it wont follow the direction of where ur looking at and move left, instead it move left by default view.

What im looking for is kinda complicated. When the mouse move to the edge of top of screen…it move forward instead of up ( so i could reach to the end of another area) , when i rotate to another view and mouse on edge to move, it moves following the view that the user is. (so its able to move to another area as well). It’s more like a free form of viewing camera system.

Example i can think of is maybe Command Conquer style of camera view. U look on the terrain, move ur mouse cursor on the edge and it move around, and u can rotate ur camera as well to see the environment.

Thanks
Ernest.

Point 2 is the easiest to fix. Change the “move” section to this:

   if ( Input.mousePosition.x >= Screen.width - mDelta )
   {
      // Move the camera
      transform.position += transform.right * Time.deltaTime * mSpeed;
   }


   if ( Input.mousePosition.x <= 0 + mDelta )
   {
      // Move the camera
      transform.position -= transform.right * Time.deltaTime * mSpeed;
   }


   if ( Input.mousePosition.y >= Screen.width - mDelta )
   {
      // Move the camera
      transform.position += transform.up * Time.deltaTime * mSpeed;
   }

   if ( Input.mousePosition.y <= 0 + mDelta )
   {
      // Move the camera
      transform.position -= transform.up * Time.deltaTime * mSpeed;
   }

About Point 1:
There are probably two things wrong with the rotation

  • We are rotating around the wrong axes.
  • You seem to want to be able to rotate to any direction regardless of where the “ground” might be, or where the camera started out. Is that correct?

If yes, I can make a quick rewrite of the script. It will actually be simpler than what it is doing now.

yes, try making it able to rotate to any direction.

Important - do a “reset” in the inspector, because I changed xSensitivity and ySensitivity a lot, and the script will remember the old values if you don’t change them yourself, or reset them.

If you don’t like the rotation, you can experiment with this line:

      transform.rotation = transform.rotation * 
      	Quaternion.Euler(yAngleChange, 0, xAngleChange);

by changing the order of xAngleChange, 0, and yAngleChange in order to rotate around different axes.

var mDelta = 10; // Pixels. The width border at the edge in which the movement work
var mSpeed = 3.0; // Scale. Speed of the movement
var xSensitivity = 100.0;
var ySensitivity = 100.0;

function LateUpdate ()
{

   // Omars "change position part"
   // Check if on the right edge
   if ( Input.mousePosition.x >= Screen.width - mDelta )
   {
      // Move the camera
      transform.position += transform.right * Time.deltaTime * mSpeed;
   }


   if ( Input.mousePosition.x <= 0 + mDelta )
   {
      // Move the camera
      transform.position -= transform.right * Time.deltaTime * mSpeed;
   }


   if ( Input.mousePosition.y >= Screen.height - mDelta )
   {
      // Move the camera
      transform.position += transform.up * Time.deltaTime * mSpeed;
   }

   if ( Input.mousePosition.y <= 0 + mDelta )
   {
      // Move the camera
      transform.position -= transform.up * Time.deltaTime * mSpeed;
   }


    // Changing an angle, if mouse button is held   
    if (Input.GetMouseButton(1) )
    {
      // Update x, y angle with the mouse delta
      xAngleChange = Input.GetAxis ("Mouse X") * xSensitivity * Time.deltaTime;
      yAngleChange = Input.GetAxis ("Mouse Y") * ySensitivity * Time.deltaTime;

      // Rotate around the current up direction by the delta mouse x
      transform.rotation = transform.rotation * 
      	Quaternion.Euler(yAngleChange, 0, xAngleChange);
   }
}

ok nice, its free form now, but i think i need a little advice on the camera rotation part.

try on this code, then you will know what type of rotation im looking for.

 var target : Transform;
var distance = 5.0;
var xSensitivity = 5.0;
var ySensitivity = 5.0;
var xAngle = 0.0;
var yAngle = 0.0;

function LateUpdate ()
{
      // Only if there is a target
   if (target)

      {
        if (Input.GetMouseButton(1) )
      
      // Update x, y angle with the mouse delta
      yAngle -= Input.GetAxis ("Mouse Y") * ySensitivity;
      
      
      if (Input.GetMouseButton(1) )

      
      xAngle += Input.GetAxis ("Mouse X") * xSensitivity;

      yAngle = Mathf.Clamp(yAngle, 0, 90);

      // Initialize the position to be distance units along the z axis
      // away from the target
      transform.position = Vector3.forward * distance + target.position;

      // Initialize the rotation to look at the target
      transform.LookAt (target.position);
      
      // Rotate around the world up axis by the accumulated delta mouse x
      transform.RotateAround (target.position, Vector3.up, xAngle);

      // Rotate around our own right vector by the accumulated delta mouse y
      worldRight = transform.TransformDirection (Vector3.right);
      transform.RotateAround (target.position, worldRight, yAngle);
   }

the rotation is not what i want,the code you wrote allow the camera to move (( )) instead of << >>. Example use our head as the camera, when i click and drag to right, ur head turns ) this way, for 45 degree for example, so u see things is like slanting. The exact thing i want is, when u click and drag to right, your head turns right,

maybe the code above can explain for me (but it only allow for left,right and down, cant look up). Hope it give you a little idea on what im trying to explain. :slight_smile:

Try changing the last two lines of code to

      transform.rotation = transform.rotation * 
      	Quaternion.Euler(-yAngleChange, xAngleChange, 0);

Great, thanks heaps!

Hijacking Han’s thread with his permission. XD

Currently the code allows rotation with the pivot point within the camera (like a fps view rotation). Is there a way to dynamically set the pivot point of the camera’s rotation to an arbituary point in world space? This is not quite unlike the mouse orbit, but this time there is no target to rotate around.

edit: also as the camera moves its position, the pivot point will move as well but still remain the same position in relative to the camera.

Thanks!
Chris

Interesting idea. I might use that for something myself.

var mDelta = 10; // Pixels. The width border at the edge in which the movement work
var mSpeed = 3.0; // Scale. Speed of the movement
var xSensitivity = 100.0;
var ySensitivity = 100.0;

var initialTarget : Transform;
private var pivotCameraSpace : Vector3 = Vector3.zero;


function Start()
{
	if (initialTarget)
		SetPivotPoint( initialTarget.position );
}

function SetPivotPoint( pivotWorldPos : Vector3 )
{
	// If you do not want the camera to actually look at the pivot point,
	// uncomment the following line
	transform.LookAt( pivotWorldPos, transform.up );
	
	pivotCameraSpace = transform.InverseTransformPoint( pivotWorldPos );
}

function LateUpdate ()
{

   // Omars "change position part"
   // Check if on the right edge
   if ( Input.mousePosition.x >= Screen.width - mDelta )
   {
      // Move the camera
      transform.position += transform.right * Time.deltaTime * mSpeed;
   }


   if ( Input.mousePosition.x <= 0 + mDelta )
   {
      // Move the camera
      transform.position -= transform.right * Time.deltaTime * mSpeed;
   }


   if ( Input.mousePosition.y >= Screen.height - mDelta )
   {
      // Move the camera
      transform.position += transform.up * Time.deltaTime * mSpeed;
   }

   if ( Input.mousePosition.y <= 0 + mDelta )
   {
      // Move the camera
      transform.position -= transform.up * Time.deltaTime * mSpeed;
   }


    // Changing an angle, if mouse button is held   
    if (Input.GetMouseButton(1) )
    {
      // Update x, y angle with the mouse delta
      xAngleChange = Input.GetAxis ("Mouse X") * xSensitivity * Time.deltaTime;
      yAngleChange = Input.GetAxis ("Mouse Y") * ySensitivity * Time.deltaTime;

      // rotate 
      var pivotWorldPos : Vector3 = transform.TransformPoint( pivotCameraSpace );
      
      transform.rotation = transform.rotation * 
      	Quaternion.Euler(-yAngleChange, xAngleChange, 0);
      // Adjust position, if the pivotpoint moved relative to us
      transform.position += pivotWorldPos - transform.TransformPoint( pivotCameraSpace );
   }
}

In Start() i used a transform in order to be able to test the code on something, but you can use whatever position you want.

Also, since you say you want the pivot point to move along with the camera, you want to fix the position of the pivot in camera space, not world space. So that is what I made.

I just recently devised an RTS style camera like this using a very different method. It’s a little convoluted at first glance, but the end result is straightforward and makes the motion very smooth. I don’t have the code or project handy but here’s the general idea…

To detect whether the mouse is on the edge of the screen, I simply have an invisible gui texture that covers everything except the region where I want scrolling to kick in. I use the OnMouseEnter and OnMouseExit functions to switch a variable back and forth between scrolling and not-scrolling. This variable, however, is not a simple 0 or 1 value, but rather a value ranging from 0 to 1. When the mouse exits the gui texture, it quickly adds up to 1 over the course of about a half second. When the mouse re-enters the texture, it quickly decrements back to zero, again over about a half second. I then use this value as a multiplier for whatever movement I apply to the camera. Therefore instead of going from a dead stop to full speed and back again, I get a half second of ease-in and ease-out.

The way I determine the exact direction the camera should travel is by projecting a ray onto an invisible plane the camera is looking down on. I compare the contact point of that ray to the camera’s focal point, determine the normalized vector, and then use that as the camera’s movement vector. So if you’re mouse is on the edge of the screen at a 2-o-clock position, the camera will scroll in that direction (not merely up/down/left/right).

Finally, the camera isn’t actually being controlled directly by any of this, but rather the camera is parented to an empty game object that represents its focal point. The scripts I’ve described translate this EGO around. Having the camera then orbit around its focal point is as simple as applying rotation to that EGO.