GMLscripts.com

Discuss and collaborate on GML scripts
Invert

You are not logged in.

#1 Script Submission » scale_val » 2024-02-15 15:37:16

maras
Replies: 1

A tiny situational script to scale a value from one range to another

Expand/// scale_val(val, in_min, in_max, out_min, out_max) 
//
//  Scale a value from one range to another
//
/// GMLscripts.com/license

function scale_val(val, in_min, in_max, out_min, out_max) {
	
	if (in_min == in_max) return out_min;

	var in_len = in_max - in_min
	var out_len = out_max - out_min;
	
	var val0 = clamp(val, in_min, in_max) - in_min;
	var in_percent = abs(val0 / in_len);
	
	return in_percent * out_len + out_min;
}

Explaination:

Expandscale_val(75, 50, 100, -10, 10) returns: 0
75 is 50% between 50 and 100 therefore 50% between -10 and 10 is 0

scale_val(25, -25, 25, 0, 100) returns: 100
scale_val(-25, -25, 25, 0, 100) returns: 0

#2 Script Submission » pick » 2022-12-28 17:42:06

maras
Replies: 0

A very small script that prevented tons of else-ifs/switches in certain situations

Expand/// pick(val, case1, return1, case2, return2, ...)
//
// returns one of the values or undefined
//
//     val - value to compare with
//     case<x> - compare this to val
//     return<x> - return this if case<x> equals to val
//     
/// GMLscripts.com/license

function pick() {
	var val = argument[0];
	for(var i = 1; i < argument_count; i += 2) if argument[i] == val return argument[i+1];
	return undefined;
}

Example:

Expandenum e_TYPE { A, B, C, D }

type = e_TYPE.C;
var c = pick(type, e_TYPE.A, c_red, e_TYPE.B, c_lime, e_TYPE.C, c_orange, e_TYPE.D, c_aqua);
draw_set_color(c);

#3 Re: Script Submission » Foreach [v3.0.1] » 2022-07-24 03:10:37

gnysek wrote:

Main issue with this script is that it uses macros to make some tricks with GML, and replace things on compiling game. While this is OK for very advanced programmers, I think it's not a style that should be promoted for clean code.

Well it was never really meant to be clean. The main goal was to make it look simple, quick to type and being able to access variables without passing them as arguments first. Dirty macros were the only thing that came to mind

#4 Re: Script Submission » is_int » 2022-04-09 06:02:20

Hmm wouldn't this be a little bit faster?

Expand return floor(number) == number; 

#5 Script Submission » Foreach [v3.0.1] » 2021-12-16 05:58:17

maras
Replies: 3

A foreach loop for arrays, lists, maps, structs, grids, strings and number ranges.
This foreach was made using macros so you don't have to pass variables like arguments. You can access them inside of the loop directly.

Reserved keywords: foreach, foreach_rev, into, exec, as_list, as_grid, as_map, fe, fe_break, fe_continue, fe_return, global._FE_*

Changes

[v3.0.1] Renamed "invar" to "into"

[v3.0.0] A complete refractor
    managed to speed it up by about 40%
    no more warnings
    DATA and VAR had to SWITCH PLACES

Syntax

Expandforeach <data> into <var> exec

reversed loop:

Expandforeach_rev <data> into <var> exec

    <var> - an unused variable name to use
    <data> - any supported data
    Only data that dont use keys as indexes can be reversed

DS datatypes require a specification:

Expandforeach <some_ds_map> as_map into v exec
foreach <some_ds_list> as_list into v exec
foreach <some_ds_grid> as_grid into v exec

The macro variable "fe" contains these variables of the current loop body:

    fe.i - for array, list, grid, number range, string
    fe.key - for map, struct
    fe.xpos, fe.ypos - for grid
    fe.set(val) - for anything but string and number range since those aren't references

To return from a function from within the loop use fe_return(val, [depth=1]);
To break the loop use fe_break;
To continue the loop use fe_continue;

While using fe_return you need to pay attention how "deep" the return is. If fe_return is called in a nested fe loop you have to specify how many fe loops to break using the depth parameter otherwise the stack doesn't get cleared correctly and it will cause unpredictable behaviour. (tbh I wouldn't return from within fe loops at all)

EXAMPLES HERE:
https://github.com/mh-cz/GameMaker-Foreach

Expand/// Foreach 3.0.1
//
// foreach <data> into <var> exec
// 
//     <var> - variable
//     <data> - any supported data
//     
/// GMLscripts.com/license

#region GLOBAL

global._FE_STACK = array_create(10, undefined);
global._FE_CURR_STACK_INDEX = -1;
global._FE = undefined;

#endregion

#region MACROS

#macro fe global._FE
#macro fe_break fe.fn = fe.end_loop; break
#macro fe_continue break
#macro fe_return return _FE_RETURN

#macro as_list ,undefined,ds_type_list
#macro as_map ,undefined,ds_type_map
#macro as_grid ,undefined,ds_type_grid

#macro foreach \
	for(_FE_AUTO_(

#macro foreach_rev \
	for(_FE_AUTO_REV_(

#macro into \
	); fe.fn(); ) for(var 

#macro exec \
	 = fe.get(); true; break)

#endregion

#region RETURN

function _FE_RETURN(val, _depth = 1) {
	repeat(_depth) fe.end_loop();
	return val;
}

#endregion

#region AUTO

function _FE_AUTO_(a1, a2 = undefined, a3 = undefined) {
	
	if a2 == undefined and a3 != undefined switch(a3) {
		case ds_type_list: fe = new _FE_LIST_(a1); break;
		case ds_type_map: fe = new _FE_MAP_(a1); break;
		case ds_type_grid: fe = new _FE_GRID_(a1); break;
		default: throw "Unsupported DS type";
	}
	else if is_array(a1) fe = new _FE_ARRAY_(a1);
	else if is_string(a1) fe = new _FE_STRING_(a1);
	else if is_struct(a1) fe = new _FE_STRUCT_(a1);
	else if is_numeric(a1) {
		if a2 == undefined fe = new _FE_RANGE_(0, a1, 1);
		else if a3 == undefined fe = new _FE_RANGE_(a1, a2, 1)
		else fe = new _FE_RANGE_(a1, a2, a3)
	}
	else throw "Unsupported type";
	
	global._FE_STACK[@ ++global._FE_CURR_STACK_INDEX] = fe;
}

function _FE_AUTO_REV_(a1, a2 = undefined, a3 = undefined) {
	
	if a2 == undefined and a3 != undefined switch(a3) {
		case ds_type_list: fe = new _FE_LIST_REV_(a1); break;
		case ds_type_map: fe = new _FE_MAP_(a1); break;
		case ds_type_grid: fe = new _FE_GRID_REV_(a1); break;
		default: throw "Unsupported DS type";
	}
	else if is_array(a1) fe = new _FE_ARRAY_REV_(a1);
	else if is_string(a1) fe = new _FE_STRING_REV_(a1);
	else if is_struct(a1) fe = new _FE_STRUCT_(a1);
	else if is_numeric(a1) {
		if a2 == undefined fe = new _FE_RANGE_(a1, 0, 1);
		else if a3 == undefined fe = new _FE_RANGE_(a2, a1, 1)
		else fe = new _FE_RANGE_(a2, a1, a3)
	}
	else throw "Unsupported type";
	
	global._FE_STACK[@ ++global._FE_CURR_STACK_INDEX] = fe;
}

#endregion

#region ARRAY

function _FE_ARRAY_() constructor {

	data = argument0;
	len = array_length(data);
	i = -1;

	static set = function(v) {
		data[@ i] = v;
	}

	static next = function() {
		return ++i < len ? true : end_loop();
	}
	
	static get = function() {
		return data[@ i];
	}
	
	static end_loop = function() {
		global._FE = --global._FE_CURR_STACK_INDEX != -1 ? global._FE_STACK[@ global._FE_CURR_STACK_INDEX] : undefined;
		return false;
	}
	
	fn = next;
}

function _FE_ARRAY_REV_() constructor {

	data = argument0;
	len = array_length(data);
	i = len;

	static set = function(v) {
		data[@ i] = v;
	}

	static next = function() {
		return --i > -1 ? true : end_loop();
	}
	
	static get = function() {
		return data[@ i];
	}
	
	static end_loop = function() {
		global._FE = --global._FE_CURR_STACK_INDEX != -1 ? global._FE_STACK[@ global._FE_CURR_STACK_INDEX] : undefined;
		return false;
	}
	
	fn = next;
}

#endregion

#region STRING

function _FE_STRING_() constructor {

	data = argument0;
	len = string_length(data);
	i = -1;

	static set = function(v) {}

	static next = function() {
		return ++i < len ? true : end_loop();
	}
	
	static get = function() {
		return string_char_at(data, i+1);
	}
	
	static end_loop = function() {
		global._FE = --global._FE_CURR_STACK_INDEX != -1 ? global._FE_STACK[@ global._FE_CURR_STACK_INDEX] : undefined;
		return false;
	}
	
	fn = next;
}

function _FE_STRING_REV_() constructor {

	data = argument0;
	len = string_length(data);
	i = len;

	static set = function(v) {}

	static next = function() {
		return --i > -1 ? true : end_loop();
	}
	
	static get = function() {
		return string_char_at(data, i+1);
	}
	
	static end_loop = function() {
		global._FE = --global._FE_CURR_STACK_INDEX != -1 ? global._FE_STACK[@ global._FE_CURR_STACK_INDEX] : undefined;
		return false;
	}
	
	fn = next;
}

#endregion

#region LIST

function _FE_LIST_() constructor {

	data = argument0;
	len = ds_list_size(data);
	i = -1;

	static set = function(v) {
		data[| i] = v;
	}

	static next = function() {
		return ++i < len ? true : end_loop();
	}
	
	static get = function() {
		return data[| i];
	}
	
	static end_loop = function() {
		global._FE = --global._FE_CURR_STACK_INDEX != -1 ? global._FE_STACK[@ global._FE_CURR_STACK_INDEX] : undefined;
		return false;
	}
	
	fn = next;
}

function _FE_LIST_REV_() constructor {

	data = argument0;
	len = ds_list_size(data);
	i = len;

	static set = function(v) {
		data[| i] = v;
	}

	static next = function() {
		return --i > -1 ? true : end_loop();
	}
	
	static get = function() {
		return data[| i];
	}
	
	static end_loop = function() {
		global._FE = --global._FE_CURR_STACK_INDEX != -1 ? global._FE_STACK[@ global._FE_CURR_STACK_INDEX] : undefined;
		return false;
	}
	
	fn = next;
}

#endregion

#region STRUCT

function _FE_STRUCT_() constructor {

	data = argument0;
	key = "";
	keys = variable_struct_get_names(data);
	len = array_length(keys);
	i = -1;

	static set = function(v) {
		data[$ i] = v;
	}

	static next = function() {
		return ++i < len ? true : end_loop();
	}
	
	static get = function() {
		key = keys[@ i];
		return data[$ key];
	}
	
	static end_loop = function() {
		global._FE = --global._FE_CURR_STACK_INDEX != -1 ? global._FE_STACK[@ global._FE_CURR_STACK_INDEX] : undefined;
		return false;
	}
	
	fn = next;
}

#endregion

#region MAP

function _FE_MAP_() constructor {

	data = argument0;
	key = "";
	keys = ds_map_keys_to_array(data);
	len = array_length(keys);
	i = -1;

	static set = function(v) {
		data[? key] = v;
	}

	static next = function() {
		return ++i < len ? true : end_loop();
	}
	
	static get = function() {
		key = keys[@ i];
		return data[? key];
	}
	
	static end_loop = function() {
		global._FE = --global._FE_CURR_STACK_INDEX != -1 ? global._FE_STACK[@ global._FE_CURR_STACK_INDEX] : undefined;
		return false;
	}
	
	fn = next;
}

#endregion

#region GRID

function _FE_GRID_() constructor {

	data = argument0;
	xpos = 0;
	ypos = 0;
	w = ds_grid_width(data);
	h = ds_grid_height(data);
	len = w * h;
	i = -1;

	static set = function(v) {
		data[# xpos, ypos] = v;
	}

	static next = function() {
		return ++i < len ? true : end_loop();
	}
	
	static get = function() {
		xpos = i mod w;
		ypos = i div h;
		return data[# xpos, ypos];
	}
	
	static end_loop = function() {
		global._FE = --global._FE_CURR_STACK_INDEX != -1 ? global._FE_STACK[@ global._FE_CURR_STACK_INDEX] : undefined;
		return false;
	}
	
	fn = next;
}

function _FE_GRID_REV_() constructor {

	data = argument0;
	xpos = 0;
	ypos = 0;
	w = ds_grid_width(data);
	h = ds_grid_height(data);
	len = w * h;
	i = len;

	static set = function(v) {
		data[# xpos, ypos] = v;
	}

	static next = function() {
		return --i > -1 ? true : end_loop();
	}
	
	static get = function() {
		xpos = i mod w;
		ypos = i div h;
		return data[# xpos, ypos];
	}
	
	static end_loop = function() {
		global._FE = --global._FE_CURR_STACK_INDEX != -1 ? global._FE_STACK[@ global._FE_CURR_STACK_INDEX] : undefined;
		return false;
	}
	
	fn = next;
}

#endregion

#region RANGE

function _FE_RANGE_() constructor {

	from = argument0;
	to = argument1;
	step = abs(argument2) * sign(to - from);
	i = from - step;
	
	static set = function(v) {}

	static next = function() {
		i += step;
		return (from < to and i <= to) or (from > to and i >= to) ? true : end_loop();
	}
	
	static get = function() {
		return i;
	}
	
	static end_loop = function() {
		global._FE = --global._FE_CURR_STACK_INDEX != -1 ? global._FE_STACK[@ global._FE_CURR_STACK_INDEX] : undefined;
		return false;
	}
	
	fn = next;
}

#endregion

#6 Script Submission » draw_curve (cardinal spline) » 2021-12-06 12:46:04

maras
Replies: 0

A curve that goes through all points

Expand/// draw_curve(points_list, tension, closed)
//
//	points_list	a list of points, ds_list
//	tension	0 to 1, real
//	closed	bool
//
//	each point is an array of 2 values [x, y] and they can be simply added like this:
//		ds_list_add(points_list, [x, y]);
//	
/// GMLscripts.com/license

function draw_curve(points_list, tension, closed) {
	
	var ps = [];
	var points_len = ds_list_size(points_list);
	
	if points_len < 2 return;
	
	if !closed {
		for(var i = 0; i < points_len + 1; i++) {
			if i == 0 ps[array_length(ps)] = points_list[| i];
			if i < points_len ps[array_length(ps)] = points_list[| i];
			else ps[array_length(ps)] = points_list[| points_len-1];
		}
	}
	else {
		for(var i = 0; i < points_len + 1; i++) {
			if i == 0 ps[array_length(ps)] = points_list[| points_len-1];
			if i < points_len ps[array_length(ps)] = points_list[| i];
			else {
				ps[array_length(ps)] = points_list[| 0];
				ps[array_length(ps)] = points_list[| 1];
			}
		}
	}
	
	for(var i = 1; i < array_length(ps) - 2; i++) {
		
	    var p0 = ps[i - 1];
	    var p1 = ps[i];
	    var p2 = ps[i + 1];
	    var p3 = ps[i + 2];
		
		var m1x = (1 - tension) * (p2[0] - p1[0] + ((p1[0] - p0[0]) / 1 - (p2[0] - p0[0]) * 0.5));
		var m2x = (1 - tension) * (p2[0] - p1[0] + ((p3[0] - p2[0]) / 1 - (p3[0] - p1[0]) * 0.5));
		var m1y = (1 - tension) * (p2[1] - p1[1] + ((p1[1] - p0[1]) / 1 - (p2[1] - p0[1]) * 0.5));
		var m2y = (1 - tension) * (p2[1] - p1[1] + ((p3[1] - p2[1]) / 1 - (p3[1] - p1[1]) * 0.5));
		
	    var ax = 2 * p1[0] - 2 * p2[0] + m1x + m2x;
	    var ay = 2 * p1[1] - 2 * p2[1] + m1y + m2y;
	    var bx = -3 * p1[0] + 3 * p2[0] - 2 * m1x - m2x;
	    var by = -3 * p1[1] + 3 * p2[1] - 2 * m1y - m2y;
	    var cx = m1x;
	    var cy = m1y;
	    var dx = p1[0];
	    var dy = p1[1];
		
		var amount = 25; // number of points in each segment, 25 is fine
		var prevx = dx;
		var prevy = dy;

	    for(var j = 1; j <= amount; j++) {
	        var t = j / amount;
	        var px = ax * t * t * t + bx * t * t + cx * t + dx;
	        var py = ay * t * t * t + by * t * t + cy * t + dy;
			
			draw_line(px, py, prevx, prevy);
			
			prevx = px;
			prevy = py;
	    }
	}
}

FMDteuO.gif

Expandif mouse_check_button_pressed(mb_left) ds_list_add(list, [mouse_x, mouse_y]);

#7 Script Submission » Draw a bent sprite » 2021-09-09 15:36:37

maras
Replies: 2

update 2. 12. 2022
https://github.com/mh-cz/draw_sprite_bent

Small performance boost and added return_pts to return the final transformed coordinates of each segment so you can maybe attach something to it

Expand/// draw_sprite_bent(spr, img_index, x, y, around_x, around_y, bend_angle, segments, xscale = 1, yscale = 1, rot = 0, color = c_white, alpha = 1, return_pts = -1)
//
// returns array of points if return_pts != -1
//
//	spr	sprite index, real
//	img_index	image index, real
//	x	draw it here, real
//	y	draw it here, real
//	around_x	bend the sprite around this x position, real
//	around_y	bend the sprite around this y position, real
//	bend_angle	apply angle, real
//	segments	the more segments, the better quality (but lower performance), real
//	xscale	scale on the x axis, real
//	yscale	scale on the y axis, real
//	rot	rotation of the final drawn texture (does not affect actual bending and around_x/y position), real
//	color	colour
//	alpha	alpha, real
//	return_pts	return array of transformed coords from bottom to top, real 0 to 1 (-1 is off)
//
//  THE IMAGE REQUIRES TO HAVE "Separate texture page" TICKED!
// 
//  return_pts = 0 -> return points on the left side
//  return_pts = 0.5 -> return points in the middle
//  return_pts = 1 -> return points on the right side
//
/// GMLscripts.com/license

global.BEND_SPR_DATA = [];
	
vertex_format_begin();
vertex_format_add_position();
vertex_format_add_colour();
vertex_format_add_texcoord();
global.BEND_SPR_DATA[0] = vertex_format_end(); // vf
global.BEND_SPR_DATA[1] = vertex_create_buffer(); // b

function draw_sprite_bent(spr, img_index, x, y, around_x, around_y, bend_angle, segments, xscale = 1, yscale = 1, rot = 0, color = c_white, alpha = 1, return_pts = -1) {
	
	var spr_w = sprite_get_width(spr);
	var spr_h = sprite_get_height(spr);
	var xoff = sprite_get_xoffset(spr) * xscale;
	var yoff = sprite_get_yoffset(spr) * yscale;
	
	segments = max(4, ceil(segments));
	var step = spr_h / segments;
	var angle_step = bend_angle / segments;
	
	// split the sprite into triangles with UVs
	
	var uv = array_create(2 + ceil((spr_h + 0.1) / step));
	var ci = 0;
	
	uv[ci++] = [1, 0];
	
	var right = false;
	for(var h = 0; h < spr_h + 0.1; h += step) {
		uv[ci++] = [real(right), h/spr_h];
		right = !right;
	}
	uv[ci++] = [real(right), 1];
	
	// rotate the triangles around pivot and save the new coordinates
	
	var counter = 0;
	var angl = 0;
	var uvlen = array_length(uv);
	var coords = array_create(uvlen);
	ci = 0;
	
	var u, v, pivot_x, pivot_y, pdr, pds, xx, yy;
	
	for(var i = uvlen-1; i > -1; i--) {
		
		u = uv[i][0];
		v = uv[i][1];
		
		pivot_x = (around_x - (x - xoff)) / xscale;
		pivot_y = (around_y - (y - yoff)) / yscale;
		
		pdr = point_direction(pivot_x, pivot_y, u * spr_w, v * spr_h);
		pds = point_distance(pivot_x, pivot_y, u * spr_w, v * spr_h);
		xx = pivot_x + lengthdir_x(pds, pdr + angl);
		yy = pivot_y + lengthdir_y(pds, pdr + angl);
		
		coords[ci++] = [ xx * xscale, yy * yscale, (counter == 1), u, v ];
		
		if counter++ == 2 {
			counter = 0;
			if i == 0 break;
			i += 2;
			angl += angle_step;
		}
	}
	
	var vf = global.BEND_SPR_DATA[0];
	var b = global.BEND_SPR_DATA[1];
	
	vertex_begin(b, vf);
	
	var final_pts = return_pts != -1 ? array_create(floor(segments/2)) : [];
	var ptsi = 0;
	var prev_px = undefined;
	var prev_py = undefined;
	var this_px = 0;
	var this_py = 0;
	
	var c_prev, c_next, c_curr;
	
	for(var i = 0; i < ci; i++) {
		
		// connect corners so the image can stretch
		
		c_curr = coords[i];
		
		if i == clamp(i, 2, ci-3) {
			
			c_prev = coords[i-2];
			c_next = coords[i+2];
			
			if c_prev[2] {
				c_curr[0] = c_prev[0];
				c_curr[1] = c_prev[1];
			}
			if c_next[2] {
				c_curr[0] = c_next[0];
				c_curr[1] = c_next[1];
			}
		}
		
		// apply rotation and draw
		
		xx = c_curr[0] - xoff;
		yy = c_curr[1] - yoff;
		
		if rot != 0 {
			pdr = point_direction(0, 0, xx, yy);
			pds = point_distance(0, 0, xx, yy);
			xx = lengthdir_x(pds, pdr + rot);
			yy = lengthdir_y(pds, pdr + rot);
		}
		
		vertex_position(b, x + xx, y + yy);
		vertex_colour(b, color, alpha);
		vertex_texcoord(b, c_curr[3], c_curr[4]);
		
		if return_pts != -1 and i > 0 and i % 6 == 1 {
			
			prev_px = x + coords[i-1][0] - xoff;
			prev_py = y + coords[i-1][1] - yoff;
			this_px = x + xx;
			this_py = y + yy;
			
			var ds = point_distance(this_px, this_py, prev_px, prev_py) * return_pts;
			var dr = point_direction(this_px, this_py, prev_px, prev_py);
    
			final_pts[ptsi++] = [ this_px + lengthdir_x(ds, dr), this_py + lengthdir_y(ds, dr) ];
		}
	}
	
	vertex_end(b);
	vertex_submit(b, pr_trianglelist, sprite_get_texture(spr, img_index));
	
	return final_pts;
}

Make sure to tick "Separate texture page" otherwise it will be glitched

The green dot is around_x and around_y attached to the mouse cursor
Adjusting the bend_angle with mouse wheel
40 segments
ezgif-2-b48a104d230e.gif

#8 Script Submission » InputBox » 2021-08-06 12:32:29

maras
Replies: 0

A simple keyboard input without async events (GMS2)
Works with proportional fonts
You can draw multiple of them at the same time
Doesn't support multi line text

Edit: added input_copy and input_set_text
24. 12. 2021 - fixed an error while while using input_copy that I shou've fixed like 2 months ago sleep

Expand/// input_init()
//
// call this once when the game starts
//
/// GMLscripts.com/license

function input_init() {
	
	global.input_map = ds_map_create();
}

/// input_create(input_id)
// 
// 	input_id	string
// 
// create a new inputbox under this input_id
//
/// GMLscripts.com/license

function input_create(input_id) {
	
	global.input_map[? input_id] = {
		
		str : "",
		placeholder_text : "",
		prev_str : "",
		input_w : 300,
		input_h : 32,
		hold_delay : 0.25,
		spam_delay : 0.02,
		hold_timer : 0,
		spam_timer : 0,
		cursor_flick_speed : 0.4,
		cursor_flick_timer : 0,
		char_spacing : 1,
		cursor_pos : 0,
		cursor_vis : true,
		has_focus : false,
		max_chars : 29,
		clamp_width : true,
		font : -1,
		padding : 4,
		text_color : c_white,
		placeholder_text_color : c_black,
		cursor_color : c_white,
		bkg_color : c_dkgray,
		focused_bkg_color : merge_color(c_dkgray, c_white, 0.15),
		bkg_alpha : 1,
		focused_bkg_alpha : 1,
		focused_text_color : c_white
	};
}

/// input_delete(input_id)
// 
// 	input_id	string
// 
// delete an inputbox under this input_id
//
/// GMLscripts.com/license

function input_delete(input_id) {
	
	global.input_map[? input_id] = 0;
}

/// input_draw(input_id, x, y, gui)
// 
// 	input_id	string
// 	x	inputbox x position, real
// 	y	inputbox y position, real
// 	gui	is this GUI event or not, bool
// 
// call in any draw or draw GUI event
//
/// GMLscripts.com/license

function input_draw(input_id, x, y, gui) {
	
	var s = global.input_map[? input_id];
	
	if is_struct(s) {
	
		var mx = mouse_x;
		var my = mouse_y;

		if gui {
			mx = device_mouse_x_to_gui(0);
			my = device_mouse_y_to_gui(0);
		}

		if device_mouse_check_button_pressed(0, mb_left) {
			s.has_focus = point_in_rectangle(mx, my, x, y, x + s.input_w, y + s.input_h);
		}

		var slen = string_length(s.str);

		if s.has_focus {

			// TYPING
			if keyboard_check(vk_anykey) {
	
				s.str = string_insert(keyboard_string, s.str, s.cursor_pos+1);
			
				if s.prev_str != s.str {
					s.cursor_pos += string_length(keyboard_string);
					s.cursor_flick_timer = 0;
					s.cursor_vis = true;
				}
				s.prev_str = s.str;
		
				slen = string_length(s.str);
			}
	
			keyboard_string = "";
	
			// KEYS

			if keyboard_check_pressed(vk_right)
			or keyboard_check_pressed(vk_left)
			or keyboard_check_pressed(vk_backspace)
			or keyboard_check_pressed(vk_delete)
			or device_mouse_check_button_pressed(0, mb_left) {
	
				s.hold_timer = 0;
				s.spam_timer = s.spam_delay * room_speed + 1;
				s.cursor_flick_timer = 0;
				s.cursor_vis = true;
			}

			// ctrl+v
			if keyboard_check_pressed(ord("V")) and keyboard_check(vk_control) {

				if clipboard_has_text() {
		
					var cb = clipboard_get_text();
					s.str += cb;
					s.cursor_pos += string_length(cb);
					slen = string_length(s.str);
				}
			}
			// backspace key
			if keyboard_check_pressed(vk_backspace) or (keyboard_check(vk_backspace) and s.hold_timer++ > s.hold_delay * room_speed) {
	
				s.cursor_flick_timer = 0;
				s.cursor_vis = true;
	
				if s.spam_timer++ > s.spam_delay * room_speed {
		
					s.spam_timer = 0;
		
					if s.cursor_pos > 0 {
			
						s.str = string_delete(s.str, s.cursor_pos--, 1);
						slen = string_length(s.str);
					}
				}
			}
			// delete key
			if keyboard_check_pressed(vk_delete) or (keyboard_check(vk_delete) and s.hold_timer++ > s.hold_delay * room_speed) {
	
				s.cursor_flick_timer = 0;
				s.cursor_vis = true;
	
				if s.spam_timer++ > s.spam_delay * room_speed {
		
					s.spam_timer = 0;
		
					if s.cursor_pos < slen {
			
						s.str = string_delete(s.str, s.cursor_pos+1, 1);
						slen = string_length(s.str);
					}
				}
			}
			// move cursor right
			if keyboard_check_pressed(vk_right) or (keyboard_check(vk_right) and s.hold_timer++ > s.hold_delay * room_speed) {
	
				s.cursor_flick_timer = 0;
				s.cursor_vis = true;
	
				if s.spam_timer++ > s.spam_delay * room_speed {
		
					s.spam_timer = 0;
					s.cursor_pos++;
				}
			}
			// move cursor left
			if keyboard_check_pressed(vk_left) or (keyboard_check(vk_left) and s.hold_timer++ > s.hold_delay * room_speed) {
	
				s.cursor_flick_timer = 0;
				s.cursor_vis = true;
	
				if s.spam_timer++ > s.spam_delay * room_speed {
		
					s.spam_timer = 0;
					s.cursor_pos--;
				}
			}
		}
		else {
			s.cursor_flick_timer = 0;
			s.cursor_vis = false;
		}
		// text max length clamp
		if string_length(s.str) > s.max_chars s.str = string_copy(s.str, 1, s.max_chars);

		// MOUSE + DRAW

		if s.has_focus {
			draw_set_color(s.focused_bkg_color);
			draw_set_alpha(s.focused_bkg_alpha);
		}
		else {
			draw_set_color(s.bkg_color);
			draw_set_alpha(s.bkg_alpha);
		}

		draw_rectangle(x, y, x + s.input_w, y + s.input_h, false);

		draw_set_alpha(1);
		draw_set_font(s.font);
		draw_set_color(s.placeholder_text_color);

		// placeholder text
		if slen == 0 draw_text(x + s.padding, y + s.padding, s.placeholder_text);

		if s.has_focus {
			draw_set_color(s.focused_text_color);
		}
		else {
			draw_set_color(s.text_color);
		}

		var chrx = s.padding;
		var nearest_dist = 9999999;

		for(var i = 0; i < slen+2; i++) {
			// move cursor to mouse position
			if s.has_focus and device_mouse_check_button_pressed(0, mb_left) {
		
				var check_curs_pos = x + chrx;
				var dist = abs(mx - check_curs_pos);
		
				if dist < nearest_dist {
			
					nearest_dist = dist;
					s.cursor_pos = i-1;
				}
			}
			// draw each character of the text
			if i == clamp(i, 1, slen+1) {
		
				var ch = string_char_at(s.str, i);
				var chw = string_width(ch);
		
				draw_text(x + chrx, y + s.padding, ch)
		
				chrx += chw + s.char_spacing;
		
				if s.clamp_width and i < slen {
			
					if chrx + string_width(string_char_at(s.str, i+1)) + s.padding > s.input_w {
			
						s.str = string_copy(s.str, 1, i);
						s.cursor_pos = i;
						slen = string_length(s.str);
						break;
					}
				}
			}
		}

		// CURSOR STUFF

		s.cursor_pos = clamp(s.cursor_pos, 0, slen);

		if s.cursor_flick_timer++ > s.cursor_flick_speed * room_speed {
	
			s.cursor_flick_timer = 0;
			s.cursor_vis = !s.cursor_vis;
		}

		draw_set_color(s.cursor_color);

		if s.cursor_vis {
	
			var cx = s.padding + string_width(string_copy(s.str, 1, s.cursor_pos)) + s.cursor_pos * s.char_spacing;
			draw_line(
				x + cx,
				y + s.padding - 2,
				x + cx,
				y + s.padding + 2 + string_height("I")
				);
		}
	}
	else show_debug_message("Unknown input ID: " + input_id);
}

/// input_copy(input_id, new_input_id)
// 
// 	input_id	string
// 	new_input_id	string
//
/// GMLscripts.com/license

function input_copy(input_id, new_input_id) {
	
	input_create(new_input_id);
	
	var s1 = global.input_map[? input_id];
	var s2 = global.input_map[? new_input_id];
	
	if is_struct(s1) and is_struct(s2) {
		
		s2.str = s1.str;
		s2.placeholder_text = s1.placeholder_text;
		s2.input_w = s1.input_w;
		s2.input_h = s1.input_h;
		s2.hold_delay = s1.hold_delay;
		s2.spam_delay = s1.spam_delay;
		s2.cursor_flick_speed = s1.cursor_flick_speed;
		s2.char_spacing = s1.char_spacing;
		s2.max_chars = s1.max_chars
		s2.clamp_width = s1.clamp_width
		s2.font = s1.font
		s2.padding = s1.padding
		s2.text_color = s1.text_color
		s2.focused_text_color = s1.focused_text_color
		s2.placeholder_text_color = s1.placeholder_text_color
		s2.cursor_color = s1.cursor_color
		s2.bkg_color = s1.bkg_color
		s2.focused_bkg_color = s1.focused_bkg_color 
		s2.bkg_alpha = s1.bkg_alpha
		s2.focused_bkg_alpha = s1.focused_bkg_alpha
	}
}

/// Functions to control the inputbox properties and look

// return what's inside the inputbox
//	input_id	string
function input_get_text(input_id) {
	var s = global.input_map[? input_id];
	return is_struct(s) ? s.str : "";
}

// set the text inside of the inputbox
//	input_id	string
//	text	string
function input_set_text(input_id, text) {
	var s = global.input_map[? input_id];
	if is_struct(s) s.str = text;
}

// only when the inputbox is focused you can type in
// you can focus it using mouse or using this script
// just make sure to focus only one inputbox
//	input_id	string
//	focus	bool
function input_set_focus(input_id, focus) {
	var s = global.input_map[? input_id];
	if is_struct(s) s.has_focus = focus;
}

// resize the inputbox (this doesn't shrink the text)
//	input_id	string
//	w	real
//	h	real
function input_set_dimensions(input_id, w, h) {
	var s = global.input_map[? input_id];
	if is_struct(s) {
		s.input_w = w;
		s.input_h = h;
	}
}

// max characters limit
// set it to something high like 99999 if you don't want to use it
//	input_id	string
//	max_chars	real
function input_set_max_chars(input_id, max_chars) {
	var s = global.input_map[? input_id];
	if is_struct(s) s.max_chars = max_chars;
}

// if clamp is true you will not be able to write more text if you reach the end of the inputbox
//	input_id	string
//	clamp	bool
function input_set_clamp_text_width(input_id, clamp) {
	var s = global.input_map[? input_id];
	if is_struct(s) s.clamp_width = clamp;
}

// set the placeholder text
// this text will only show up when the inputbox is empty
//	input_id	string
//	text	string
function input_set_placeholder_text(input_id, text) {
	var s = global.input_map[? input_id];
	if is_struct(s) s.placeholder_text = string(text);
}

// font
// -1 is default
//	input_id	string
//	font	font
function input_set_font(input_id, font) {
	var s = global.input_map[? input_id];
	if is_struct(s) s.font = font;
}

// move the text further away from borders
//	input_id	string
//	padding	real
function input_set_text_padding(input_id, padding) {
	var s = global.input_map[? input_id];
	if is_struct(s) s.padding = padding;
}

// text color
//	input_id	string
//	col	colour
function input_set_text_color(input_id, col) {
	var s = global.input_map[? input_id];
	if is_struct(s) s.text_color = col;
}

// focused text color
//	input_id	string
//	col	colour
function input_set_focused_text_color(input_id, col) {
	var s = global.input_map[? input_id];
	if is_struct(s) s.focused_text_color = col;
}

// placeholder text color
//	input_id	string
//	col	colour
function input_set_placeholder_text_color(input_id, col) {
	var s = global.input_map[? input_id];
	if is_struct(s) s.placeholder_text_color = col;
}

// background color
//	input_id	string
//	col	colour
function input_set_bkg_color(input_id, col) {
	var s = global.input_map[? input_id];
	if is_struct(s) s.bkg_color = col;
}

// focused background color
//	input_id	string
//	col	colour
function input_set_focused_bkg_color(input_id, col) {
	var s = global.input_map[? input_id];
	if is_struct(s) s.focused_bkg_color = col;
}

// background alpha
//	input_id	string
//	alpha	real
function input_set_bkg_alpha(input_id, alpha) {
	var s = global.input_map[? input_id];
	if is_struct(s) s.bkg_alpha = alpha;
}

// focused background alpha
//	input_id	string
//	alpha	real
function input_set_focused_bkg_alpha(input_id, alpha) {
	var s = global.input_map[? input_id];
	if is_struct(s) s.focused_bkg_alpha = alpha;
}

// cursor color
//	input_id	string
//	col	colour
function input_set_cursor_color(input_id, col) {
	var s = global.input_map[? input_id];
	if is_struct(s) s.cursor_color = col;
}

// how long you need to hold a key before the cursor starts going on its own (in seconds)
//	input_id	string
//	delay	real
function input_set_cursor_hold_delay(input_id, delay) {
	var s = global.input_map[? input_id];
	if is_struct(s) s.hold_delay = delay;
}

// delay when the cursor is going on its own  (in seconds)
//	input_id	string
//	delay	real
function input_set_cursor_spam_delay(input_id, delay) {
	var s = global.input_map[? input_id];
	if is_struct(s) s.spam_delay = delay;
}

// cursor flickering speed (in seconds)
//	input_id	string
//	spd	real
function input_set_cursor_flick_speed(input_id, spd) {
	var s = global.input_map[? input_id];
	if is_struct(s) s.cursor_flick_speed = spd;
}

// spacing between characters
//	input_id	string
//	space	real
function input_set_char_spacing(input_id, space) {
	var s = global.input_map[? input_id];
	if is_struct(s) s.char_spacing = space;
}

List of all the functions

Expand// INIT
input_init()

// CREATE / DELETE
input_create(input_id)
input_delete(input_id)
input_copy(input_id, new_input_id)

// DRAW
input_draw(input_id, x, y)

// MAIN
input_set_focus(input_id, focus)
input_set_dimensions(input_id, w, h)
input_set_max_chars(input_id, max_chars)
input_set_clamp_text_width(input_id, clamp)
input_set_placeholder_text(input_id, text)

// GET
input_get_text(input_id)

// COLOURS n STUFF
input_set_text(input_id, text)
input_set_font(input_id, font)
input_set_text_padding(input_id, padding)
input_set_text_color(input_id, col)
input_set_focused_text_color(input_id, col)
input_set_placeholder_text_color(input_id, col)
input_set_bkg_color(input_id, col)
input_set_bkg_alpha(input_id, col)
input_set_focused_bkg_color(input_id, col)
input_set_focused_bkg_alpha(input_id, col)
input_set_cursor_color(input_id, padding)

// EXTRA
input_set_cursor_hold_delay(input_id, delay)
input_set_cursor_spam_delay(input_id, delay)
input_set_cursor_flick_speed(input_id, spd)
input_set_char_spacing(input_id, space)

3Pwv8IH.gif

#9 Script Submission » collision_cone » 2021-07-26 12:42:14

maras
Replies: 0

Doesn't work with precision

Expand/// collision_cone(x, y, obj, cone_dir, cone_len, cone_angle, return_arr, force_col_point)
//
// returns array/bool
//
//	x			x from, real
//	y			y from, real
//	obj			object to check, id/object_index
//	cone_dir		facing direction of the cone, real
//	cone_len		length of the sides, real
//	cone_angle		inner cone angle, real
//	return_arr		return all objects inside as an array, otherwise return true/false, bool
//	force_col_point		check x, y coordinates only instead of sprite bboxes, bool
//	
// if the object doesn't have a sprite it checks the x, y coordinates automatically 
//
/// GMLscripts.com/license

function collision_cone(x, y, obj, cone_dir, cone_len, cone_angle, return_arr, force_col_point) {
	
	if !instance_exists(obj) return return_arr ? [] : false;
	var obj_arr = [];
	
	cone_len = max(cone_len, 1);
	cone_angle = clamp(cone_angle, 0.1, 360);
	
	var tri = [];
	var tri_count = 0;
	
	var ab_len = cone_len * 1.425;
	var dir = cone_dir - cone_angle * 0.5;
	
	var next_a = 90;
	var br = false;

	for(var a = 0; a < 360; a += 90) {
		
		if a + next_a >= cone_angle {
			
			next_a = cone_angle - a;
			br = true;
		}
		
		tri[tri_count++] = [
			x + lengthdir_x(ab_len, a + dir),
			y + lengthdir_y(ab_len, a + dir),
			x + lengthdir_x(ab_len, a + dir + next_a),
			y + lengthdir_y(ab_len, a + dir + next_a)
		];
		
		if br break;
	}
	
	// just in case you'd like to see it
	/*draw_circle(x, y, cone_len, true);
	draw_line(x, y, tri[0][0], tri[0][1]);
	draw_line(x, y, tri[tri_count-1][2], tri[tri_count-1][3]);
	draw_set_alpha(0.35);
	draw_arrow(x, y, x+lengthdir_x(cone_len, cone_dir), y+lengthdir_y(cone_len, cone_dir), 20);
	draw_set_alpha(1);*/
	
	with(obj) {
		
		if sprite_index != -1 and !force_col_point {
				
			if rectangle_in_circle(id.bbox_left, id.bbox_top, id.bbox_right, id.bbox_bottom, x, y, cone_len) {
				
				for(var ti = 0; ti < array_length(tri); ti++) {
					
					if rectangle_in_triangle(id.bbox_left, id.bbox_top, id.bbox_right, id.bbox_bottom, 
											 x, y, tri[ti][0], tri[ti][1], tri[ti][2], tri[ti][3]) {
						
						if !return_arr return true;
						else obj_arr[array_length(obj_arr)] = id;
					}
				}
			}
		}
		else {
			
			if point_in_circle(id.x, id.y, x, y, cone_len) {
				
				for(var ti = 0; ti < array_length(tri); ti++) {
					
					if point_in_triangle(id.x, id.y, x, y, tri[ti][0], tri[ti][1], tri[ti][2], tri[ti][3]) {
						
						if !return_arr return true;
						else obj_arr[array_length(obj_arr)] = id;
					}
				}
			}
		}
	}
	
	return return_arr ? obj_arr : false;
}

Works with angles over 180
5IlmU3P.png

#10 Script Submission » random_range_towards » 2021-07-25 09:53:28

maras
Replies: 0

A tiny script but can be handy

also does anyone have a better name for it?

Expand/// random_range_towards(mn, mx, to, f, int)
//
// returns real
//
//	mn	min value, real
//	mx	max value, real
//	to	the result will get closer towards this value, real
//	f	force towards the desired value, real (0-1)
//	int	round the result or not, bool
//
/// GMLscripts.com/license

function random_range_towards(mn, mx, to, f, int) {

	var r = lerp(random_range(mn, mx), to, random(f));
	return int ? round(r) : r;
}

min = 0, max = 100, towards = 10

force = 0
> average: 50

force = 0.5
> average: 42

force = 1
> average: 29

#11 Script Submission » Line x shape collisions » 2021-07-13 15:30:03

maras
Replies: 0

Some line x shape intersections converted to GM

Line and circle

Expand/// line_circle_intersection(x1, y1, x2, y2, cx, cy, rad)
//
// returns bool
//
//	x1	line x from, real
//	y1	line y from, real
//	x2	line x to, real
//	y2	line y to, real
//	cx	circle x, real
//	cy	circle y, real
//	rad	circle radius, real
//
/// GMLscripts.com/license

function line_circle_intersection(x1, y1, x2, y2, cx, cy, rad) {

	var ac1 = cx - x1;
	var ac2 = cy - y1;
	var ab1 = x2 - x1;
	var ab2 = y2 - y1;
	
    var abab = dot_product(ab1, ab2, ab1, ab2);
    var acab = dot_product(ac1, ac2, ab1, ab2);
    var t = clamp(acab/abab, 0, 1);

    var h1 = ab1 * t + x1 - cx;
	var h2 = ab2 * t + y1 - cy;
	
    return dot_product(h1, h2, h1, h2) <= rad * rad
}

Line and rectangle

Expand/// line_rect_intersection(x1, y1, x2, y2, rx1, ry1, rx2, ry2)
//
// returns bool
//
//	x1	line x from, real
//	y1	line y from, real
//	x2	line x to, real
//	y2	line y to, real
//	rx1	rectangle min x, real
//	ry1	rectangle min y, real
//	rx2	rectangle max x, real
//	ry2	rectangle max y, real
//
/// GMLscripts.com/license

function line_rect_intersection(x1, y1, x2, y2, rx1, ry1, rx2, ry2) {

	if point_in_rectangle(x1, y1, rx1+1, ry1+1, rx2-1, ry2-1) return true;
	if point_in_rectangle(x2, y2, rx1+1, ry1+1, rx2-1, ry2-1) return true;

	if ((x1 <= rx1 and x2 <= rx1)
	or (y1 <= ry1 and y2 <= ry1)
	or (x1 >= rx2 and x2 >= rx2)
	or (y1 >= ry2 and y2 >= ry2))
	    return false;

	var m = (y2 - y1) / (x2 - x1);

	var yy = m * (rx1 - x1) + y1;
	if (yy > ry1 and yy < ry2) return true;

	yy = m * (rx2 - x1) + y1;
	if (yy > ry1 and yy < ry2) return true;

	var xx = (ry1 - y1) / m + x1;
	if (xx > rx1 and xx < rx2) return true;

	xx = (ry2 - y1) / m + x1;
	if (xx > rx1 and xx < rx2) return true;

	return false;
}

Line and rotated rectangle (rotates around the middle)

Expand/// line_rot_rect_intersection(x1, y1, x2, y2, rx1, ry1, rx2, ry2, rot)
//
// returns bool
//
//	x1	line x from, real
//	y1	line y from, real
//	x2	line x to, real
//	y2	line y to, real
//	rx1	rectangle min x, real
//	ry1	rectangle min y, real
//	rx2	rectangle max x, real
//	ry2	rectangle max y, real
//	rot	rectangle rotation, real
//
/// GMLscripts.com/license

function line_rot_rect_intersection(x1, y1, x2, y2, rx1, ry1, rx2, ry2, rot) {
	
	var pivot_x = (rx1 + rx2) * 0.5;
	var pivot_y = (ry1 + ry2) * 0.5;
	
	var s = [
		[point_distance(pivot_x, pivot_y, x1, y1), point_direction(pivot_x, pivot_y, x1, y1) - rot],
		[point_distance(pivot_x, pivot_y, x2, y2), point_direction(pivot_x, pivot_y, x2, y2) - rot]
	];
	
	x1 = pivot_x + lengthdir_x(s[0][0], s[0][1]);
	y1 = pivot_y + lengthdir_y(s[0][0], s[0][1]);
	x2 = pivot_x + lengthdir_x(s[1][0], s[1][1]);
	y2 = pivot_y + lengthdir_y(s[1][0], s[1][1]);

	if point_in_rectangle(x1, y1, rx1+1, ry1+1, rx2-1, ry2-1) return true;
	if point_in_rectangle(x2, y2, rx1+1, ry1+1, rx2-1, ry2-1) return true;

	if ((x1 <= rx1 and x2 <= rx1)
	or (y1 <= ry1 and y2 <= ry1)
	or (x1 >= rx2 and x2 >= rx2)
	or (y1 >= ry2 and y2 >= ry2))
	    return false;

	var m = (y2 - y1) / (x2 - x1);

	var yy = m * (rx1 - x1) + y1;
	if (yy > ry1 and yy < ry2) return true;

	yy = m * (rx2 - x1) + y1;
	if (yy > ry1 and yy < ry2) return true;

	var xx = (ry1 - y1) / m + x1;
	if (xx > rx1 and xx < rx2) return true;

	xx = (ry2 - y1) / m + x1;
	if (xx > rx1 and xx < rx2) return true;

	return false;
}

Line and line

Expand/// line_line_intersection(x1, y1, x2, y2, x3, y3, x4, y4)
//
// returns bool
//
//	x1	line 1 x from, real
//	y1	line 1 y from, real
//	x2	line 1 x to, real
//	y2	line 1 y to, real
//	x3	line 2 x from, real
//	y3	line 2 y from, real
//	x4	line 2 x to, real
//	y4	line 2 y to, real
//
/// GMLscripts.com/license

function line_line_intersection(x1, y1, x2, y2, x3, y3, x4, y4) {

    var s1_x = x2 - x1;
    var s1_y = y2 - y1;
    var s2_x = x4 - x3;
    var s2_y = y4 - y3;
	
    var s = (-s1_y * (x1 - x3) + s1_x * (y1 - y3)) / (-s2_x * s1_y + s1_x * s2_y);
    var t = ( s2_x * (y1 - y3) - s2_y * (x1 - x3)) / (-s2_x * s1_y + s1_x * s2_y);
	
    return s >= 0 and s <= 1 and t >= 0 and t <= 1;
}

#13 Re: Script Submission » foreach » 2021-06-20 18:16:46

Found a way to get the type
it's pretty heavy tho

Expandnvm

#14 Script Submission » draw_slider » 2021-06-18 21:46:17

maras
Replies: 0

Draw a slider with sprites
Using device_mouse so it'll also work on phones

Expand/// draw_slider(slider_map, slider_id, x, y, sprite_first, sprite_mid, sprite_last, sprite_rider, snaps, scale)
//
// returns nothing
//
//	slider_map	map to store the slider data, ds_map
//	slider_id	id for this slider so it can be accessed, real/string
//	x		x position, real
//	y		y position, real
//	sprite_first	the first sprite, sprite
//	sprite_mid	the middle sprite, sprite
//	sprite_last	the last sprite, sprite
//	sprite_rider	that moving thing, sprite
//	snaps		how many snap points it'll have, real
//	scale		scale, real
//
// the slider ds_map needs to be created in a Create event (it can be also global)
// to access the values use: slider_map[? <slider_id>][<data_index>]
// data_indexes:
//	0: rider distance from the middle sprite's pivot
//	1: slider value between 0 and 1
//	2: current snapped point
// 
// slider_map can be only accessed AFTER it's been initialized by the sliders otherwise it'll throw an error that the value you want to access is not an array
// 
// slider_id cannot be "$ID". that is reserved for the current moving slider
// the length of the slider depends on the length of the middle sprite
// if snap is less than 2, it will not snap
//
/// GMLscripts.com/license

function draw_slider(SLIDER_MAP, slider_id, pos_x, pos_y, sprite_first, sprite_mid, sprite_last, sprite_rider, snaps, scale) {
	
	if !ds_map_exists(SLIDER_MAP, "$ID") SLIDER_MAP[? "$ID"] = undefined; // init selected slider if not done already
	if !ds_map_exists(SLIDER_MAP, slider_id) SLIDER_MAP[? slider_id] = [0, 0, 0]; // init defaults for this slider_id if not already created [rider_x, 0-1, snap], can be done manually
	
	var mx = device_mouse_x_to_gui(0);
	var my = device_mouse_y_to_gui(0);
	
	scale = max(scale, 0.001);
	
	var line_w = sprite_get_width(sprite_mid) * scale;
	var rider_w = sprite_get_width(sprite_first) * scale;
	var hitbox_h = max(sprite_get_height(sprite_mid) * scale, rider_w);
	
	pos_x += sprite_get_width(sprite_first) * scale;
	pos_y += round(hitbox_h / 2);
	
	if snaps < 2 or snaps > line_w snaps = line_w;

	var selected_id = SLIDER_MAP[? "$ID"];
	
	if device_mouse_check_button_pressed(0, mb_left) and selected_id == undefined
	and point_in_rectangle(mx, my, pos_x - rider_w, pos_y - hitbox_h/2, pos_x + rider_w + line_w, pos_y + hitbox_h/2)
		SLIDER_MAP[? "$ID"] = slider_id;
		
	if device_mouse_check_button_released(0, mb_left) and selected_id != undefined SLIDER_MAP[? "$ID"] = undefined;
	
	var rider_x = SLIDER_MAP[? slider_id][0];
	
	if selected_id == slider_id {

		var snap_size = line_w / clamp(--snaps, 1, line_w);
		rider_x = clamp(round((mx - pos_x) / snap_size) * snap_size, 0, line_w);
		
		SLIDER_MAP[? slider_id] = [rider_x, rider_x / line_w, floor(rider_x / snap_size)];
	}
	
	var alpha = draw_get_alpha();
	var col = draw_get_color();
	
	draw_sprite_ext(sprite_first, 0, pos_x, pos_y, scale, scale, 0, col, alpha); // first part
	draw_sprite_ext(sprite_mid, 0, pos_x, pos_y, scale, scale, 0, col, alpha); // middle part
	draw_sprite_ext(sprite_last, 0, pos_x + line_w, pos_y, scale, scale, 0, col, alpha); // last part
	draw_sprite_ext(sprite_rider, 0, pos_x + rider_x, pos_y, scale, scale, 0, col, alpha); // rider
}

cqd9AF0.png

#15 Re: Script Submission » foreach » 2021-06-17 16:11:18

Ohh ok I get it
And for array you can also use ds_type_list and then check it with is_array()

#16 Re: Script Submission » foreach » 2021-06-17 10:57:58

Already tried that but ds_exists does not check it correctly
When I use

Expandds_exists(list, ds_type_list)

it returns true
but when I use

Expandds_exists(list, ds_type_map)

it also returns true

https://www.reddit.com/r/gamemaker/comm … _and_data/

#17 Script Submission » foreach » 2021-06-16 07:08:37

maras
Replies: 8
Expand/// foreach(data, type, f_each)
//
// returns nothing
//
//	data		array / ds_list / ds_map / ds_grid
//	type 		what type of data is entering, ds_type
//	f_each		what to do with each value, function
//	
// type:
//	for array / ds_list: 	ds_type_list
//	for ds_map: 		ds_type_map
//	for ds_grid: 		ds_type_grid
//		
// f_each:
// function(data, index, val)
//
//	returns undefined or true
//	
//	data	returned data so it's accessible inside of the inner function
//	index	returned current data index/key
//	    array: position, real
//	    ds_list: position, real
//	    ds_map: key, string
//	    ds_grid: positions, array[x, y]
//
//	val	returned current data value
//
// to break the foreach loop simply return true inside of the inner function
//
/// GMLscripts.com/license

function foreach(data, type, f_each) {
	
	switch(type) {

		case ds_type_list:
		
			if is_array(data){
				var len = array_length(data);
				for(var i = 0; i < len; i++) {
					if f_each(data, i, data[i]) break;
				}
			}
			else {
				var len = ds_list_size(data);
				for(var i = 0; i < len; i++) {
					if f_each(data, i, data[| i]) break;
				}
			}
		break;
		
		case ds_type_map:
		
			for(var key = ds_map_find_first(data); !is_undefined(key); key = ds_map_find_next(data, key)) {
				if f_each(data, key, data[? key]) break;
			}
		break;
		
		case ds_type_grid:
		
			var w = ds_grid_width(data);
			var h = ds_grid_height(data);
		
			for(var xx = 0; xx < w; xx++) {
				for(var yy = 0; yy < h; yy++) {
					if f_each(data, [xx, yy], data[# xx, yy]) break;
				}
			}
		break;
		}
	
	}

Example code:

Expandvar list = ds_list_create();
ds_list_add(list, "one");
ds_list_add(list, "two");
ds_list_add(list, "three");

foreach(list, ds_type_list, function(d, i, v) {
	if i == 2 return true; // break
	show_debug_message(string(i)+": "+string(v));
});

// *console*
// 0: one
// 1: two

#18 Script Submission » base64 URL encode / decode » 2021-06-10 03:08:08

maras
Replies: 1

Might be useful for people using HTTP stuff
Works just like regular base64 but with characters that can be used in URL

Expand/// base64url_encode(string)
//
// returns encoded string
//
//     s    string to encode, string
//
/// GMLscripts.com/license

function base64url_encode(s) {
    s = base64_encode(string(s));
    s = string_replace_all(s, "/", "_");
    s = string_replace_all(s, "=", "");
    s = string_replace_all(s, "+", "-");
    return s;
}
Expand/// base64url_decode(string)
//
// returns decoded string
//
//     s    string to decode, string
//
/// GMLscripts.com/license

function base64url_decode(s) {
    s = string(s);
    s = string_copy(s + "===", 0, string_length(s) + (string_length(s) % 4));
    s = string_replace_all(s, "_", "/");
    s = string_replace_all(s, "-", "+");
    return base64_decode(s);
}

#19 Script Submission » draw_curve_cb (cubic bezier) » 2021-06-01 05:53:58

maras
Replies: 0
Expand/// draw_curve_cb(p1, p2, p3, p4, prec)
//
//    p1    start point, array [x, y]
//    p2    curvature point 1, array [x, y]
//    p3    curvature point 2, array [x, y]
//    p4    end point, array [x, y]
//    prec     precision, number of segments, real
//
/// GMLscripts.com/license

function draw_curve_cb(p1, p2, p3, p4, prec) {
	
	prec = round(prec);
	var prev_cb = p1;
	for(var i = 0; i < prec; i++) {
		var cb = cubic_bezier(p1, p2, p3, p4, i / prec);
		draw_line(cb[0], cb[1], prev_cb[0], prev_cb[1]);
		prev_cb = cb;
	}
	draw_line(prev_cb[0], prev_cb[1], p4[0], p4[1]);
}

/// cubic_bezier(p1, p2, p3, p4, t)
//
// returns array [x, y], a single point on the curve depending on t
//
//    p1    start point, array [x, y]
//    p2    curvature point 1, array [x, y]
//    p3    curvature point 2, array [x, y]
//    p4    end point, array [x, y]
//    t     curve position, real
//
/// GMLscripts.com/license

function cubic_bezier(p1, p2, p3, p4, t) {
    t = clamp(t, 0, 1);
    return [
        p1[0] * power(1-t, 3) + 3 * p2[0] * power(1-t, 2) * t + 3 * p3[0] * (1-t) * power(t, 2) + p4[0] * power(t, 3),
        p1[1] * power(1-t, 3) + 3 * p2[1] * power(1-t, 2) * t + 3 * p3[1] * (1-t) * power(t, 2) + p4[1] * power(t, 3)
    ];
}

AovkbN5.gif

#20 Re: Script Submission » string_get_between » 2021-05-26 18:30:04

I feel like this is faster than using string_pos because this script checks the string and returns the result in one go
With string_pos you'd need to call it twice and then use string_copy or something to get the result

Board footer

Powered by FluxBB