Last active
September 18, 2020 07:01
-
-
Save figgleforth/c4fd7cc605e3570d8f53ab694cf3fc74 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Based on https://gamedev.stackexchange.com/questions/182534/comparing-analog-stick-movements-to-predefined-flick-shapes | |
extends Node2D | |
signal gesture_began(recognizer, gesture) | |
signal gesture_ended(recognizer, gesture) | |
signal gesture_recognized(recognizer, gesture) | |
export(bool) var draw_gizmos = true | |
export(int) var gizmo_line_resolution = 100 | |
export(float) var gizmo_analog_diagram_line_width = 2.0 | |
export(float) var gizmo_analog_trail_line_width = 3.0 | |
export(int) var gizmo_analog_diagram_radius = 40 | |
export(Color) var gizmo_analog_diagram_color = Color.black | |
export(Color) var gizmo_analog_trail_color = Color.orangered | |
export(Color) var gizmo_analog_knob_color = Color.orange | |
export(float) var gizmo_analog_knob_size = 7.0 | |
export(float, 0.1, 0.9)var gesture_activation_radius: float = 0.7 | |
export(int) var frame_count_before_gesture_reset = 2 | |
export(int) var gesture_bucket_count: int = 8 | |
var _input: Vector2 | |
var _gesture_duration = 0.0 | |
var _last_bucket: int | |
var _frames_in_deadzone: int | |
var _ready_to_begin_gesture: bool | |
var _current_gesture := "" | |
var _gesture_history = [] | |
var _gesture_history_size = 32 | |
var _registered_gestures = [] | |
onready var _offset: float = gizmo_analog_diagram_radius - gizmo_analog_knob_size | |
func _ready(): | |
_gesture_history.resize(_gesture_history_size) | |
for i in _gesture_history_size: | |
_gesture_history[i] = Vector2() | |
func register_gesture(gesture: String) -> void: | |
if not _registered_gestures.has(gesture): | |
_registered_gestures.append(gesture) | |
func input(analog_input: Vector2) -> void: | |
_input = analog_input | |
func _process(delta): | |
if not draw_gizmos: | |
return | |
_gesture_history[get_tree().get_frame() & (_gesture_history_size - 1)] = _input | |
var magnitude = _input.length() | |
if magnitude < (1.0 - gesture_activation_radius): | |
if _gesture_duration > 0 && _frames_in_deadzone > frame_count_before_gesture_reset: | |
_end_gesture() | |
_frames_in_deadzone += 1 | |
_ready_to_begin_gesture = true | |
else: | |
_frames_in_deadzone = 0 | |
if _ready_to_begin_gesture && magnitude > gesture_activation_radius: | |
if _gesture_duration == 0: | |
_begin_gesture() | |
_gesture_duration += delta | |
_process_gesture() | |
update() | |
func _begin_gesture(): | |
_last_bucket = -1 | |
_current_gesture = "" | |
func _process_gesture() -> void: | |
var bucket = _current_bucket() | |
if bucket != _last_bucket: | |
_current_gesture += str(bucket) | |
_recognize_gesture() | |
_last_bucket = bucket | |
func _end_gesture(): | |
emit_signal("gesture_ended", self, _current_gesture) | |
_gesture_duration = 0.0 | |
_ready_to_begin_gesture = false | |
func _recognize_gesture() -> void: | |
if _current_gesture.length() == 1: | |
emit_signal("gesture_began", self, _current_gesture) | |
if _registered_gestures.has(_current_gesture): | |
emit_signal("gesture_recognized", self, _current_gesture) | |
func _current_bucket() -> int: | |
var buckets_per_radian = gesture_bucket_count / (2 * PI) | |
var angle = atan2(-_input.x, -_input.y) | |
return int(round(angle * buckets_per_radian + gesture_bucket_count / 2.0)) % gesture_bucket_count | |
func _gesture_at_index(index: int = 1) -> Vector2: | |
return _gesture_history[(get_tree().get_frame() + index) & (_gesture_history_size - 1)] | |
func _draw(): | |
if not draw_gizmos: | |
return | |
var buckets_per_radian = gesture_bucket_count / (2 * PI) | |
var radians_per_bucket = (2 * PI) / gesture_bucket_count | |
var activation_radius = gesture_activation_radius * gizmo_analog_diagram_radius | |
var angle_offset = 0.5 * radians_per_bucket | |
for i in gesture_bucket_count: | |
var start_angle = i * radians_per_bucket + angle_offset | |
var end_angle = (i + 1) * radians_per_bucket + angle_offset | |
# Outer arc | |
draw_arc(Vector2(), | |
gizmo_analog_diagram_radius, | |
start_angle, | |
end_angle, | |
gizmo_line_resolution, | |
gizmo_analog_diagram_color, | |
gizmo_analog_diagram_line_width) | |
# Inner arc | |
draw_arc(Vector2(), | |
activation_radius, | |
start_angle, | |
end_angle, | |
gizmo_line_resolution, | |
gizmo_analog_diagram_color, | |
gizmo_analog_diagram_line_width) | |
# Vertical line separating buckets | |
var bucket_separator = Vector2(sin(start_angle), cos(start_angle)) | |
draw_line(bucket_separator * activation_radius, | |
bucket_separator * gizmo_analog_diagram_radius, | |
gizmo_analog_diagram_color, | |
gizmo_analog_diagram_line_width) | |
# Gesture trail | |
var last_gesture: Vector2 = _gesture_at_index() | |
for i in range(1, _gesture_history_size + 1): | |
var next_gesture = _gesture_at_index(i) | |
draw_line(last_gesture * _offset, | |
next_gesture * _offset, | |
gizmo_analog_trail_color, | |
gizmo_analog_trail_line_width) | |
last_gesture = next_gesture | |
# Gesture knob | |
draw_circle(last_gesture * _offset, | |
gizmo_analog_knob_size, | |
gizmo_analog_knob_color) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extends Node2D | |
# Add a Node2D as a child of this node and attach the AnalogGestureRecognizer.gd script to it. Then reference it in this node. | |
onready var gesture_recognizer = $AnalogGestureRecognizer | |
# Register a gesture for the recognizer to look for and connect to the signals. | |
func _ready(): | |
gesture_recognizer.register_gesture('01234') | |
gesture_recognizer.connect("gesture_began", self, "gesture_began") | |
gesture_recognizer.connect("gesture_ended", self, "gesture_ended") | |
gesture_recognizer.connect("gesture_recognized", self, "gesture_recognized") | |
func _process(delta): | |
var right_stick = Vector2.ZERO | |
var rx = Input.get_joy_axis(0, JOY_AXIS_2) | |
var ry = Input.get_joy_axis(0 ,JOY_AXIS_3) | |
if abs(rx) > 0.1: # deadzone | |
right_stick.x = rx | |
if abs(ry) > 0.1: # deadzone | |
right_stick.y = ry | |
gesture_recognizer.input(right_stick) | |
func gesture_began(recognizer, gesture): | |
print(str('began ', gesture)) | |
func gesture_ended(recognizer, gesture): | |
print(str('ended ', gesture)) | |
func gesture_recognized(recognizer, gesture): | |
print(str('recognized ', gesture)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment