Sign in to follow this  
thefollower

Techniques for "Smooth" camera scroll with mouse

Recommended Posts

I have made a scrolling function on my canvas that lets the user click and drag their view point.

Currently it moves with raw mouse movement. But I wanted to know what are common techniques people use to apply a smoother feel to it.

My current function looks like this:

Javascript:

function drag(evt,el){
if(evt.button == 2){
    mousePos = {};
    mousePos.x = evt.offsetX / scale;
    mousePos.y = evt.offsetY / scale;

    function update(e){
    var difx = mousePos.x - (e.offsetX/scale),
        dify = mousePos.y - (e.offsetY/scale);


        camera.x += difx;
        camera.y += dify;
        mousePos.x = e.offsetX / scale;
        mousePos.y = e.offsetY / scale;
} 
  function clear(){
     el.removeEventListener('mousemove', update, false);
     this.removeEventListener('mouseup', clear, false);
  }
    el.addEventListener('mousemove',update,false);
    document.body.addEventListener('mouseup',clear,false); 
   }
}
element.addEventListener('mousedown', function(e) { drag(e,this);}, false);

I have added a jsFiddle of this function working too http://jsfiddle.net/jmnte8cL/

So, what are common simple ways to smooth out the scrolling so it feels a bit less dry that are commonly used in games?

Share this post


Link to post
Share on other sites

I don't know about the implementation in Javascript, but you could do something like have the mouse directly drive a target point and have the current point interpolate towards that target point over time. The rate at which you interpolate towards the target will govern the responsiveness, so a long delay (slow interpolation) will feel smooth but a bit laggy, while a short delay will be twitchier but more direct.

Share this post


Link to post
Share on other sites

Inertia can also help make the movement feel smoother:

 

When releasing the mouse button don't immediately stop moving. Keep moving the canvas with the velocity of the last mouse movement and slowly move the velocity towards zero.

Share this post


Link to post
Share on other sites

You can simply change the move by a velocity vector and add a friction which each update reduce the velocity vector :

float friction = 1.0f - m_friction * elapsed;
m_velocity *= friction;
vector3 velocity = m_velocity * elapsed;
AddTranslation( velocity.x, velocity.y, velocity.z );

Share this post


Link to post
Share on other sites

I'm not fully understanding it. Say i click and move the mouse, currently i measure the "difference" from last movement when the function was called.

 

This difference is there for basically 1px at a time so i simply add that difference to the camera.

 

If i add a loop which increments ve, would it not cause me to have multiple loops running as each time i move the mouse it is starting a new loop to increase the velocity again, causing an exponential increase ?

Share this post


Link to post
Share on other sites

I don't know about the implementation in Javascript, but you could do something like have the mouse directly drive a target point and have the current point interpolate towards that target point over time. The rate at which you interpolate towards the target will govern the responsiveness, so a long delay (slow interpolation) will feel smooth but a bit laggy, while a short delay will be twitchier but more direct.



L. Spiro

Share this post


Link to post
Share on other sites

The method said by L. Spiro and Barry is the friction alike way but it's a timer param and not friction, you go from start to end using a timer.

Using a timer as param you always have the same time to go from start to end.

Edited by Alundra

Share this post


Link to post
Share on other sites

I have a kinda working version here: http://jsfiddle.net/bbb9q2c3/

But i can't get it to accurately hit the target x,y position so currrently I can't exit out of the animation loop.

 

This is what i did :

 

var	difx 	        = mousePos.x - (e.offsetX/scale),
        dify 	        = mousePos.y - (e.offsetY/scale);
       	mousePos.x 	= e.offsetX / scale;
        mousePos.y	= e.offsetY / scale; 
var     targetX         = camera.x + difx;
var     targetY         = camera.y + dify;
    
        
        function smooth(){
            if(camera.x != targetX){
                camera.x  += (difx * lerp);
            }
            if(camera.y != targetY){
                camera.y  += (dify * lerp);
            }
        }
        
	timer = setInterval(smooth,16);

Is there a way I can guarentee it will hit the target co ordinates that i set?

Edited by thefollower

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this