GestureArea.gd 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. extends Control
  2. export(NodePath) var target
  3. export var min_scale = 0.1
  4. export var max_scale = 3.0
  5. export var one_finger_rot_x = true
  6. export var one_finger_rot_y = true
  7. export var two_fingers_rot_z = true
  8. export var two_fingers_zoom = true
  9. var base_state
  10. var curr_state
  11. var target_node
  12. # We keep here a copy of the state before the number of fingers changed to avoid accumulation errors.
  13. var base_xform
  14. func _ready():
  15. base_state = {}
  16. curr_state = {}
  17. target_node = get_node(target)
  18. func _gui_input(event):
  19. # We must start touching inside, but we can drag or unpress outside.
  20. # if !(event is InputEventScreenDrag ||
  21. # (event is InputEventScreenTouch && (!event.pressed || get_global_rect().has_point(event.position)))):
  22. # return
  23. var finger_count = base_state.size()
  24. if finger_count == 0:
  25. # No fingers => Accept press.
  26. if event is InputEventScreenTouch:
  27. if event.pressed:
  28. # A finger started touching.
  29. base_state = {
  30. event.index: event.position,
  31. }
  32. elif finger_count == 1:
  33. # One finger => For rotating around X and Y.
  34. # Accept one more press, unpress or drag.
  35. if event is InputEventScreenTouch:
  36. if event.pressed:
  37. # One more finger started touching.
  38. # Reset the base state to the only current and the new fingers.
  39. base_state = {
  40. curr_state.keys()[0]: curr_state.values()[0],
  41. event.index: event.position,
  42. }
  43. else:
  44. if base_state.has(event.index):
  45. # Only touching finger released.
  46. base_state.clear()
  47. elif event is InputEventScreenDrag:
  48. if curr_state.has(event.index):
  49. # Touching finger dragged.
  50. var unit_drag = _px2unit(base_state[base_state.keys()[0]] - event.position)
  51. if one_finger_rot_x:
  52. target_node.global_rotate(Vector3.UP, deg2rad(180.0 * unit_drag.x))
  53. if one_finger_rot_y:
  54. target_node.global_rotate(Vector3.RIGHT, deg2rad(180.0 * unit_drag.y))
  55. # Since rotating around two axes, we have to reset the base constantly.
  56. curr_state[event.index] = event.position
  57. base_state[event.index] = event.position
  58. base_xform = target_node.get_transform()
  59. elif finger_count == 2:
  60. # Two fingers => To pinch-zoom and rotate around Z.
  61. # Accept unpress or drag.
  62. if event is InputEventScreenTouch:
  63. if !event.pressed && base_state.has(event.index):
  64. # Some known touching finger released.
  65. # Remove released finger from the base state.
  66. base_state.erase(event.index)
  67. # Reset the base state to the now only toyching finger.
  68. base_state = {
  69. curr_state.keys()[0]: curr_state.values()[0],
  70. }
  71. elif event is InputEventScreenDrag:
  72. if curr_state.has(event.index):
  73. # Some known touching finger dragged.
  74. curr_state[event.index] = event.position
  75. # Compute base and current inter-finger vectors.
  76. var base_segment = base_state[base_state.keys()[0]] - base_state[base_state.keys()[1]]
  77. var new_segment = curr_state[curr_state.keys()[0]] - curr_state[curr_state.keys()[1]]
  78. # Get the base scale from the base matrix.
  79. var base_scale = Vector3(base_xform.basis.x.x, base_xform.basis.y.y, base_xform.basis.z.z).length()
  80. if two_fingers_zoom:
  81. # Compute the new scale limiting it and taking into account the base scale.
  82. var new_scale = clamp(base_scale * (new_segment.length() / base_segment.length()), min_scale, max_scale) / base_scale
  83. target_node.set_transform(base_xform.scaled(new_scale * Vector3.ONE))
  84. else:
  85. target_node.set_transform(base_xform)
  86. if two_fingers_rot_z:
  87. # Apply rotation between base inter-finger vector and the current one.
  88. var rot = new_segment.angle_to(base_segment)
  89. target_node.global_rotate(Vector3.BACK, rot)
  90. # Finger count changed?
  91. if base_state.size() != finger_count:
  92. # Copy new base state to the current state.
  93. curr_state = {}
  94. for idx in base_state.keys():
  95. curr_state[idx] = base_state[idx]
  96. # Remember the base transform.
  97. base_xform = target_node.get_transform()
  98. # Converts a vector in pixels to a unitary magnitude,
  99. # considering the number of pixels of the shorter axis is the unit.
  100. func _px2unit(v):
  101. var shortest = min(get_size().x, get_size().y)
  102. return v * (1.0 / shortest)