Adventure Game Studio

AGS Development => Engine Development => Topic started by: Crimson Wizard on Wed 05/03/2025 12:47:44

Title: AGS 4: Touch input API
Post by: Crimson Wizard on Wed 05/03/2025 12:47:44
This has been a request for a long while, but somehow we never got to implement touch API in script.
@eri0o has started to research this and made a draft, but it stayed unfinished for some time.

Recently I took his old draft and updated to a working version, ready to be included into the engine.

The PR:
https://github.com/adventuregamestudio/ags/pull/2692
Test build may be downloaded here:
https://cirrus-ci.com/task/5043738189234176


The API is very simple for starters, there are no sophisticated gesture detections, only basic things.

First there's array of TouchPointer objects that let to learn current state of N pointers, where "Pointer" is an abstract "device" that can touch a sensor. Normally this is a finger touching a touch pad or touch screen. Mouse can be emulated through this as well:

Code (ags) Select
managed struct TouchPointer {
  /// Gets this touch pointer's identifier.
  import readonly attribute int ID;
  /// Gets whether this touch pointer is currently down (in touching state).
  import readonly attribute bool IsDown;
  /// Gets this touch pointer's X screen coordinate.
  import readonly attribute int X;
  /// Gets this touch pointer's Y screen coordinate.
  import readonly attribute int Y;
};

builtin struct Touch {
  /// Number of touch pointers registered by the game engine.
  readonly import static attribute int TouchPointerCount;  // $AUTOCOMPLETESTATICONLY$
  /// Accesses a touch pointer state by its identifier.
  readonly import static attribute TouchPointer* TouchPointers[];  // $AUTOCOMPLETESTATICONLY$
};

Besides the pointer states, there are pointer callbacks that you may add to your code:

Code (ags) Select
function on_pointer_down(int pointer, int x, int y);
function on_pointer_up(int pointer, int x, int y);
function on_pointer_move(int pointer, int x, int y);


Here's an example of a game built for Android, which requires 2 fingers to control:
https://www.dropbox.com/scl/fi/6pqtttp2pwzyshqgn9ceg/ags4-touch-test-apk.zip?rlkey=764b7unhlrm9lafv3b4qnuy2f&st=f7h1x5um&dl=0

It features 2 on-screen "pads", one of which works like a joystick and another has 4 "buttons". These may be interacted with 2 fingers simultaneously, and it does not matter which finger you use on what.
(Now when I think about it, it's possible to use more fingers, in which case extra fingers will probably override each others.)
I apologize for the crude gfx and low resolution, i used lazy design and "programmers art".
But I think it serves a proof of concept.

Here's the game project:
https://www.dropbox.com/scl/fi/1ozjmq0yn0qi3103leb3r/ags4-touch-test.zip?rlkey=em6spjqj1z2a9cazpvss9ojq0&st=rn64iyj2&dl=0


The related code looks like this:
Spoiler
Code (ags) Select
int JoystickRelX, JoystickRelY;

void HandleJoystickMotion(TouchPointer *p)
{
    int rel_x;
    int rel_y;
    if (p != null)
    {
        rel_x = p.X - gJoystick.X;
        rel_y = p.Y - gJoystick.Y;
    }
    else
    {
        rel_x = gJoystick.Width / 2;
        rel_y = gJoystick.Height / 2;
    }

    int btn_x = (rel_x - btnStick.Width / 2);
    int btn_y = (rel_y - btnStick.Height / 2);
    if (btn_x < 0) btn_x = 0;
    if (btn_x > gJoystick.Width - btnStick.Width) btn_x = gJoystick.Width - btnStick.Width;
    if (btn_y < 0) btn_y = 0;
    if (btn_y > gJoystick.Height - btnStick.Height) btn_y = gJoystick.Height - btnStick.Height;
    btnStick.X = btn_x;
    btnStick.Y = btn_y;
   
    JoystickRelX = rel_x;
    JoystickRelY = rel_y;
}

void HandlePlayerJoystick()
{
    int dx = JoystickRelX - gJoystick.Width / 2;
    int dy = JoystickRelY - gJoystick.Height / 2;
    float fdx = IntToFloat(dx) / IntToFloat(gJoystick.Width / 2);
    float fdy = IntToFloat(dy) / IntToFloat(gJoystick.Height / 2);
    player.x += FloatToInt(fdx * IntToFloat(player.WalkSpeedX), eRoundNearest);
    player.y += FloatToInt(fdy * IntToFloat(player.WalkSpeedY), eRoundNearest);
    if (player.x < 0) player.x = 0;
    if (player.y < 0) player.y = 0;
    if (player.x > Room.Width) player.x = Room.Width;
    if (player.y > Room.Height) player.y = Room.Height;
}

void HandlePadMotion(TouchPointer *p)
{
}

void HandlePadDown(TouchPointer *p)
{
    int rel_x = p.X - gPad.X;
    int rel_y = p.Y - gPad.Y;
   
    if (rel_x < gPad.Width / 2)
    {
        if (rel_y < gPad.Height / 2)
        {
            player.SayBackground("BLUE");
        }
        else
        {
            player.SayBackground("GREEN");
        }
    }
    else
    {
        if (rel_y < gPad.Height / 2)
        {
            player.SayBackground("RED");
        }
        else
        {
            player.SayBackground("YELLOW");
        }
    }
}

// called on every game cycle, except when the game is blocked
function repeatedly_execute()
{
    HandleJoystickMotion(null); // reset
    for (int i = 0; i < Touch.TouchPointerCount; i++)
    {
        TouchPointer* p = Touch.TouchPointers[i];
        if (p.IsDown)
        {
            if (p.X >= gJoystick.X && p.X <= gJoystick.X + gJoystick.Width &&
                p.Y >= gJoystick.Y && p.Y <= gJoystick.Y + gJoystick.Height)
            {
                HandleJoystickMotion(p);
            }
            else if (p.X >= gPad.X && p.X <= gPad.X + gPad.Width &&
                p.Y >= gPad.Y && p.Y <= gPad.Y + gPad.Height)
            {
                HandlePadMotion(p);
            }
        }
    }

    HandlePlayerJoystick();
}

function on_pointer_down(int pointer, int x, int y)
{
    if (x >= gPad.X && x <= gPad.X + gPad.Width &&
        y >= gPad.Y && y <= gPad.Y + gPad.Height)
    {
        HandlePadDown(Touch.TouchPointers[pointer]);
    }
}
[close]
Title: Re: AGS 4: Touch input API
Post by: Mehrdad on Sat 29/03/2025 12:40:45
Quote from: Crimson Wizard on Wed 05/03/2025 12:47:44Here's the game project:

It's great work. Nice job. So we can make more different genres like platformer on mobiles 8-0
Maybe it's out of this topic but I have some suggestions. (Maybe it's ready and I don't know)

1) For point & click adventure games we needed to "release mouse" instead of "left click". Because we want to search the room for find objects and hotspots by touching them without moving the player to the point.

2)Add  D-Pad instead of a joystick too (Up, Down, Left, Right) and combine

3) Combine two touches for an action like running
Title: Re: AGS 4: Touch input API
Post by: Crimson Wizard on Sat 29/03/2025 13:26:49
Quote from: Mehrdad on Sat 29/03/2025 12:40:451) For point & click adventure games we needed to "release mouse" instead of "left click". Because we want to search the room for find objects and hotspots by touching them without moving the player to the point.

2)Add  D-Pad instead of a joystick too (Up, Down, Left, Right) and combine

3) Combine two touches for an action like running

I'm sorry because I may be misunderstanding, are you proposing to change the demo game, or add something to the touch api?

Touch API has separate "pointer down" and "pointer_up" events, so it's possible to do something when the finger is pressed, and when it is released.
It in theory lets you to track as many fingers as the device supports, up to 10 (I think).

Or were you suggesting similar events for the mouse too?
Title: Re: AGS 4: Touch input API
Post by: Mehrdad on Sat 29/03/2025 14:16:13
Quote from: Crimson Wizard on Sat 29/03/2025 13:26:49Touch API has separate "pointer down" and "pointer_up" events, so it's possible to do something when the finger is pressed, and when it is released.

OK. It's the same "mouse release" think so and I'm sorry that I don't know your complete API

Quote from: Crimson Wizard on Sat 29/03/2025 13:26:49are you proposing to change the demo game, or add something to the touch api?

My mean was add more examples to this demo. Like holding two fingers at the same time to run fast or shoot a bullet, etc.
 
 
Title: Re: AGS 4: Touch input API
Post by: Crimson Wizard on Sun 30/03/2025 06:42:30
Quote from: Mehrdad on Sat 29/03/2025 14:16:13OK. It's the same "mouse release" think so and I'm sorry that I don't know your complete API

The existing touch API is listed in the first post here.

Quote from: Mehrdad on Sat 29/03/2025 14:16:13My mean was add more examples to this demo. Like holding two fingers at the same time to run fast or shoot a bullet, etc.

I'd rather prefer users try this out and make their own tests and demonstrations. That will also show if the api is easy to use and understand. If you have questions about how to script something particular then I can answer them here. If we find that something is missing, then we can make additions to API.