(mouseover/click to play GIF)Or check here for a non-animated illustration.
This is a post about doing the kind of "click/tap and drag to scroll" effect in GameMaker.
Commonly used across games and software alike.
The code
You'll need a few variables for this:
// in a Create event dragging = false; drag_x = 0; drag_y = 0;
Then, on mouse press/touch, you write down where the mouse was,
// typically in Step if (mouse_check_button_pressed(mb_left)) { dragging = true; drag_x = mouse_x; drag_y = mouse_y; }
and during drag operations you add the difference between the original and current mouse position to the camera coordinates so that the mouse cursor still points at the same spot of the room and the camera adjusts accordingly:
// also typically in Step if (dragging) { if (mouse_check_button(mb_left)) { var camera = view_camera[0]; camera_set_view_pos(camera, camera_get_view_x(camera) + drag_x - mouse_x, camera_get_view_y(camera) + drag_y - mouse_y ); } else { dragging = false; } }
So, for example, if you pressed the mouse at 100,100 and then moved it 10 pixels to the left,
reported mouse_x
would be 90, thus the view would be moved 10 pixels to the right to compensate.
And this will even work when your view is rotated and/or scaled! Pretty neat, isn't it
You can download a test project (for GM LTS and newer) from GitHub.
Limiting the view
If you want the view to stay within room boundaries while doing this,
you can change the camera_set_view_pos
call to something like this:
camera_set_view_pos(camera, clamp( camera_get_view_x(camera) + drag_x - mouse_x, 0, room_width - camera_get_view_width(camera) ), clamp( camera_get_view_y(camera) + drag_y - mouse_y, 0, room_height - camera_get_view_height(camera) ) );
If your view is rotated, this gets a little more complex, depending on how exactly you want to fit it within the boundaries.
For older GM
If you are using GameMaker: Studio or GM8.1, instead of the camera_set_view_pos
call
you would have
view_xview[0] += drag_x - mouse_x; view_yview[0] += drag_y - mouse_y;
And for clamping, you could add
view_xview = clamp(view_xview, 0, room_width - view_wview); view_yview = clamp(view_yview, 0, room_height - view_hview);
after those lines.
You may download the 2013 edition of this example for GM8.
And that's all!
This post was originally published on September 15, 2013 and revised in 2025 for better wording and code examples for modern GameMaker
This might seem really obvious – but remember to check “Enable the use of views” in your room settings (under the Views tab). Without this, your mouse drag will move things too quickly.
Rly thanks :)
You saved me a lot of work and time, really thank you very much =)
how i can make it smooth?
If you mean inertia, I have answered that before.
how would I add an object on screen that i can drag around that also moves with the view when dragging it is done? In the objects step:
if global.drag == true
{
x = mouse_x
y = mouse_y
}
if global.drag == false
{
x = view_xview + x
y = view_yview + y
}
Have any ideas getting this to work?
I’m not entirely sure what you are trying to accomplish – if you want the object to always be fixed at a position, you’d do something like
since doing the way shown would just rapidly accelerate object past screen bounds as soon as view is moved (as you are basically using view coordinates as object speed).
Perhaps readjust xstart\ystart (or make separate variables for this) if you want the object to be on-screen but draggable.
thanks so much for your response. Im basically trying to move an object around the view with the mouse button. But it fails to stay in position within the view once ive finished moving it.
x = view_xview + xpos
y = view_yview + ypos
if global.move_obj == true
{
xpos = mouse_x
ypos = mouse_y
}
ive taken what youve said into mind but am still having some trouble :S
this launches the object off screen the higher the x and y values are.
Is there a way to zoom the view with the mousewheel too at the mouse xy like the room editor?
I plan to make example on that in the future.
Very useful code, thanks friend!! =D
Thanks!
I have no idea why I was updating draw_x and draw_y with new mouse values each step, in my own code. Now it’s working how it’s supposed to :)
Perfect! Very usefull, thanks.
Thank you for this! I couldn’t find it anywhere else. You saved me :D
Wow this is so cool, its spot on, so on point….keep it up bro
Thank you for the helpful tutorial!
quick, well written thorough,
keep on truckin’
Hey, thanks for that.
Is there a way to have the view not snap back to start when mouse button is released? I need to be able to scroll the view, and have it stop, then gain control over the mouse again to move objects around etc.
That does not seem to happen in the example. Do you have built-in view following enabled for some object in your game, perhaps?
Yeah, I have the view following the player, is there a way to disable that temporarily?
Yes, you can set `view_object` to `noone` to stop the built-in following behaviour, and later set it back to `obj_player` (or whatever the name is in your case) to resume it.
Sweet, thanks a lot! I will try that.
In these two lines, is there a reason you are not using the clamp function?
view_xview = max(0, min(view_xview, room_width – view_wview))
view_yview = max(0, min(view_yview, room_height – view_hview))
Like this:
view_xview = clamp(view_xview, 0, room_width – view_wview);
view_yview = clamp(view_yview, 0, room_height – view_yview);
I would think that the single function call simplifies the code a little and possibly runs a little faster, since there is no nested function calls.
clamp only exists in GameMaker: Studio and in later updates of GameMaker 8.1. Since most examples on my blog are intended to work in 8.0, 8.1, and Studio, current approach is used.
In GameMaker 8.0 you can technically also use median instead of clamp, but I’m not sure, whether it’s less, or more confusing, than a min-max pair (which is pretty standard).
On the performance… while a valid point, view dragging code is not really a good place to seek micro-optimizations in, as it is executed once per game step at best.
Hi, I found this article very useful… but i’d like to ask you a new question:
Is there any way to have any inertia scrolling after the mouse is released?
I don’t like the way the view scroll suddenly stops after I release the mouse button…
Thanx in advance
You could store the distance moved per frame, like
and then translate the last known delta into velocity when the mouse is released. Such “velocity” would be implemented as a simple pair of variables that are added to view x/y each step and reduced (“friction”) afterwards.
Thankyou so much for this! Could not find this info anywhere!
For anyone using love2d this is how I added it, with using the camera from here http://nova-fusion.com/2011/04/19/cameras-in-love2d-part-1-the-basics/. Not sure if there is a better way as I’m fairly new to it, but it works… (map.width and map.height are the size of map)
function love.update(dt)
if love.mouse.isDown("l") then
dragging(true, drag_x, drag_y)
end
end
function dragging(mouseDown, drag_x, drag_y)
if mouseDown == true then
--dragging logic
local x, y = camera:mousePosition()
camera._x = camera._x + drag_x - x
camera._y = camera._y + drag_y - y
--boundaries
camera._x = math.max(0, math.min(camera._x, map.width - love.graphics.getWidth()))
camera._y = math.max(0, math.min(camera._y, map.height - love.graphics.getHeight()))
end
end
function love.mousepressed(x, y, button)
if button == 'l' then
drag_x, drag_y = camera:mousePosition()
end
end
function love.mousereleased( x, y, button )
if button == 'l' then
mouseDown = false
end
end
Hi there! I’ve noticed your blog has russian! Is it your own decision (and are YOU RUSSIAN) or just a default thing?
Own decision. You can kind of tell from my About page – “I live in Ukraine […] I speak Ukrainian, Russian, and English freely.”.
And yes, this means many posts are written twice.
Very simple yet useful script, implemented it in my strategy game and gave credit :)