diff --git a/core/edge_scroll_camera.gd b/core/edge_scroll_camera.gd index aab10f0..00ad1fb 100644 --- a/core/edge_scroll_camera.gd +++ b/core/edge_scroll_camera.gd @@ -1,6 +1,7 @@ ## Scrolls the camera when the mouse cursor reaches the screen edge. ## Attach to a Camera2D node. Requires an OrthographicCamera2D or ViewportContainer ## to determine screen bounds at runtime. +@tool extends Camera2D ## Speed at which the camera scrolls (pixels per second). @@ -18,6 +19,15 @@ extends Camera2D ## Maximum bounds when clamping (in world space). @export var clamp_max: Vector2 = Vector2.ZERO +## Zoom sensitivity per mouse wheel tick. +@export var zoom_sensitivity: float = 0.1 + +## Minimum zoom level. +@export var zoom_min: float = 0.25 + +## Maximum zoom level. +@export var zoom_max: float = 3.0 + var _screen_rect: Rect2 @@ -29,6 +39,10 @@ func _ready() -> void: func _process(delta: float) -> void: + if Engine.is_editor_hint(): + queue_redraw() + return + if is_zero_approx(scroll_speed): return @@ -58,11 +72,46 @@ func _get_scroll_direction(mouse_pos: Vector2) -> Vector2: return direction.normalized() +func _draw() -> void: + if not Engine.is_editor_hint(): + return + if not clamp_enabled: + return + + var rect_size: Vector2 = clamp_max - clamp_min + draw_rect(Rect2(clamp_min, rect_size), Color(1, 0.4, 0, 0.35)) + draw_rect(Rect2(clamp_min, rect_size), Color(1, 0.6, 0.2, 0.8), false, 2.0) + + func _clamp_position() -> void: position.x = clampf(position.x, clamp_min.x, clamp_max.x) position.y = clampf(position.y, clamp_min.y, clamp_max.y) +func _unhandled_input(event: InputEvent) -> void: + if Engine.is_editor_hint(): + return + + if event is InputEventMouseButton: + var mouse_event: InputEventMouseButton = event + if mouse_event.button_index == MOUSE_BUTTON_WHEEL_UP: + _zoom(zoom_sensitivity, mouse_event.position) + elif mouse_event.button_index == MOUSE_BUTTON_WHEEL_DOWN: + _zoom(-zoom_sensitivity, mouse_event.position) + + +func _zoom(change: float, mouse_pos: Vector2) -> void: + var new_zoom_value: float = clampf(zoom.x + change, zoom_min, zoom_max) + if is_equal_approx(new_zoom_value, zoom.x): + return + + var viewport_center: Vector2 = get_viewport_rect().size / 2.0 + var offset: Vector2 = mouse_pos - viewport_center + var world_point: Vector2 = position + offset / zoom + zoom = Vector2(new_zoom_value, new_zoom_value) + position = world_point - offset / zoom + + func _update_screen_rect() -> void: var viewport: Viewport = get_viewport() if viewport != null: diff --git a/docs/gyms/tiny_sword/buildings/alchemy_tower/alchemy_tower.gd b/docs/gyms/tiny_sword/buildings/alchemy_tower/alchemy_tower.gd index de947cd..fddca0d 100644 --- a/docs/gyms/tiny_sword/buildings/alchemy_tower/alchemy_tower.gd +++ b/docs/gyms/tiny_sword/buildings/alchemy_tower/alchemy_tower.gd @@ -3,21 +3,19 @@ extends Node2D ## Emitted when production progress changes (0.0 to 1.0) signal production_progress_updated(progress: float) - ## Emitted when magic gold balance changes signal magic_gold_balance_updated(amount: BigNumber) - ## Emitted when a production cycle completes signal production_completed(amount: BigNumber) ## Configuration data for this tower @export var data: AlchemyTowerData - ## Available craft recipes @export var craft_recipes: AlchemyCraftCatalogue ## Reference to game state @onready var game_state: LevelGameState = find_parent("LevelGameState") +@onready var _alchemy_currencies_panel: AlchemyCurrenciesPanel = $AlchemyCurrenciesPanel ## Current production state var production_time_elapsed: float = 0.0 @@ -194,3 +192,11 @@ func _on_craft_requested(recipe: Variant) -> void: var success: bool = craft_item(recipe) if not success: push_warning("AlchemyTower: Failed to craft %s - insufficient funds" % recipe.output_currency.display_name) + + +func _on_area_2d_mouse_entered() -> void: + _alchemy_currencies_panel.visible = true + + +func _on_area_2d_mouse_exited() -> void: + _alchemy_currencies_panel.visible = false diff --git a/docs/gyms/tiny_sword/buildings/alchemy_tower/alchemy_tower.tscn b/docs/gyms/tiny_sword/buildings/alchemy_tower/alchemy_tower.tscn index 10e5493..7f00c41 100644 --- a/docs/gyms/tiny_sword/buildings/alchemy_tower/alchemy_tower.tscn +++ b/docs/gyms/tiny_sword/buildings/alchemy_tower/alchemy_tower.tscn @@ -25,9 +25,13 @@ position = Vector2(0.5, 11) shape = SubResource("RectangleShape2D_8pntr") [node name="AlchemyCurrenciesPanel" parent="." unique_id=731368154 instance=ExtResource("2_8pntr")] +visible = false offset_left = 65.0 offset_top = -75.0 offset_right = 65.0 offset_bottom = -75.0 currency = ExtResource("7_b8p5n") craft_recipes = ExtResource("5_recipes") + +[connection signal="mouse_entered" from="Area2D" to="." method="_on_area_2d_mouse_entered"] +[connection signal="mouse_exited" from="Area2D" to="." method="_on_area_2d_mouse_exited"] diff --git a/docs/gyms/tiny_sword/tiny_sword.tscn b/docs/gyms/tiny_sword/tiny_sword.tscn index e4dbdff..2106f61 100644 --- a/docs/gyms/tiny_sword/tiny_sword.tscn +++ b/docs/gyms/tiny_sword/tiny_sword.tscn @@ -90,5 +90,12 @@ position = Vector2(105, 920) position = Vector2(1239, 775) [node name="Camera2D" type="Camera2D" parent="." unique_id=1494908331] +position = Vector2(5, 0) offset = Vector2(960, 540) script = ExtResource("17_x77df") +clamp_enabled = true +clamp_min = Vector2(-1920, -1080) +clamp_max = Vector2(1920, 1080) +zoom_sensitivity = null +zoom_min = null +zoom_max = null diff --git a/docs/museums/edge_scroll_camera.tscn b/docs/museums/edge_scroll_camera.tscn index 0ba817b..108e56f 100644 --- a/docs/museums/edge_scroll_camera.tscn +++ b/docs/museums/edge_scroll_camera.tscn @@ -6,8 +6,37 @@ [node name="EdgeScrollCamera" type="Node2D" unique_id=1977543223] [node name="Camera2D" type="Camera2D" parent="." unique_id=455629291] +offset = Vector2(960, 540) script = ExtResource("1_08uhj") +clamp_enabled = true +clamp_max = Vector2(3000, 2000) [node name="Icon" type="Sprite2D" parent="." unique_id=629901180] -position = Vector2(469, 252) +position = Vector2(988, 485) +texture = ExtResource("2_c5cli") + +[node name="Icon2" type="Sprite2D" parent="." unique_id=919808260] +position = Vector2(1714, 130) +texture = ExtResource("2_c5cli") + +[node name="Icon3" type="Sprite2D" parent="." unique_id=368045162] +position = Vector2(1750, 957) +texture = ExtResource("2_c5cli") + +[node name="Icon6" type="Sprite2D" parent="." unique_id=1755994416] +position = Vector2(2641, 1655) +rotation = 0.9242716 +texture = ExtResource("2_c5cli") + +[node name="Icon7" type="Sprite2D" parent="." unique_id=460486605] +position = Vector2(895.00024, 1641) +rotation = 0.9242716 +texture = ExtResource("2_c5cli") + +[node name="Icon4" type="Sprite2D" parent="." unique_id=957351194] +position = Vector2(134, 962) +texture = ExtResource("2_c5cli") + +[node name="Icon5" type="Sprite2D" parent="." unique_id=2077463270] +position = Vector2(137, 129) texture = ExtResource("2_c5cli")