keebie/scripts/key_helper.gd

141 lines
4.5 KiB
GDScript

class_name KeyHelper
const ADJACENCY_MAP: Dictionary[Key, Array] = {
KEY_1: [KEY_2, KEY_Q],
KEY_2: [KEY_3, KEY_W, KEY_Q, KEY_1],
KEY_3: [KEY_4, KEY_E, KEY_W, KEY_2],
KEY_4: [KEY_5, KEY_R, KEY_E, KEY_3],
KEY_5: [KEY_6, KEY_T, KEY_R, KEY_4],
KEY_6: [KEY_7, KEY_Y, KEY_T, KEY_5],
KEY_7: [KEY_8, KEY_U, KEY_Y, KEY_6],
KEY_8: [KEY_9, KEY_I, KEY_U, KEY_7],
KEY_9: [KEY_0, KEY_O, KEY_I, KEY_8],
KEY_0: [KEY_MINUS, KEY_P, KEY_O, KEY_9],
KEY_MINUS: [KEY_EQUAL, KEY_BRACKETLEFT, KEY_P, KEY_0],
KEY_EQUAL: [KEY_BRACKETLEFT, KEY_BRACKETRIGHT, KEY_MINUS],
KEY_Q: [KEY_1, KEY_2, KEY_W, KEY_A],
KEY_W: [KEY_2, KEY_3, KEY_E, KEY_S, KEY_A, KEY_Q],
KEY_E: [KEY_3, KEY_4, KEY_R, KEY_D, KEY_S, KEY_W],
KEY_R: [KEY_4, KEY_5, KEY_T, KEY_F, KEY_D, KEY_E],
KEY_T: [KEY_5, KEY_6, KEY_Y, KEY_G, KEY_F, KEY_R],
KEY_Y: [KEY_6, KEY_7, KEY_U, KEY_H, KEY_G, KEY_T],
KEY_U: [KEY_7, KEY_8, KEY_I, KEY_J, KEY_H, KEY_Y],
KEY_I: [KEY_8, KEY_9, KEY_O, KEY_K, KEY_J, KEY_U],
KEY_O: [KEY_9, KEY_0, KEY_P, KEY_L, KEY_K, KEY_I],
KEY_P: [KEY_0, KEY_MINUS, KEY_BRACKETLEFT, KEY_SEMICOLON, KEY_L, KEY_O],
KEY_BRACKETLEFT:
[KEY_MINUS, KEY_EQUAL, KEY_BRACKETRIGHT, KEY_APOSTROPHE, KEY_SEMICOLON, KEY_P],
KEY_BRACKETRIGHT: [KEY_EQUAL, KEY_APOSTROPHE, KEY_BRACKETLEFT],
KEY_A: [KEY_Q, KEY_W, KEY_S, KEY_Z],
KEY_S: [KEY_W, KEY_E, KEY_D, KEY_X, KEY_Z, KEY_A],
KEY_D: [KEY_E, KEY_R, KEY_F, KEY_C, KEY_X, KEY_S],
KEY_F: [KEY_R, KEY_T, KEY_G, KEY_V, KEY_C, KEY_D],
KEY_G: [KEY_T, KEY_Y, KEY_H, KEY_B, KEY_V, KEY_F],
KEY_H: [KEY_Y, KEY_U, KEY_J, KEY_N, KEY_B, KEY_G],
KEY_J: [KEY_U, KEY_I, KEY_K, KEY_M, KEY_N, KEY_H],
KEY_K: [KEY_I, KEY_O, KEY_L, KEY_COMMA, KEY_M, KEY_J],
KEY_L: [KEY_O, KEY_P, KEY_SEMICOLON, KEY_PERIOD, KEY_COMMA, KEY_K],
KEY_SEMICOLON:
[KEY_P, KEY_BRACKETLEFT, KEY_APOSTROPHE, KEY_SLASH, KEY_PERIOD, KEY_L],
KEY_APOSTROPHE: [KEY_BRACKETLEFT, KEY_BRACKETRIGHT, KEY_SLASH, KEY_SEMICOLON],
KEY_Z: [KEY_A, KEY_S, KEY_X],
KEY_X: [KEY_S, KEY_D, KEY_C, KEY_Z],
KEY_C: [KEY_D, KEY_F, KEY_V, KEY_X],
KEY_V: [KEY_F, KEY_G, KEY_B, KEY_C],
KEY_B: [KEY_G, KEY_H, KEY_N, KEY_V],
KEY_N: [KEY_H, KEY_J, KEY_M, KEY_B],
KEY_M: [KEY_J, KEY_K, KEY_COMMA, KEY_N],
KEY_COMMA: [KEY_K, KEY_L, KEY_PERIOD, KEY_M],
KEY_PERIOD: [KEY_L, KEY_SEMICOLON, KEY_SLASH, KEY_COMMA],
KEY_SLASH: [KEY_SEMICOLON, KEY_APOSTROPHE, KEY_PERIOD],
}
static func sort_func(a: GameKey, b: GameKey) -> bool:
var a_pos := a.get_default_transform().origin
var b_pos := b.get_default_transform().origin
if a_pos.y == b_pos.y:
return a_pos.x < b_pos.x
return a_pos.y < b_pos.y
static func get_rotated_key_pos(
key_pos: Vector3, pivot: Vector2, angle: float
) -> Vector3:
var pivot_pos := Vector3(pivot.x, 0, pivot.y)
return (key_pos - pivot_pos).rotated(Vector3.UP, angle) + pivot_pos
static func iterate_keys(
iter_func: Callable,
layout_rows: Array[Array],
key_size: float = 1,
key_gap: float = 0,
current_keys: Dictionary[Vector2i, Array] = {}
) -> Rect2:
var pos: Vector2 = Vector2.ZERO
var pivot := Vector2.ZERO
var angle: float = 0
var rect: Rect2 = Rect2(0, 0, 0, 0)
for row: Array[KeyProps] in layout_rows:
var result := _iterate_row(
iter_func, row, pos, pivot, angle, rect, key_size, key_gap, current_keys
)
pos = result[0]
pos.y += 1 + key_gap
pivot = result[1]
angle = result[2]
rect = result[3]
return rect
static func _iterate_row(
iter_func: Callable,
row: Array[KeyProps],
pos: Vector2,
pivot: Vector2,
angle: float,
rect: Rect2,
key_size: float,
key_gap: float,
current_keys: Dictionary[Vector2i, Array]
) -> Array[Variant]:
pos.x = pivot.x
for key_props in row:
if key_props.has_angle():
angle = -deg_to_rad(key_props.angle)
if key_props.has_pivot_x():
pivot.x = key_props.pivot_x
if key_props.has_pivot_y():
pivot.y = key_props.pivot_y
if key_props.has_pivot_x() or key_props.has_pivot_y():
pos = pivot
var key_pos := Vector3(pos.x + key_size / 2, 0, pos.y + key_size / 2)
key_pos.x += (
(key_size * key_props.width - key_size) / 2 + key_size * key_props.x
)
key_pos.z += key_props.y * key_size
key_pos = KeyHelper.get_rotated_key_pos(key_pos, pivot, angle)
iter_func.call(key_props, key_pos, angle, current_keys)
if pos.x < rect.position.x:
rect.position.x = pos.x
if pos.y < rect.position.y:
rect.position.y = pos.y
pos.x += key_props.width * key_size + key_props.x * key_size + key_gap
pos.y += key_props.y * key_size
if pos.x - key_gap > rect.end.x:
rect.end.x = pos.x - key_gap
if pos.y + key_size * key_props.height > rect.end.y:
rect.end.y = pos.y + key_size * key_props.height
return [pos, pivot, angle, rect]