summaryrefslogtreecommitdiff
path: root/UI/Camera.gd
blob: 3009ed226250d497e6f68b773c88c123ba9d1743 (plain)
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
class_name Camera
extends Camera2D


signal zoomed(zoom: Vector2)

var is_in_drag_mode := false
var drag_anchor := Vector2.ZERO

var is_in_edge_mode := false
var edge := Vector2.ZERO
@export var edge_scroll_margin := 4.0

@export var speed := 25

@export_group("Zoom", "zoom")
@export var zoom_min: float = 0.5
@export var zoom_max: float = 3
@export var zoom_step: float = 0.01


func _ready():
	get_viewport().size_changed.connect(func():
		set_new_position(global_position)
		var new_zoom = Vector2(
			(limit_right - limit_left) / get_viewport_rect().size.x,
			(limit_bottom - limit_top) / get_viewport_rect().size.y
		)
		zoom = Vector2(
			new_zoom[new_zoom.max_axis_index()],
			new_zoom[new_zoom.max_axis_index()]
		)
		zoomed.emit(zoom)
	)
	
	Input.mouse_mode = Input.MOUSE_MODE_CONFINED


func _input(event):
	if event.is_action("camera_zoom_out"):
		var can_zoom_out = (
			(limit_right - limit_left) / get_rect().size.x > 1.0 and
			(limit_bottom - limit_top) / get_rect().size.y > 1.0
		)
		if can_zoom_out:
			var new_zoom = max(zoom.x - zoom_step, zoom_min)
			zoom = Vector2(new_zoom, new_zoom)
			zoomed.emit(zoom)
	if event.is_action("camera_zoom_in"):
		var new_zoom = min(zoom.x + zoom_step, zoom_max)
		zoom = Vector2(new_zoom, new_zoom)
		zoomed.emit(zoom)
	
	
	if event.is_action_pressed("camera_drag"):
		is_in_drag_mode = true
		drag_anchor = get_global_mouse_position()
		Input.set_default_cursor_shape(Input.CURSOR_MOVE)
	elif event.is_action_released("camera_drag"):
		is_in_drag_mode = false
		Input.set_default_cursor_shape(Input.CURSOR_ARROW)
	
	
	if event is InputEventMouseMotion:
		is_in_edge_mode = false
		edge = Vector2.ZERO
		if get_global_mouse_position().x - edge_scroll_margin <= get_rect().position.x:
			is_in_edge_mode = true
			edge += Vector2.LEFT
		if get_global_mouse_position().y - edge_scroll_margin <= get_rect().position.y:
			is_in_edge_mode = true
			edge += Vector2.UP
		if get_global_mouse_position().x + edge_scroll_margin >= get_rect().end.x:
			is_in_edge_mode = true
			edge += Vector2.RIGHT
		if get_global_mouse_position().y + edge_scroll_margin >= get_rect().end.y:
			is_in_edge_mode = true
			edge += Vector2.DOWN
		edge = edge.normalized()
	
	if event is InputEventMouseButton and event.is_pressed():
		Input.mouse_mode = Input.MOUSE_MODE_CONFINED
	elif event.is_action_pressed("mouse_escape"):
		Input.mouse_mode = Input.MOUSE_MODE_VISIBLE


func _process(delta):
	if is_in_drag_mode:
		set_new_position(global_position + drag_anchor - get_global_mouse_position())
	
	if is_in_edge_mode:
		set_new_position(
			lerp(
				global_position,
				global_position + (edge * speed),
				speed * delta
			)
		)
	
	var direction_h = Input.get_axis("ui_left", "ui_right")
	var direction_v = Input.get_axis("ui_up", "ui_down")
	
	if direction_h != 0 or direction_v != 0:
		set_new_position(
			lerp(
				global_position,
				global_position + Vector2(direction_h * speed, direction_v * speed),
				speed * delta
			)
		)


func set_new_position(new_position: Vector2):
	new_position.x = clamp(
		new_position.x,
		limit_left,
		limit_right - get_rect().size.x
	)
	
	new_position.y = clamp(
		new_position.y,
		limit_top,
		limit_bottom - get_rect().size.y
	)
	
	global_position = new_position


func set_center(center_position: Vector2):
	set_new_position(
		center_position - (get_rect().size / 2)
	)


func get_rect():
	var viewport = get_viewport_rect()
	
	return Rect2(
		global_position,
		viewport.size * Vector2(1 / zoom.x, 1 / zoom.y)
	)