Skip to content

Instantly share code, notes, and snippets.

@BonIsDead
Last active February 7, 2025 02:36
Show Gist options
  • Save BonIsDead/24cd5e9c4dddebfa8ad0bc51a0f75bc7 to your computer and use it in GitHub Desktop.
Save BonIsDead/24cd5e9c4dddebfa8ad0bc51a0f75bc7 to your computer and use it in GitHub Desktop.

Flick Input for GameMakerStudio 2

I wrote this to allow for reading a joystick's tilt value, and detect whether or not it's been flicked, by how much, and what direction. Very specific use case for sure, but I'm sure someone will find it useful!

Create Event

// Create a new flick input
flick_input = new FlickInput();

Step Event

// Read the flick input
var _flick_info = flick_input.read();

// Check for a successful flick, and launch the player
if _flick_info.successful {
	speed = flick_info.flick_value * 32;
	direction = _flick_info.flick_angle;
}

Draw Event

// Read the flick input
var _flick_info = flick_input.read();

// Draw a line to visualize the current axis information
draw_line(
	x,
	y,
	x + lengthdir_x(_flick_info.axis_value * 32, _flick_info.axis_angle),
	y + lengthdir_y(_flick_info.axis_value * 32, _flick_info.axis_angle)
);

// Draw debug visualization
flick_input.draw_debug(64, 64, 32);

For more information on what FlickInput.read() returns, look inside the script for commented


No need for credit but it doesn't hurt ✌

Bon·is·Bored 2025

function FlickInput() constructor {
// Deadzone used for the joystick
deadzone = 0.24;
// If a flick was detected
detected = false;
// Axis information
axis = {
// Left-stick x-axis value
x: 0,
// Left-stick y-axis value
y: 0,
// Raw value of the left-stick axis
value: 0,
// Angle of the left-stick
angle: 0,
// Difference in value from the current and last frame
difference: 0
};
// Flick information
flick = {
// If a flick was detected
detected: false,
// Flick value
value: 0,
// Flick value on the last frame
value_previous: 0,
// Flick angle
angle: 0,
// Flick angle on the last frame
angle_previous: 0,
};
// Stashed flick information
last_flick = {
// Last successful flick value
value: 0,
// Last successful flick angle
angle: 0
};
/// Reads values from the joystick
/// @param {real} _device Device ID to read input from
/// @return {struct.FlickInfo}
static read = function(_device = 0) {
// Update axis information
axis.x = gamepad_axis_value(_device, gp_axislh);
axis.y = gamepad_axis_value(_device, gp_axislv);
axis.value = clamp(point_distance(0, 0, axis.x, axis.y), 0, 1);
axis.angle = point_direction(0, 0, axis.x, axis.y);
axis.difference = flick.value_previous - axis.value;
// Reset flick value and angle
flick.value = 0;
flick.angle = 0;
// Check if conditions are met to detect a flick
if (not detected) && (axis.difference >= deadzone) {
flick.value = remap(deadzone, 1.0, 0.0, 1.0, flick.value_previous);
flick.angle = flick.angle_previous;
last_flick.value = flick.value;
last_flick.angle = flick.angle;
detected = true;
} else {
// Reset flick detection
detected = false;
}
// Update previous values if axis value is over the deadzone threshold
if (not detected) && (axis.value > deadzone) {
flick.value_previous = axis.value;
flick.angle_previous = axis.angle;
} else {
// Clear previous flick value
flick.value_previous = 0;
}
// Return the flick information
return new FlickInfo(
clamp(remap(deadzone, 1.0, 0.0, 1.0, axis.value), 0, 1), // Remapped axis value with the deadzone
axis.angle,
flick.value,
flick.angle,
detected
);
}
/// Draws a debug view of the controller joystick
/// @param {real} _x X-position
/// @param {real} _y Y-position
/// @param {real} _radius Radius
static draw_debug = function(_x, _y, _radius) {
// The deadzone
draw_set_color(c_red);
draw_circle(_x, _y, _radius * deadzone, true);
// The outmost circle
draw_set_color(c_white);
draw_circle(_x, _y, _radius, true);
draw_set_color(axis.value > deadzone ? c_white : c_red);
// The sticks current position
var _stick_x = _x + lengthdir_x(axis.value * _radius, axis.angle);
var _stick_y = _y + lengthdir_y(axis.value * _radius, axis.angle);
draw_circle(_stick_x, _stick_y, _radius * 0.2, false);
draw_set_color(c_white);
// Last successful flick detected
var _flick_x = _x - lengthdir_x(last_flick.value * _radius, last_flick.angle);
var _flick_y = _y - lengthdir_y(last_flick.value * _radius, last_flick.angle);
draw_arrow(_x, _y, _flick_x, _flick_y, _radius * 0.3);
// Current axis value remapped to the deadzone, and last successful flick value
draw_set_halign(fa_center);
draw_text(_x - 32, _y + _radius, clamp(remap(deadzone, 1.0, 0.0, 1.0, axis.value), 0, 1) );
draw_text(_x + 32, _y + _radius, last_flick.value);
}
}
/// Container for flick information
/// @param {real} _axis_value
/// @param {real} _axis_angle
/// @param {real} _flick_value
/// @param {real} _flick_angle
/// @param {bool} _successful
function FlickInfo(_axis_value, _axis_angle, _flick_value, _flick_angle, _successful) constructor {
// Value of the axis
axis_value = _axis_value;
// Angle of the axis
axis_angle = _axis_angle;
// Value of the flick
flick_value = _flick_value;
// Angle of the flick
flick_angle = _flick_angle;
// Whether the last flick was successful or not
successful = _successful;
}
/// Returns a fraction t, based on a value between a and b
/// @param {real} _a Start value
/// @param {real} _b End value
/// @param {real} _t Fraction
/// @return {real}
function inverse_lerp(_a, _b, _t) {
return (_t - _a) / (_b - _a);
}
/// Returns a value within a given input range into a given output range
/// @param {real} _imin Input minimum
/// @param {real} _imax Input maximum
/// @param {real} _omin Output minimum
/// @param {real} _omax Output maximum
/// @param {real} _value Value to be remapped
/// @return {real}
function remap(_imin, _imax, _omin, _omax, _value) {
var _t = inverse_lerp(_imin, _imax, _value);
return lerp(_omin, _omax, _t);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment