diff --git a/Dunkanoid.gd b/Dunkanoid.gd index 8be5dca..e721f58 100644 --- a/Dunkanoid.gd +++ b/Dunkanoid.gd @@ -29,6 +29,10 @@ var _Coin = preload("res://Coin/Coin.tscn") @onready var CoinCollectedSoundNode = $Sounds/CoinCollected @onready var TokenLabelNode = $Tokens/TokenLabel +var _Aliens : Array = [ + preload("res://Alien.tscn") +] + var bricks : Array = [] var balls : Array[Node] = [] @@ -424,7 +428,7 @@ func spawn_alien() -> void: func _on_pipes_door_opened(door) -> void: match door: Pipes.TOP_LEFT: - var alien = _Alien.instantiate() + var alien = _Aliens.pick_random().instantiate() alien.position = Vector2(96, -12) alien.velocity = Vector2(0, 50) alien.alien_died.connect(_alien_died) @@ -432,7 +436,7 @@ func _on_pipes_door_opened(door) -> void: get_tree().create_timer(2).timeout.connect(_close_top_left) pass Pipes.TOP_RIGHT: - var alien = _Alien.instantiate() + var alien = _Aliens.pick_random().instantiate() alien.position = Vector2(352, -12) alien.velocity = Vector2(0, 50) alien.alien_died.connect(_alien_died) diff --git a/ExitButton.gd b/ExitButton.gd index a85e3c9..eba6abc 100644 --- a/ExitButton.gd +++ b/ExitButton.gd @@ -1,4 +1,4 @@ -extends HBoxContainer +extends Button func _ready() -> void: visible = not OS.has_feature("web") diff --git a/Intro.gd b/Intro.gd index c0a107d..c6ee792 100644 --- a/Intro.gd +++ b/Intro.gd @@ -20,7 +20,7 @@ func _ready() -> void: EventBus.update_highscore.connect(_on_update_highscore) _on_update_score(Global.score) _on_update_highscore(Global.highscore) - $VBoxContainer/Play/Play.grab_focus() + $VBoxContainer/Play/VBoxContainer/Play.grab_focus() Music.play_intro() get_tree().create_timer(5).timeout.connect(_show_credits) diff --git a/Intro.tscn b/Intro.tscn index c261aa1..bc81f4a 100644 --- a/Intro.tscn +++ b/Intro.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=13 format=3 uid="uid://c2oboya05agti"] +[gd_scene load_steps=15 format=3 uid="uid://c2oboya05agti"] [ext_resource type="Script" path="res://Intro.gd" id="1_1hnh1"] [ext_resource type="Theme" uid="uid://cfvww0geatnnk" path="res://MainTheme.tres" id="3_8d2ix"] @@ -7,7 +7,9 @@ [ext_resource type="Script" path="res://ExitButton.gd" id="4_ty0na"] [ext_resource type="Texture2D" uid="uid://b56kjbt4ub52n" path="res://NoidTex.png" id="4_v8i0c"] [ext_resource type="PackedScene" uid="uid://deyotp28r4uwj" path="res://LoadPanel.tscn" id="5_esv62"] +[ext_resource type="Script" path="res://Level.gd" id="6_hw2gq"] [ext_resource type="SpriteFrames" uid="uid://c6wwkgmwfpdu7" path="res://Coin/Coin.tres" id="7_2tpc7"] +[ext_resource type="Script" path="res://Preview.gd" id="9_x2ejj"] [sub_resource type="Curve" id="Curve_jhhjd"] min_value = -200.0 @@ -114,109 +116,47 @@ layout_mode = 2 size_flags_horizontal = 3 theme = ExtResource("3_8d2ix") -[node name="Play" type="Button" parent="VBoxContainer/Play"] +[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/Play"] +layout_mode = 2 + +[node name="Play" type="Button" parent="VBoxContainer/Play/VBoxContainer"] layout_mode = 2 theme = ExtResource("3_8d2ix") text = "PLAY" icon_alignment = 1 -[node name="HSeparator2" type="HSeparator" parent="VBoxContainer/Play"] -layout_mode = 2 -size_flags_horizontal = 3 -theme = ExtResource("3_8d2ix") - -[node name="PlayLevel" type="HBoxContainer" parent="VBoxContainer"] -layout_mode = 2 - -[node name="HSeparator" type="HSeparator" parent="VBoxContainer/PlayLevel"] -layout_mode = 2 -size_flags_horizontal = 3 -theme = ExtResource("3_8d2ix") - -[node name="PlayLevel" type="Button" parent="VBoxContainer/PlayLevel"] +[node name="PlayLevel" type="Button" parent="VBoxContainer/Play/VBoxContainer"] layout_mode = 2 theme = ExtResource("3_8d2ix") text = "PLAY LEVEL" icon_alignment = 1 -[node name="HSeparator2" type="HSeparator" parent="VBoxContainer/PlayLevel"] -layout_mode = 2 -size_flags_horizontal = 3 -theme = ExtResource("3_8d2ix") - -[node name="Upgrades" type="HBoxContainer" parent="VBoxContainer"] -layout_mode = 2 - -[node name="HSeparator" type="HSeparator" parent="VBoxContainer/Upgrades"] -layout_mode = 2 -size_flags_horizontal = 3 -theme = ExtResource("3_8d2ix") - -[node name="Upgrades" type="Button" parent="VBoxContainer/Upgrades"] +[node name="Upgrades" type="Button" parent="VBoxContainer/Play/VBoxContainer"] layout_mode = 2 theme = ExtResource("3_8d2ix") text = "UPGRADES" icon_alignment = 1 -[node name="HSeparator2" type="HSeparator" parent="VBoxContainer/Upgrades"] -layout_mode = 2 -size_flags_horizontal = 3 -theme = ExtResource("3_8d2ix") - -[node name="LevelEditor" type="HBoxContainer" parent="VBoxContainer"] -layout_mode = 2 - -[node name="HSeparator" type="HSeparator" parent="VBoxContainer/LevelEditor"] -layout_mode = 2 -size_flags_horizontal = 3 -theme = ExtResource("3_8d2ix") - -[node name="Editor" type="Button" parent="VBoxContainer/LevelEditor"] +[node name="Editor" type="Button" parent="VBoxContainer/Play/VBoxContainer"] layout_mode = 2 theme = ExtResource("3_8d2ix") text = "LEVEL EDITOR" icon_alignment = 1 -[node name="HSeparator2" type="HSeparator" parent="VBoxContainer/LevelEditor"] -layout_mode = 2 -size_flags_horizontal = 3 -theme = ExtResource("3_8d2ix") - -[node name="Settings" type="HBoxContainer" parent="VBoxContainer"] -layout_mode = 2 - -[node name="HSeparator" type="HSeparator" parent="VBoxContainer/Settings"] -layout_mode = 2 -size_flags_horizontal = 3 -theme = ExtResource("3_8d2ix") - -[node name="Settings" type="Button" parent="VBoxContainer/Settings"] +[node name="Settings" type="Button" parent="VBoxContainer/Play/VBoxContainer"] layout_mode = 2 theme = ExtResource("3_8d2ix") text = "SETTINGS" icon_alignment = 1 -[node name="HSeparator2" type="HSeparator" parent="VBoxContainer/Settings"] -layout_mode = 2 -size_flags_horizontal = 3 -theme = ExtResource("3_8d2ix") - -[node name="ExitButton" type="HBoxContainer" parent="VBoxContainer"] -layout_mode = 2 -script = ExtResource("4_ty0na") - -[node name="HSeparator" type="HSeparator" parent="VBoxContainer/ExitButton"] -layout_mode = 2 -size_flags_horizontal = 3 -theme = ExtResource("3_8d2ix") - -[node name="Exit" type="Button" parent="VBoxContainer/ExitButton"] +[node name="Exit" type="Button" parent="VBoxContainer/Play/VBoxContainer"] layout_mode = 2 theme = ExtResource("3_8d2ix") text = "EXIT" icon_alignment = 1 +script = ExtResource("4_ty0na") -[node name="HSeparator2" type="HSeparator" parent="VBoxContainer/ExitButton"] +[node name="HSeparator2" type="HSeparator" parent="VBoxContainer/Play"] layout_mode = 2 size_flags_horizontal = 3 theme = ExtResource("3_8d2ix") @@ -315,10 +255,39 @@ offset_top = 116.0 offset_right = 399.0 offset_bottom = 297.0 -[connection signal="pressed" from="VBoxContainer/Play/Play" to="." method="_on_button_pressed"] -[connection signal="pressed" from="VBoxContainer/PlayLevel/PlayLevel" to="." method="_on_play_level_pressed"] -[connection signal="pressed" from="VBoxContainer/Upgrades/Upgrades" to="." method="_on_upgrades_pressed"] -[connection signal="pressed" from="VBoxContainer/LevelEditor/Editor" to="." method="_on_editor_pressed"] -[connection signal="pressed" from="VBoxContainer/Settings/Settings" to="." method="_on_settings_pressed"] -[connection signal="pressed" from="VBoxContainer/ExitButton/Exit" to="." method="_on_exit_pressed"] +[node name="Preview" type="Node2D" parent="."] +modulate = Color(1, 1, 1, 0) +script = ExtResource("9_x2ejj") + +[node name="SubViewportContainer" type="SubViewportContainer" parent="Preview"] +offset_left = 68.0 +offset_top = 124.0 +offset_right = 516.0 +offset_bottom = 484.0 +scale = Vector2(0.3, 0.3) +stretch = true + +[node name="Level" type="SubViewport" parent="Preview/SubViewportContainer"] +handle_input_locally = false +size = Vector2i(448, 360) +render_target_update_mode = 4 +script = ExtResource("6_hw2gq") + +[node name="Label" type="Label" parent="Preview"] +offset_left = 68.0 +offset_top = 238.0 +offset_right = 202.0 +offset_bottom = 261.0 +theme = ExtResource("3_8d2ix") +theme_type_variation = &"Numbers" +text = "00:00.00" +horizontal_alignment = 1 +vertical_alignment = 1 + +[connection signal="pressed" from="VBoxContainer/Play/VBoxContainer/Play" to="." method="_on_button_pressed"] +[connection signal="pressed" from="VBoxContainer/Play/VBoxContainer/PlayLevel" to="." method="_on_play_level_pressed"] +[connection signal="pressed" from="VBoxContainer/Play/VBoxContainer/Upgrades" to="." method="_on_upgrades_pressed"] +[connection signal="pressed" from="VBoxContainer/Play/VBoxContainer/Editor" to="." method="_on_editor_pressed"] +[connection signal="pressed" from="VBoxContainer/Play/VBoxContainer/Settings" to="." method="_on_settings_pressed"] +[connection signal="pressed" from="VBoxContainer/Play/VBoxContainer/Exit" to="." method="_on_exit_pressed"] [connection signal="load_level" from="LoadPanel" to="." method="_on_load_panel_load_level"] diff --git a/Level.gd b/Level.gd new file mode 100644 index 0000000..eca0895 --- /dev/null +++ b/Level.gd @@ -0,0 +1,129 @@ +@tool +extends SubViewport + +class_name Level + +signal level_cleared +signal brick_destroyed(brick : Node2D) + +var _Brick = preload("res://Brick/Brick.tscn") + +var Background : TextureRect +var BricksNode : Node2D + +var bricks : Array = [] +var level_data : Dictionary = {} + +@export var LevelName : String = "DUNKANOID" : + set(x): + LevelName = x + load_level(LevelName) + + + +func _ready() -> void: + size = Vector2(448, 360) + + Background = TextureRect.new() + Background.size = Vector2(448, 360) + Background.expand_mode = TextureRect.EXPAND_KEEP_SIZE + Background.stretch_mode = TextureRect.STRETCH_TILE + Background.z_index = -2 + add_child(Background) + + BricksNode = Node2D.new() + add_child(BricksNode) + + load_level(LevelName) + #Background = TextureRect.new() + #Background.size = Vector2(448, 360) + #Background.expand_mode = TextureRect.EXPAND_KEEP_SIZE + #Background.stretch_mode = TextureRect.STRETCH_TILE + #Background.z_index = -2 + #add_child(Background) + # + #BricksNode = Node2D.new() + #add_child(BricksNode) + +func load_level(level_name : String) -> void: + if FileAccess.file_exists("user://Levels/%s.json" % level_name): + load_from_file("user://Levels/%s.json" % level_name) + return + if FileAccess.file_exists("res://Levels/%s.json" % level_name): + load_from_file("res://Levels/%s.json" % level_name) + return + push_warning("Level %s unknown" % level_name) + +func load_from_file(filename : String) -> void: + print("Loading %s" % filename) + var data = JSON.parse_string(FileAccess.get_file_as_string(filename)) + if data != null: + load_from_data(data) + return + push_warning("Corrupt JSON in %s" % filename) + +func load_from_data(data : Dictionary) -> void: + purge_bricks() + level_data = data + Background.texture = load("res://Backgrounds/%s.png" % level_data.background) + Background.modulate = Color("#%s" % level_data.get("tint", "FFFFFF")) + for y in level_data.data.size(): + var line : String = level_data.data[y] + for x in line.length(): + var c = line.substr(x, 1) + if c == " ": + continue + + if not Engine.is_editor_hint(): + var brick = _Brick.instantiate() + match c: + "R": + brick.type(Brick.NORMAL, Color.RED) + "G": + brick.type(Brick.NORMAL, Color.GREEN) + "Y": + brick.type(Brick.NORMAL, Color.YELLOW) + "B": + brick.type(Brick.NORMAL, Color.ROYAL_BLUE) + "M": + brick.type(Brick.NORMAL, Color.MAGENTA) + "C": + brick.type(Brick.NORMAL, Color.CYAN) + "W": + brick.type(Brick.NORMAL, Color.WHITE) + "O": + brick.type(Brick.NORMAL, Color.ORANGE) + "s": + brick.type(Brick.SILVER, Color.SILVER) + "g": + brick.type(Brick.GOLD, Color.GOLD) + "i": + brick.type(Brick.INVULNERABLE, Color.GRAY) + + brick.position = Vector2(x * 32 + 16 + 16, y * 16 + 8 + 16) + bricks.push_back(brick) + brick.brick_destroyed.connect(_brick_destroyed) + BricksNode.add_child(brick) + + +func purge_bricks() -> void: + for brick in bricks: + BricksNode.call_deferred("remove_child", brick) + brick.call_deferred("queue_free") + bricks.clear() + +func _brick_destroyed(brick : Node2D) -> void: + + if brick.my_type != Brick.INVULNERABLE: + brick_destroyed.emit(brick) + bricks.erase(brick) + BricksNode.call_deferred("remove_child", brick) + brick.call_deferred("queue_free") + + var brick_count = 0 + for abrick in bricks: + if abrick.my_type != Brick.INVULNERABLE: + brick_count += 1 + + if brick_count == 0: + level_cleared.emit() diff --git a/LevelPreview.gd b/LevelPreview.gd new file mode 100644 index 0000000..545e553 --- /dev/null +++ b/LevelPreview.gd @@ -0,0 +1,26 @@ +@tool +extends TextureRect + +class_name LevelPreview + +@export var LevelName : String = "DUNKANOID" : + set(x): + LevelName = x + update_preview() + +func _ready() -> void: + update_preview() + +func update_preview() -> void: + var level = Level.new() + level.load_level(LevelName) + add_child(level) + await RenderingServer.frame_post_draw + + var img = level.get_texture().get_image() + var itex = ImageTexture.create_from_image(img) + texture = itex +# remove_child(level) +# sv.queue_free() +# level.call_deferred("queue_free") + queue_redraw() diff --git a/Preview.gd b/Preview.gd new file mode 100644 index 0000000..d0bb1ba --- /dev/null +++ b/Preview.gd @@ -0,0 +1,46 @@ +extends Node2D + +func _ready() -> void: + get_tree().create_timer(5).timeout.connect(_show_level) + +func _show_level() -> void: + var level = get_random_level() + $Label.text = format_time(Global.get_best_time(level)) + $SubViewportContainer/Level.load_level(level) + var tween = get_tree().create_tween() + tween.tween_property(self, "modulate", Color(1, 1, 1, 1), 1) + tween.finished.connect(_wait_showing) + +func _wait_showing() -> void: + get_tree().create_timer(5).timeout.connect(_hide_level) + +func _hide_level() -> void: + var tween = get_tree().create_tween() + tween.tween_property(self, "modulate", Color(1, 1, 1, 0), 1) + tween.finished.connect(_wait_hiding) + +func _wait_hiding() -> void: + get_tree().create_timer(5).timeout.connect(_show_level) + + +func get_random_level() -> String: + var levels : Array[String] = [] + if DirAccess.dir_exists_absolute("user://Levels"): + for file in DirAccess.get_files_at("user://Levels"): + if file.ends_with(".json"): + var data = JSON.parse_string(FileAccess.get_file_as_string("user://Levels/%s" % file)) + if data != null: + levels.push_back(data.get("name")) + for file in DirAccess.get_files_at("res://Levels"): + if file.ends_with(".json"): + var data = JSON.parse_string(FileAccess.get_file_as_string("res://Levels/%s" % file)) + if data != null: + if not levels.has(data.get("name")): + levels.push_back(data.get("name")) + levels.erase("NOTFOUND") + return levels.pick_random() + +func format_time(time : int) -> String: + if time > 3600000: + return "--:--.--" + return "%02d:%05.2f" % [int(time / 60000.0), time % 60000 / 1000.0] diff --git a/Upgrades.tscn b/Upgrades.tscn index d96a469..89212b3 100644 --- a/Upgrades.tscn +++ b/Upgrades.tscn @@ -17,7 +17,7 @@ point_count = 2 [sub_resource type="Gradient" id="Gradient_ucorl"] colors = PackedColorArray(0, 0, 0, 0, 1, 1, 1, 1) -[sub_resource type="ShaderMaterial" id="ShaderMaterial_1rhte"] +[sub_resource type="ShaderMaterial" id="ShaderMaterial_6weej"] shader = ExtResource("4_waenw") shader_parameter/rect_global_position = Vector2(0.012945, 0.0794118) shader_parameter/rect_size = Vector2(608, 25) @@ -75,7 +75,7 @@ autoplay = "default" centered = false [node name="ArkaLabel" type="Label" parent="VBoxContainer"] -material = SubResource("ShaderMaterial_1rhte") +material = SubResource("ShaderMaterial_6weej") layout_mode = 2 size_flags_vertical = 6 theme = ExtResource("1_rv7oa") diff --git a/project.godot b/project.godot index d4e33b7..22bf1a6 100644 --- a/project.godot +++ b/project.godot @@ -11,7 +11,7 @@ config_version=5 [application] config/name="Dunkanoid" -config/version="0.9.0" +config/version="0.9.2" run/main_scene="res://Intro.tscn" config/features=PackedStringArray("4.2", "Forward Plus") run/max_fps=30