-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathMapController2D.gd
216 lines (167 loc) · 7.79 KB
/
MapController2D.gd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
extends Panel # TODO change to Control or something similar
# Orthogonal basis vectors
var Origin : Vector2 = Vector2(-2.5, -1.2)
var HorizontalBasis : Vector2 = Vector2(0.004, 0.0)
var VerticalBasis : Vector2 = Vector2(0.0, 0.004)
# View-related variables
var Center : Vector2 = Vector2(-0.55, 0.0)
var Radius : float = 1.3
var Rotation : Vector3 = Vector3(0.0, 0.0, 0.0) # TODO: change to single Angle (2D)
var Zoom : float = 1.0
# Parameters of keyboard and mouse triggered movements
export var ZoomFactor : float = 1.1
export var PanDelta : float = 10
export var RotationAngle : float = PI/100
# TODO: rename with uppercase
export var MouseButtonPan = BUTTON_LEFT
export var MouseButtonZoomIn = BUTTON_WHEEL_UP
export var MouseButtonZoomOut = BUTTON_WHEEL_DOWN
# TODO to be used later
export var VerticalAxisUp : bool = true
export var ViewCircle : bool = true
#export var Rotation : bool = true
var dragging : bool = false
var dragging_position : Vector2
# Dictionary of current touch points in screen coordinates relative to the Node (from InputEvent).
# The coordinates of the related points in Map coordinates do not change during a pan or zoom.
var touch_points = {}
# List of touch point indexes to be removed at next frame (e.g. following unpressed)
var released_touch_points = []
# Touch points of the previous frame. The number of touch points may vary between frames.
# Normally only updated in `_process` but may be modified in `_input` to simulate movements
# based on single events (from keyboard or clicks).
var previous_touch_points = {}
# Non-continuous movement triggered by single clicks or keyboard hits
enum {ZOOM, PAN, ROTATION, NONE}
var single_movement_type = NONE
var single_zoom_factor : float
var single_zoom_center : Vector2
var single_pan_direction : Vector2 = Vector2(0,0)
var single_rotation_angle : float
# Called when the node enters the scene tree for the first time.
func _ready():
#print(Time.get_unix_time_from_system())
pass # Replace with function body.
# Called every frame to compute the new position using the touch points acquired from input events
func _process(_delta):
############################ Single movements ##############################
match single_movement_type:
ZOOM:
Origin += (1-single_zoom_factor)*single_zoom_center.x*HorizontalBasis
Origin += (1-single_zoom_factor)*single_zoom_center.y*VerticalBasis
HorizontalBasis *= single_zoom_factor
VerticalBasis *= single_zoom_factor
PAN:
Origin += single_pan_direction.x*HorizontalBasis
Origin += single_pan_direction.y*VerticalBasis
ROTATION:
HorizontalBasis = HorizontalBasis.rotated(single_rotation_angle)
VerticalBasis = VerticalBasis.rotated(single_rotation_angle)
single_movement_type = NONE
single_pan_direction = Vector2(0,0)
############################ Touch movements ###############################
# PAN if current or previous frame has exactly one point, kept between frames
if touch_points.size() == 1 and previous_touch_points.has(touch_points.keys()[0]) or \
previous_touch_points.size() == 1 and touch_points.has(previous_touch_points.keys()[0]):
# Determines the index of the touch point and the delta in screen coordinates
var index = (touch_points if touch_points.size() == 1 else previous_touch_points).keys()[0]
var delta = touch_points[index] - previous_touch_points[index]
# Adapts values
Origin -= delta.x*HorizontalBasis + delta.y*VerticalBasis
# ZOOM/ROTATE if 2 points are kept between frames
elif touch_points.size() == 2 and previous_touch_points.size() >= 2 and \
previous_touch_points.has(touch_points.keys()[0]) and \
previous_touch_points.has(touch_points.keys()[1]):
# Determines the new and previous touch points, and their deltas
var index1 = touch_points.keys()[0]
var np1 = touch_points[index1]
var pp1 = previous_touch_points[index1]
#var d1 = np1 - pp1
var index2 = touch_points.keys()[1]
var np2 = touch_points[index2]
var pp2 = previous_touch_points[index2]
#var d2 = np2 - pp2
# Computes intermediate vectors (see formulas notebook)
var A = np1 - np2
var B = (pp1.x-pp2.x)*HorizontalBasis + (pp1.y-pp2.y)*VerticalBasis
var D = A.x*A.x + A.y*A.y
# Solution only if D big enough
if D > 1e-6:
Origin += pp1.x*HorizontalBasis + pp1.y*VerticalBasis
HorizontalBasis.x = (A.x*B.x + A.y*B.y) / D
HorizontalBasis.y = (A.x*B.y - A.y*B.x) / D
VerticalBasis.x = -HorizontalBasis.y
VerticalBasis.y = HorizontalBasis.x
Origin -= np1.x*HorizontalBasis + np1.y*VerticalBasis
# Prepares structure for next frame
previous_touch_points = touch_points.duplicate()
for index in released_touch_points:
touch_points.erase(index)
released_touch_points = []
# Updates parameters in shader
material.set_shader_param("Resolution", rect_size)
material.set_shader_param("Center", Center)
material.set_shader_param("Radius", Radius)
material.set_shader_param("Rotation", Rotation)
material.set_shader_param("Origin", Origin)
material.set_shader_param("HorizontalBasis", HorizontalBasis)
material.set_shader_param("VerticalBasis", VerticalBasis)
# Message
$Label.text = "Arrow keys or mouse to pan - Mouse wheel or PgUp/PgDown to zoom"
$Label.text += " - Del/End to rotate - Drag/Pinch on mobile"
$Label.text += "\nOrigin: " + str(Origin)
$Label.text += "\nBasis vectors: " + str(HorizontalBasis) + " " + str(VerticalBasis)
$Label.text += "\nTouch points:" + str(previous_touch_points)
func label_print(string):
$Label.text = string + "\n" + $Label.text
func _input(event : InputEvent) -> void:
######################### Mouse events #####################################
if event is InputEventMouseButton:
if event.pressed and event.button_index == BUTTON_WHEEL_UP:
single_movement_type = ZOOM
single_zoom_center = event.position
single_zoom_factor = 1/(ZoomFactor*event.factor)
if event.pressed and event.button_index == BUTTON_WHEEL_DOWN:
single_movement_type = ZOOM
single_zoom_center = event.position
single_zoom_factor = ZoomFactor*event.factor
# Simulates a pan with single touch point with index 100
if event is InputEventMouseButton and event.button_index == MouseButtonPan or \
event is InputEventMouseMotion and touch_points.has(100):
touch_points[100] = event.position
if event is InputEventMouseButton and not event.pressed:
released_touch_points.append(100)
######################### Touch events #####################################
# Record position of touch event
if event is InputEventScreenTouch or event is InputEventScreenDrag:
touch_points[event.index] = event.position
if event is InputEventScreenTouch and not event.pressed:
released_touch_points.append(event.index)
######################### Keyboard events ##################################
if event is InputEventKey and event.pressed:
if event.scancode in [KEY_RIGHT, KEY_D]:
single_movement_type = PAN
single_pan_direction.x += PanDelta
if event.scancode in [KEY_LEFT, KEY_A]:
single_movement_type = PAN
single_pan_direction.x -= PanDelta
if event.scancode in [KEY_UP, KEY_W]:
single_movement_type = PAN
single_pan_direction.y -= PanDelta
if event.scancode in [KEY_DOWN, KEY_S]:
single_movement_type = PAN
single_pan_direction.y += PanDelta
if event.scancode in [KEY_KP_ADD, KEY_PAGEDOWN, KEY_R]:
single_movement_type = ZOOM
single_zoom_factor = 1/ZoomFactor
single_zoom_center = rect_size / 2
if event.scancode in [KEY_KP_SUBTRACT, KEY_PAGEUP, KEY_F]:
single_movement_type = ZOOM
single_zoom_factor = ZoomFactor
single_zoom_center = rect_size / 2
if event.scancode in [KEY_KP_DIVIDE, KEY_DELETE, KEY_Q]:
single_movement_type = ROTATION
single_rotation_angle = RotationAngle
if event.scancode in [KEY_KP_MULTIPLY, KEY_END, KEY_E]:
single_movement_type = ROTATION
single_rotation_angle = -RotationAngle