Smooth scrolling on mobile devices

Appsurd

Member
Smooth scrolling on mobile devices


GM version: GMStudio 2.3.2
Target platform: ALL
Download: https://marketplace.yoyogames.com/assets/5091/smooth-scrolling-example
Links: N/A
Latest change: 2021-08-25
Level: Medium



Summary

This mini tutorial will explain how you can enable smooth scrolling on a mobile device. This is particularly useful in a large menu or for large pieces of text. The tutorial will first explain its functionality and thereafter the scripts are shown. In case you’re just interested to see/use the code, please head for the Marketplace to download it! Of course you can also copy-and-paste the scripts from this tutorial from chapter 2.

Table of contents

Introduction
Chapter 1: The concept
Chapter 2: The scripts and the variables
Conclusion
Changelog

Introduction

Many games have a starting menu at the very beginning of your game. Most menus are very small, but, as your game grows larger or you have an extensive shop or so, a scrollable menu is really nice. Especially when your menu is large (e.g. more than three times the width/height of the screen) a smooth scrollable menu really beautifies your game. In this tutorial I will discuss a set of scripts for creating a scrollable menu.

This tutorial and all its assets are completely free, there is no need for any credit. We do appreciate if you rate the script in the Marketplace such that we know what can be improved. Thanks in advance and enjoy the tutorial!

Chapter 1: The concept

In order to use the smooth scrolling system, we will need an object to handle it. Let’s create an object called obj_smoothview to handle it all. We do not need any advanced camera function for this project, because we can use the build-in views. We need to activate view 0 since this view will be used for scrolling. You can activate a view by going to the room editor of your room. In the left panel, under Properties -> Viewports and Cameras, you need to select "Enable viewports". Then you need to go to "Viewport 0" and select "visible". I expect you to know what views are and how they work, but if you don’t, then please have a look at the manual or possibly another tutorial.

Now, scrolling can be done in two directions: horizontally and vertically. So one parameter in the initialize script will handle this. In the tutorial, I will discuss vertical only, but the same process can be applied to the horizontal direction. And don’t worry, the example and the scripts contain both :).

We will also need a variable to handle the current scrolling speed. Let’s call it drag_speed. But the drag speed should decay slowly, such that we have a nice smooth effect. This is more or less called friction (the variable we will use is called smooth).

Those are the variables we will need, so we can start. We will distinguish two types of pressing/touching: the first touch (in code: mouse_check_button_pressed) or the continuous touch (mouse_check_button).

In the first case, we will initialise the movement. We will call drag the position of the start of your mouse and of course, the drag_speed is zero.
GML:
// Initialise the movement by pressing using the left mouse button
if (mouse_check_button_pressed(mb_left))
{
    drag_speed = 0;
    if (drag_horizontally)
        drag = mouse_x;
    else
        drag = mouse_y;
}
Now we will look into the scrolling. Whenever we move, let’s increase the drag_speed. Using the drag_speed, we want to move the view. We can handle this in the following code:

GML:
// Dragging
if (mouse_check_button(mb_left))
{
   drag_speed = (drag - mouse_y) * speed_modifier;
   camera_set_view_pos(view_camera[0], 0, camera_get_view_y(view_camera[0]) + drag_speed);
}
You can see the variable called speed_modifier. This variable is used to set how fast you scroll. In general, you might want to choose 1 (such that you scroll the same as you move your finger) or maybe somewhat smaller if you can only scroll for a small distance (for example if your room is not so large). The second line changes the position of view 0 to the current position plus the drag_speed.

But we wanted to slowly reduce the speed of the movement, so we get a nice scrolling effect. So let’s implement it. If the drag_speed is larger than zero, we want it to decay slowly. In code, we have the following:

GML:
// Drag slow down effect
if (abs(drag_speed) > 0)
{
   camera_set_view_pos(view_camera[0], 0, camera_get_view_y(view_camera[0]) + drag_speed);
   if (camera_get_view_y(view_camera[0]) <= 0 || camera_get_view_y(view_camera[0]) >= (room_height-camera_get_view_height(view_camera[0]))) then drag_speed = 0;
   drag_speed += (-drag_speed*smooth);
}
You might recognize the variable smooth here, which actually is the friction. The reason I’m not using the variable name friction here is that friction is a build-in variable, so you might already be using it in your project... Generally, choosing the smooth value around 0.1 is convenient for the majority of the cases. Depending on the size of your scrollable room, you might want to adjust it a little.

Notice that we also want to set the speed to zero whenever we get outside the room. Otherwise we would be able to move out without getting stopped at the boundary. However, we should also make sure that we strictly remain inside the room. So we will need another line just below the previous code, which is the following:

GML:
// Keep the screen within the room
camera_set_view_pos(view_camera[0], 0, round(max(0, min(camera_get_view_y(view_camera[0]), room_height - camera_get_view_height(view_camera[0])))));
This actually completes the code for the moving of the view. Now we will examine just a simple checking method to be able to scroll through the menu and while scrolling, not being able to click on the buttons. A very simple checking method is just to check whether the current drag_speed has dropped below a certain value, which we will call limit. In general, a limit value around 2 is convenient but again, you may want to adjust it to your situation.

And that’s it. It’s rather simple but it works quite well. Of course improvements can be made, such as including a timer to improve the clicking procedure. Any suggestions can be posted in the comments below, but please note, I tried to keep it simple, so a very extensive set of codes is not really what I wanted to achieve. Nevertheless I definitely want to see your improvements :).

I made a little example project in which you can see the code in practise. You can download this project from the Marketplace: https://marketplace.yoyogames.com/assets/5091/smooth-scrolling-example .

Chapter 2: The scripts and the variables

All variables used for the smooth scrolling are summarised in Figure 1.



Figure 1: All variables for smooth view scrolling.​

For the people who would like to see the scripts used, here they are! Of course they can also be download from the Marketplace.

GML:
/// @function smoothview_init(drag_horizontally, speed_modifier, smoothness, limit)
/// @param {boolean} drag_horizontally        Horizontal (1) or Vertical (0)
/// @param {real}     speedmodifier        Speed of the view while swiping (default: 0.33)
/// @param {real}     smoothness            Friction causes to slow down (default: 0.08)
/// @param {real}     limit                Limit value used for clicking (default: 2)
///
/// @description    Initialises the smoothview
/// @date            2021-08-25
/// @copyright        Appsurd
function smoothview_init(argument0, argument1, argument2, argument3) {

    // Initialise variables
    drag_speed = 0;
    drag_horizontally = argument0;
    speed_modifier = argument1;
    smooth = argument2;
    limit = argument3;

    // Set drag direction
    if (drag_horizontally)
        drag = mouse_x;
    else
        drag = mouse_y;
}

GML:
/// @function smoothview_step()
///
/// @description    Handles the movement of the view
/// @date            2021-08-25
/// @copyright        Appsurd
function smoothview_step() {

    // Initialise the movement by pressing using the left mouse button
    if (mouse_check_button_pressed(mb_left))
    {
        //Start position for dragging
        drag_speed = 0;
        if (drag_horizontally)
            drag = mouse_x;
        else
            drag = mouse_y;
    }

    // Scrolling horizontally
    if (drag_horizontally)
    {
        //Drag
        if (mouse_check_button(mb_left))
        {
            drag_speed = (drag - mouse_x) * speed_modifier;
            camera_set_view_pos(view_camera[0], camera_get_view_x(view_camera[0]) + drag_speed, 0);
        }
       
        //Drag slow down effect
        if (abs(drag_speed) > 0)
        {
            camera_set_view_pos(view_camera[0], camera_get_view_x(view_camera[0]) + drag_speed, 0);
            if (camera_get_view_x(view_camera[0]) <= 0 || camera_get_view_x(view_camera[0]) >= (room_width-camera_get_view_width(view_camera[0]))) then drag_speed = 0;
            drag_speed += (-drag_speed*smooth);
        }

        // Keep the screen within the room
        camera_set_view_pos(view_camera[0], round(max(0, min(camera_get_view_x(view_camera[0]), room_width - camera_get_view_width(view_camera[0])))), 0);
    }
    else
    {
        // Dragging
        if (mouse_check_button(mb_left))
        {
            drag_speed = (drag - mouse_y) * speed_modifier;
            camera_set_view_pos(view_camera[0], 0, camera_get_view_y(view_camera[0]) + drag_speed);
        }
       
        // Drag slow down effect
        if (abs(drag_speed) > 0)
        {
            camera_set_view_pos(view_camera[0], 0, camera_get_view_y(view_camera[0]) + drag_speed);
            if (camera_get_view_y(view_camera[0]) <= 0 || camera_get_view_y(view_camera[0]) >= (room_height-camera_get_view_height(view_camera[0]))) then drag_speed = 0;
            drag_speed += (-drag_speed*smooth);
        }
       
        // Keep the screen within the room
        camera_set_view_pos(view_camera[0], 0, round(max(0, min(camera_get_view_y(view_camera[0]), room_height - camera_get_view_height(view_camera[0])))));
    }
}

GML:
/// @function smoothview_can_press(drag_speed, limit)
/// @param {real}    drag_speed    The drag speed of the controller object
/// @param {real}    limit        Limit value of pressing
///
/// @description    Checks whether you may click on a moving button
///                    Used to prevent clicking while dragging
/// @date            2021-08-25
/// @copyright        Appsurd
function smoothview_can_press(drag_speed, limit) {

    return (abs(drag_speed) <= limit);
}

Conclusion

The tutorial is finished by now. I hope you have learned how you can apply a smooth scrolling system in your game. If there are any questions or if you find anything unclear, please post your response in the comments below. Thanks for reading this mini tutorial and have fun with your smooth scrolling system!

Changelog
V1.0.0 (2017-02-08)

First English version of the tutorial was written.

V1.0.1 (2018-08-09)

- Small text changes
- Minor improvements in the sample project

V1.1.1 (2021-08-25)

- Update to GMS 2.3+
- Improved variable names
- Improved tutorial explanation
 
Last edited:
E

ethanoh

Guest
Thank you, very useful. In case anyone is wondering, for Game Maker Studio 2, you have to adapt the code for the camera/viewport/view system.

This means adding these lines to the beginning of the Step code:

Code:
view_xview = camera_get_view_x(view_camera[0]);
view_yview = camera_get_view_y(view_camera[0]);
As well as these lines at the end:

Code:
camera_set_view_pos(view_camera[0], view_xview, view_yview);
And don't forget to enable viewports on your room.
 
K

KLaurence

Guest
Thank you for the tutorial! I just wanna ask if you can do it (scroll) in both ways (horizontal and vertical). Thanks!
 

Appsurd

Member
Thank you for the tutorial! I just wanna ask if you can do it (scroll) in both ways (horizontal and vertical). Thanks!
Hi, great you liked the tutorial! Would you mind rating it in the Marketplace? Thanks!
https://marketplace.yoyogames.com/assets/5091/smooth-view-example

As for your question, you can, but it is slightly more difficult. You would need a variable to see in which direction the user is scrolling. By the way, in most cases you need vertical and horizontal scrolling, you don't want scrolling but simply being able to 'drag' the view. For example, when moving over a map. If the last case is applicable to your situation, I would not recommend using this tutorial but implement the dragging yourself instead.
 
V

VintermGames

Guest
Bookmarking this for later use. Scrolling smoothly on mobile apps is SUPER important for making it feel professional. Thank you! :)
 
U

UnknownHello

Guest
Thanks for this tutorial!

I was wondering if someone could help explain this code slightly more:


if (mouse_check_button(mb_left))
{
//Drag
drag_speed = (drag - mouse_x) * speed_modifier;
view_xview += drag_speed;
}

In particular the drag_speed = (drag - mouse_x) * speed_modifier;

This confuses me because as far as I'm aware drag = mouse_x so it's the value of mouse_x - mouse_x, wouldn't this just be 0?

Thanks :)
 

Appsurd

Member
Thanks!
As for your question, the key concept is the mouse left button pressed. Here, you set the 'drag' variable, and the mouse_x /mouse_y of course changes while dragging, i.e. the mouse left button. In this way, you can drag around the room ;)
If you have any further questions, don't hesistate to ask them!
 

Appsurd

Member
@Dirusym The limit variable acts as a threshold: If the current drag_speed is higher than limit, then clicking on a button is impossible (because the game assumes that you are still dragging). If the drag_speed is below the limit, then the dragging speed is almost zero so you are able to click on the button.
 

Dirusym

Member
@Dirusym The limit variable acts as a threshold: If the current drag_speed is higher than limit, then clicking on a button is impossible (because the game assumes that you are still dragging). If the drag_speed is below the limit, then the dragging speed is almost zero so you are able to click on the button.
Thanks ! But i have a problem with my buttons. Because if my dragging is over and my mouse is over a button Game Maker active the "Left mouse released Event" and is switching to another room. How could i repair it in my program ?
 

Appsurd

Member
The tutorial and corresponding demo project are completely revised for GMS 2.3

V1.1.1 (2021-08-25)

- Update to GMS 2.3+
- Improved variable names
- Improved tutorial explanation
 
Top