diff --git a/Scenes/toast.tscn b/Scenes/toast.tscn new file mode 100644 index 0000000..740f711 --- /dev/null +++ b/Scenes/toast.tscn @@ -0,0 +1,38 @@ +[gd_scene format=3 uid="uid://c8toast123456"] + +[ext_resource type="Script" path="res://Scripts/toast.gd" id="1_toast"] + +[node name="Toast" type="Control"] +z_index = 1000 +layout_mode = 3 +anchors_preset = 0 +offset_left = 0.0 +offset_top = 0.0 +offset_right = 300.0 +offset_bottom = 60.0 +script = ExtResource("1_toast") + +[node name="Panel" type="Panel" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="Label" type="Label" parent="Panel"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +offset_left = 10.0 +offset_top = 5.0 +offset_right = -10.0 +offset_bottom = -5.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_colors/font_color = Color(1, 1, 1, 1) +theme_override_font_sizes/font_size = 18 +horizontal_alignment = 1 +vertical_alignment = 1 +autowrap_mode = 2 diff --git a/Scripts/ConveyerController.gd b/Scripts/ConveyerController.gd index e7c6fc0..ac78ffb 100644 --- a/Scripts/ConveyerController.gd +++ b/Scripts/ConveyerController.gd @@ -49,6 +49,7 @@ func create_conveyor(): func send_event(): print("sending events!") + ToastManager.info("📦 Dispatching...") self.started = true if conveyerInd!=0: for n in events.size(): diff --git a/Scripts/SinkClick.gd b/Scripts/SinkClick.gd index 35de978..3e3af54 100644 --- a/Scripts/SinkClick.gd +++ b/Scripts/SinkClick.gd @@ -7,6 +7,7 @@ func _input_event(viewport, event, shape_idx): func on_click(): print("hey") AudioManager.play_click_end() + ToastManager.toast("Route connected!") ConveyerController.destination.append(get_parent().get_position()) transfer_box() @@ -25,4 +26,7 @@ func _on_area_entered(area: Area2D) -> void: print(get_parent().expectedType) if area.get_parent().boxType != get_parent().expectedType: print("Not Expected Box") + ToastManager.warning("⚠️ Type mismatch!") Level.sinkBoxMatchPresent=false + else: + ToastManager.success("✅ Delivered!") diff --git a/Scripts/ToastManager.gd b/Scripts/ToastManager.gd new file mode 100644 index 0000000..5879709 --- /dev/null +++ b/Scripts/ToastManager.gd @@ -0,0 +1,88 @@ +extends CanvasLayer + +# ToastManager - Global autoload for showing toast notifications +# Usage: ToastManager.show("Message") or ToastManager.success("Yay!") + +const TOAST_SCENE = preload("res://Scenes/toast.tscn") + +# Toast colors +const COLOR_DEFAULT = Color(0.2, 0.2, 0.2, 0.9) +const COLOR_SUCCESS = Color(0.18, 0.55, 0.34, 0.95) +const COLOR_ERROR = Color(0.7, 0.2, 0.2, 0.95) +const COLOR_INFO = Color(0.2, 0.4, 0.7, 0.95) +const COLOR_WARNING = Color(0.8, 0.6, 0.2, 0.95) + +# Toast positioning +var toast_margin: int = 20 +var toast_spacing: int = 10 +var active_toasts: Array = [] + +func _ready() -> void: + # Set layer to be on top of everything + layer = 100 + +# Show a default toast +func toast(message: String, duration: float = 2.0) -> void: + _create_toast(message, duration, COLOR_DEFAULT) + +# Show a success toast (green) +func success(message: String, duration: float = 2.0) -> void: + _create_toast(message, duration, COLOR_SUCCESS) + +# Show an error toast (red) +func error(message: String, duration: float = 2.5) -> void: + _create_toast(message, duration, COLOR_ERROR) + +# Show an info toast (blue) +func info(message: String, duration: float = 2.0) -> void: + _create_toast(message, duration, COLOR_INFO) + +# Show a warning toast (orange) +func warning(message: String, duration: float = 2.0) -> void: + _create_toast(message, duration, COLOR_WARNING) + +func _create_toast(message: String, duration: float, color: Color) -> void: + var toast = TOAST_SCENE.instantiate() + add_child(toast) + + # Setup toast content + toast.setup(message, duration, color) + + # Position at bottom center of screen + var viewport_size = get_viewport().get_visible_rect().size + var toast_width = 300 + var toast_height = 60 + + # Calculate vertical position based on active toasts + var y_offset = toast_margin + (active_toasts.size() * (toast_height + toast_spacing)) + + toast.position = Vector2( + (viewport_size.x - toast_width) / 2, + viewport_size.y - toast_height - y_offset + ) + + # Track active toast + active_toasts.append(toast) + toast.tree_exited.connect(_on_toast_removed.bind(toast)) + + # Show with animation + toast.show_toast() + +func _on_toast_removed(toast: Control) -> void: + active_toasts.erase(toast) + # Reposition remaining toasts + _reposition_toasts() + +func _reposition_toasts() -> void: + var viewport_size = get_viewport().get_visible_rect().size + var toast_height = 60 + + for i in active_toasts.size(): + var toast = active_toasts[i] + if is_instance_valid(toast): + var y_offset = toast_margin + (i * (toast_height + toast_spacing)) + var target_y = viewport_size.y - toast_height - y_offset + + # Animate repositioning + var tween = create_tween() + tween.tween_property(toast, "position:y", target_y, 0.2).set_ease(Tween.EASE_OUT) diff --git a/Scripts/event_button.gd b/Scripts/event_button.gd index 37fba59..d3da8bc 100644 --- a/Scripts/event_button.gd +++ b/Scripts/event_button.gd @@ -12,5 +12,6 @@ func _process(delta: float) -> void: func _on_button_pressed() -> void: + ToastManager.info("▶️ Started!") Level.initialise() ConveyerController.can_send = true diff --git a/Scripts/level.gd b/Scripts/level.gd index 5565b4c..105db4f 100644 --- a/Scripts/level.gd +++ b/Scripts/level.gd @@ -34,21 +34,23 @@ func next_level(): if nextLevel: print("success") AudioManager.play_level_clear() + ToastManager.success("🎉 Level Complete!") message_display.show_message("Success") await message_display.show_message_for_duration(2.0) message_display.visible = false levelind+=1 if levelind!=levels.size(): - # CRITICAL FIXInitialize BEFORE changing scene, not after! ConveyerController.initialise() var next_level_path="res://Scenes/"+levels[levelind]+".tscn" get_tree().change_scene_to_file(next_level_path) else: print("End of Levels.") + ToastManager.success("🏆 All Levels Complete!") get_tree().change_scene_to_file("res://Scenes/end_of_all_levels.tscn") else: print("Failed. Try Again") AudioManager.play_level_fail() + ToastManager.error("❌ Wrong destination!") message_display.show_message("Failed. Try Again") await message_display.show_message_for_duration(2.0) message_display.visible = false diff --git a/Scripts/restart.gd b/Scripts/restart.gd index 9056d8e..d2d8b83 100644 --- a/Scripts/restart.gd +++ b/Scripts/restart.gd @@ -12,6 +12,7 @@ func _process(delta: float) -> void: func _on_button_pressed() -> void: print("restart clicked") + ToastManager.toast("Restarting...") #if not Level.nextLevel: #Level.levelind-=1 Level.initialise() diff --git a/Scripts/toast.gd b/Scripts/toast.gd new file mode 100644 index 0000000..25c7634 --- /dev/null +++ b/Scripts/toast.gd @@ -0,0 +1,42 @@ +extends Control + +# Toast notification - individual toast instance +var duration: float = 2.0 + +func _ready() -> void: + # Start invisible for fade-in + modulate.a = 0.0 + +func setup(message: String, toast_duration: float = 2.0, color: Color = Color(0.2, 0.2, 0.2, 0.9)) -> void: + duration = toast_duration + $Panel/Label.text = message + + # Set panel color based on toast type + var style = StyleBoxFlat.new() + style.bg_color = color + style.corner_radius_top_left = 8 + style.corner_radius_top_right = 8 + style.corner_radius_bottom_left = 8 + style.corner_radius_bottom_right = 8 + style.content_margin_left = 15 + style.content_margin_right = 15 + style.content_margin_top = 10 + style.content_margin_bottom = 10 + $Panel.add_theme_stylebox_override("panel", style) + +func show_toast() -> void: + # Fade in + var tween_in = create_tween() + tween_in.tween_property(self, "modulate:a", 1.0, 0.3).set_ease(Tween.EASE_OUT) + await tween_in.finished + + # Wait for duration + await get_tree().create_timer(duration).timeout + + # Fade out + var tween_out = create_tween() + tween_out.tween_property(self, "modulate:a", 0.0, 0.3).set_ease(Tween.EASE_IN) + await tween_out.finished + + # Remove self + queue_free() diff --git a/project.godot b/project.godot index fdbdc1c..331a7c8 100644 --- a/project.godot +++ b/project.godot @@ -8,11 +8,15 @@ config_version=5 +[animation] + +compatibility/default_parent_skeleton_in_mesh_instance_3d=true + [application] config/name="eventing-game" run/main_scene="res://Scenes/basicEventFlow.tscn" -config/features=PackedStringArray("4.3", "GL Compatibility") +config/features=PackedStringArray("4.6", "GL Compatibility") config/icon="res://icon.svg" [autoload] @@ -20,6 +24,7 @@ config/icon="res://icon.svg" ConveyerController="*res://Scripts/ConveyerController.gd" Level="*res://Scripts/level.gd" AudioManager="*res://Scripts/AudioManager.gd" +ToastManager="*res://Scripts/ToastManager.gd" [input]