Today I'm going to tell a bit about implementing "click and drag to scroll" type of effect in GameMaker. This particular thing is useful for strategy games (and normally bound to middle mouse button), applications (where visible area may exceed available window space), and various mobile games and applications (where visible area may be panned by tapping and dragging the finger).

Effect itself looks like this:

Implementation

Implementation is fairly straight-forward:

First, let there be a variable to indicate that view is currently being dragged. This goes into Create event:

dragging = false

Then there'll have to be an event to start the process of dragging view around. That would be either Global Mouse Left Pressed or Global Mouse Middle Pressed :

dragging = true drag_x = mouse_x drag_y = mouse_y

drag_x and drag_y do not do much yet, but these are going to indicate the "starting point" from which view movement begins. I'll explain this in a bit.

Perhaps the most important part about making this work is the "update" code. This goes into any of three Step events:

if ( dragging ) { // actual dragging logic: view_xview = view_xview + drag_x - mouse_x view_yview = view_yview + drag_y - mouse_y }

Here we check if view is being dragged, and if that's so, change it's position accordingly. Formula is simple but confusing - new view position is calculated by adding difference between starting mouse coordinates and current mouse coordinates to current view position. This works because mouse_x and mouse_y already include view coordinates in their value. So actually the formula works like this behind the scences ( _mouse_* implying relative mouse position to view or dragging offset accordingly):

view_xview = drag_xview + drag_mouse_x + view_xview - view_xview - view_mouse_x view_yview = drag_yview + drag_mouse_y + view_yview - view_yview - view_mouse_y

After reducing the self-destructing view_xview - view_xview , formula becomes quite simpler:

view_xview = drag_xview + drag_mouse_x - view_mouse_x view_yview = drag_yview + drag_mouse_y - view_mouse_y

So, essentially, we are pretty much adding difference between old and new mouse positions in the view to original view's position. Swapping signs of mouse coordinates ( + mouse_x - drag_x ) would have granted us effect when scrolling moves view in opposite direction. Which may be handy as well, but in other situations.

Now that most of things are done, there's the last but not least important thing to add - stopping the drag. This goes into Release variant of event that you've added start of process to.

dragging = false

Useful extras

Staying inside

By default, with above script view can be dragged around anywhere, giving player the freedom to leave the room and go exploring the empty nothingness beyond the seen limits.

Fortunately, this is fixable at expense of adding two lines of code into update:

if ( dragging ) { // actual dragging logic: view_xview = view_xview + drag_x - mouse_x view_yview = view_yview + drag_y - mouse_y // make sure view doesn't go outside the room: view_xview = max ( 0 , min ( view_xview , room_width - view_wview ) ) view_yview = max ( 0 , min ( view_yview , room_height - view_hview ) ) }

Monoblock

In preference of some, and for use as a script, all event codes can be joined into one, going into Step event:

// start: if ( mouse_check_button_pressed ( mb_left ) ) { drag_x = mouse_x drag_y = mouse_y } // update: if ( mouse_check_button ( mb_left ) ) { // actual dragging logic: view_xview = drag_x - ( mouse_x - view_xview ) view_yview = drag_y - ( mouse_y - view_yview ) // make sure view doesn't go outside the room: view_xview = max ( 0 , min ( view_xview , room_width - view_wview ) ) view_yview = max ( 0 , min ( view_yview , room_height - view_hview ) ) }

Downloads

For purposes of easier observation, or discovering whether anything was hidden beyond the seen area, you can download an example that was used for illustrations here. Both multi-event and single-event implementations are included:

Download GMK

Related posts: