diff --git a/project.godot b/project.godot index 439716e..bf1e982 100644 --- a/project.godot +++ b/project.godot @@ -17,7 +17,7 @@ warnings/check_angle_interpolation_type_conflicting=false config/name="Liberation of the Neighbourville" config/version="0.3.0" -run/main_scene="uid://boxt0hfowqe66" +run/main_scene="uid://bh1yiiv1fi0b8" config/features=PackedStringArray("4.4", "Forward Plus") config/icon="res://icon.png" config/windows_native_icon="res://icon.ico" @@ -44,6 +44,12 @@ enabled=PackedStringArray() import/blender/enabled=false +[global_group] + +Plants="Mostly player's means of defence" +Zombies="Agressors of player" +Projectile="Something that has ben shot" + [gui] theme/custom_font="res://assets/fonts/pico12.ttf" diff --git a/resources/plants/aloe.tres b/resources/plants/aloe.tres index fcb0b68..0b41558 100644 --- a/resources/plants/aloe.tres +++ b/resources/plants/aloe.tres @@ -1,7 +1,8 @@ -[gd_resource type="Resource" script_class="SeedpacketResource" load_steps=3 format=3 uid="uid://d1nwlatkrtkpe"] +[gd_resource type="Resource" script_class="SeedpacketResource" load_steps=4 format=3 uid="uid://d1nwlatkrtkpe"] [ext_resource type="Script" uid="uid://dtjdfji87kybn" path="res://scripts/resources/entity_resource.gd" id="1_giqbo"] [ext_resource type="Texture2D" uid="uid://d4btl7vqi4v0q" path="res://assets/sprites/plants/aloe.tres" id="1_qou1a"] +[ext_resource type="PackedScene" uid="uid://dba4s3ke32u0l" path="res://scenes/plants/aloe.tscn" id="2_6p2kr"] [resource] script = ExtResource("1_giqbo") @@ -9,5 +10,6 @@ preview = ExtResource("1_qou1a") cost = 75.0 recharge_time = 5.0 initial_recharge_percent = 1.0 +scene = ExtResource("2_6p2kr") order = 0 metadata/_custom_type_script = "uid://dtjdfji87kybn" diff --git a/scenes/gui/plants_pick_test.tscn b/scenes/gui/plants_pick_test.tscn deleted file mode 100644 index bbd6c7d..0000000 --- a/scenes/gui/plants_pick_test.tscn +++ /dev/null @@ -1,34 +0,0 @@ -[gd_scene load_steps=4 format=3 uid="uid://boxt0hfowqe66"] - -[ext_resource type="Script" uid="uid://crlumefuo1biu" path="res://scripts/gui/plant_pick/seedpacket_generator.gd" id="1_celhi"] -[ext_resource type="Script" uid="uid://co3yto3q7mnm7" path="res://scripts/level/level_data.gd" id="2_pdbkq"] -[ext_resource type="Script" uid="uid://cbrhnb4tp4pem" path="res://scripts/gui/hotbar.gd" id="3_qyndx"] - -[node name="PlantsPickTest" type="Control"] -layout_mode = 3 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 - -[node name="GridContainer" type="GridContainer" parent="."] -layout_mode = 0 -anchor_left = 0.27 -anchor_top = 0.48 -anchor_right = 0.74 -anchor_bottom = 0.94 -columns = 3 -script = ExtResource("1_celhi") -metadata/_edit_use_anchors_ = true - -[node name="LevelData" type="Node" parent="."] -script = ExtResource("2_pdbkq") - -[node name="HBoxContainer" type="HBoxContainer" parent="."] -layout_mode = 0 -offset_left = 69.0 -offset_top = 12.0 -offset_right = 479.0 -offset_bottom = 75.0 -script = ExtResource("3_qyndx") diff --git a/scenes/gui/seedpacket.tscn b/scenes/gui/seedpacket.tscn index 810d4c0..c0a72ab 100644 --- a/scenes/gui/seedpacket.tscn +++ b/scenes/gui/seedpacket.tscn @@ -137,5 +137,6 @@ grow_vertical = 2 texture = SubResource("AtlasTexture_gtmhg") [node name="RechargeTimer" type="Timer" parent="."] +one_shot = true [connection signal="pressed" from="TextureButton" to="." method="on_pressed"] diff --git a/scenes/levels/standard_level.tscn b/scenes/levels/standard_level.tscn new file mode 100644 index 0000000..809492b --- /dev/null +++ b/scenes/levels/standard_level.tscn @@ -0,0 +1,71 @@ +[gd_scene load_steps=9 format=3 uid="uid://bh1yiiv1fi0b8"] + +[ext_resource type="Texture2D" uid="uid://b0tb2hjum40aw" path="res://assets/sprites/background_summer.png" id="1_3bchh"] +[ext_resource type="Script" uid="uid://cj8mt02far5np" path="res://scripts/level/field_rect_offsetter.gd" id="1_4dbyi"] +[ext_resource type="Script" uid="uid://cyttjwv888cb4" path="res://scripts/level/layered_entity_container.gd" id="1_ia5ss"] +[ext_resource type="Script" uid="uid://co3yto3q7mnm7" path="res://scripts/level/level_data.gd" id="1_ssqyj"] +[ext_resource type="Script" uid="uid://sjnxv5q4yk2" path="res://scripts/level/seedpacket_placer.gd" id="4_5r585"] +[ext_resource type="Script" uid="uid://crlumefuo1biu" path="res://scripts/gui/plant_pick/seedpacket_generator.gd" id="6_2y6d3"] +[ext_resource type="Script" uid="uid://cbrhnb4tp4pem" path="res://scripts/gui/plant_pick/hotbar.gd" id="7_e4b3h"] +[ext_resource type="Script" uid="uid://60lwfjb634kd" path="res://scripts/gui/plant_pick/go_button.gd" id="8_e4b3h"] + +[node name="StandardLevel" type="Node"] + +[node name="Data" type="Node" parent="."] +script = ExtResource("1_ssqyj") +metadata/_custom_type_script = "uid://co3yto3q7mnm7" + +[node name="LayeredEntityContainer" type="Node" parent="."] +script = ExtResource("1_ia5ss") + +[node name="Game" type="Node2D" parent="."] + +[node name="Field Start" type="Marker2D" parent="Game"] +position = Vector2(305, 76) +script = ExtResource("1_4dbyi") +metadata/_edit_lock_ = true + +[node name="SeedpacketPlacer" type="CanvasGroup" parent="Game" node_paths=PackedStringArray("entity_container")] +script = ExtResource("4_5r585") +entity_container = NodePath("../../LayeredEntityContainer") + +[node name="Plants" type="Node2D" parent="Game"] +unique_name_in_owner = true + +[node name="Background" type="CanvasLayer" parent="Game"] +layer = -10 +follow_viewport_enabled = true + +[node name="BackgroundSummer" type="Sprite2D" parent="Game/Background"] +texture = ExtResource("1_3bchh") +centered = false +metadata/_edit_lock_ = true + +[node name="Camera2D" type="Camera2D" parent="Game"] +position = Vector2(517, 206) + +[node name="User Interface" type="CanvasLayer" parent="."] +layer = 5 +metadata/_edit_lock_ = true + +[node name="GridContainer" type="GridContainer" parent="User Interface"] +offset_left = -1.0 +offset_top = 216.0 +offset_right = 257.0 +offset_bottom = 401.0 +columns = 5 +script = ExtResource("6_2y6d3") + +[node name="Hotbar" type="HBoxContainer" parent="User Interface"] +offset_left = -1.0 +offset_top = -2.0 +offset_right = 365.0 +offset_bottom = 65.0 +script = ExtResource("7_e4b3h") + +[node name="Button" type="Button" parent="User Interface"] +offset_top = 178.0 +offset_right = 124.0 +offset_bottom = 210.0 +text = "next state" +script = ExtResource("8_e4b3h") diff --git a/scenes/plants/aloe.tscn b/scenes/plants/aloe.tscn new file mode 100644 index 0000000..db2640a --- /dev/null +++ b/scenes/plants/aloe.tscn @@ -0,0 +1,15 @@ +[gd_scene load_steps=3 format=3 uid="uid://dba4s3ke32u0l"] + +[ext_resource type="Texture2D" uid="uid://d4btl7vqi4v0q" path="res://assets/sprites/plants/aloe.tres" id="1_38l32"] +[ext_resource type="Script" uid="uid://bwdvaov8sse4k" path="res://scripts/entities/entity.gd" id="1_yhqjp"] + +[node name="Aloe" type="Node2D" groups=["Plants"]] + +[node name="Entity" type="Node" parent="."] +script = ExtResource("1_yhqjp") +max_hp = 30.0 +layer = &"base" +metadata/_custom_type_script = "uid://bwdvaov8sse4k" + +[node name="Sprite2D" type="Sprite2D" parent="."] +texture = ExtResource("1_38l32") diff --git a/scripts/autoloads/level_event_bus.gd b/scripts/autoloads/level_event_bus.gd index a05e765..77f3166 100644 --- a/scripts/autoloads/level_event_bus.gd +++ b/scripts/autoloads/level_event_bus.gd @@ -20,6 +20,11 @@ signal entity_killed(context : Entity.KilledContext) ## Called for every entity that gets damage signal entity_hp_changed(context : Entity.HPChangedContext) +## Called for every entity that has layer set that enters game +signal layer_entity_created(entity : Entity) +## Called for every entity that has layer set that exits game +signal layer_entity_killed(entity : Entity.KilledContext) + #endregion #region Seedpacket manipulation @@ -27,6 +32,9 @@ signal entity_hp_changed(context : Entity.HPChangedContext) ## Called when player selects SeedpacketResource signal packet_selected(resource : SeedpacketResource) +## Called when player deselects (usually loses focus) SeedpacketResource +signal packet_deselected(resource : SeedpacketResource) + ## Called when selected packets are updated signal hotbar_packets_update(selected : Array[SeedpacketResource]) #endregion diff --git a/scripts/autoloads/player_progress.gd b/scripts/autoloads/player_progress.gd new file mode 100644 index 0000000..c6b6a00 --- /dev/null +++ b/scripts/autoloads/player_progress.gd @@ -0,0 +1,4 @@ +extends Node + +var seedpacket_count : int +var owned_plants : Array[SeedpacketResource] diff --git a/scripts/autoloads/player_progress.gd.uid b/scripts/autoloads/player_progress.gd.uid new file mode 100644 index 0000000..46584fb --- /dev/null +++ b/scripts/autoloads/player_progress.gd.uid @@ -0,0 +1 @@ +uid://cjxsn8khrawb4 diff --git a/scripts/entities/entity.gd b/scripts/entities/entity.gd index fe9b860..2121b9b 100644 --- a/scripts/entities/entity.gd +++ b/scripts/entities/entity.gd @@ -5,6 +5,8 @@ class_name Entity ## Maximum health points of an entity. Any heal cannot exceed this value @export var max_hp : float +## Optional spawn layer for grid interactions +@export var layer : StringName = "" ## Current amount of health points of an entity. Cannot be below 0 or [code]max_hp[/code] var hp : float = max_hp @@ -67,6 +69,10 @@ func kill(source : Entity): context.target = self killed.emit(context) + LevelEventBus.entity_killed.emit(context) + if not layer.is_empty(): + LevelEventBus.layer_entity_killed.emit(context) + deconstruct() diff --git a/scripts/gui/plant_pick/go_button.gd b/scripts/gui/plant_pick/go_button.gd new file mode 100644 index 0000000..0b5914a --- /dev/null +++ b/scripts/gui/plant_pick/go_button.gd @@ -0,0 +1,5 @@ +extends Button + + +func _pressed() -> void: + LevelEventBus.state_advance_requested.emit() diff --git a/scripts/gui/plant_pick/go_button.gd.uid b/scripts/gui/plant_pick/go_button.gd.uid new file mode 100644 index 0000000..3809c87 --- /dev/null +++ b/scripts/gui/plant_pick/go_button.gd.uid @@ -0,0 +1 @@ +uid://60lwfjb634kd diff --git a/scripts/gui/hotbar.gd b/scripts/gui/plant_pick/hotbar.gd similarity index 100% rename from scripts/gui/hotbar.gd rename to scripts/gui/plant_pick/hotbar.gd diff --git a/scripts/gui/hotbar.gd.uid b/scripts/gui/plant_pick/hotbar.gd.uid similarity index 100% rename from scripts/gui/hotbar.gd.uid rename to scripts/gui/plant_pick/hotbar.gd.uid diff --git a/scripts/gui/seedpacket/hotbar_handler.gd b/scripts/gui/seedpacket/hotbar_handler.gd index 5fc311d..9fa2e5f 100644 --- a/scripts/gui/seedpacket/hotbar_handler.gd +++ b/scripts/gui/seedpacket/hotbar_handler.gd @@ -29,4 +29,4 @@ func on_level_state_changed(state : LevelData.LevelStates): func on_sun_count_updated(to : float): enough_sun = to >= seedpacket.held_resource.cost - + seedpacket.update_contents() diff --git a/scripts/gui/seedpacket/seedpacket.gd b/scripts/gui/seedpacket/seedpacket.gd index 19b40c3..1409530 100644 --- a/scripts/gui/seedpacket/seedpacket.gd +++ b/scripts/gui/seedpacket/seedpacket.gd @@ -16,6 +16,9 @@ class_name Seedpacket var held_resource : SeedpacketResource var handler : SeedpacketHandler +func _ready() -> void: + focus_exited.connect(on_focus_exited) + func _process(_delta: float) -> void: button.disabled = recharge_timer.time_left > 0 or handler.is_avaiable() == false @@ -45,3 +48,6 @@ func on_packet_placed(packet : SeedpacketResource): func disconnect_placement(): LevelEventBus.packet_placed.disconnect(on_packet_placed) focus_exited.disconnect(disconnect_placement) + +func on_focus_exited(): + LevelEventBus.packet_deselected.emit(held_resource) diff --git a/scripts/level/field_rect_offsetter.gd b/scripts/level/field_rect_offsetter.gd new file mode 100644 index 0000000..4c415b6 --- /dev/null +++ b/scripts/level/field_rect_offsetter.gd @@ -0,0 +1,6 @@ +extends Marker2D + + +func _ready() -> void: + FieldParams.field_rect.position = global_position + queue_free() diff --git a/scripts/level/field_rect_offsetter.gd.uid b/scripts/level/field_rect_offsetter.gd.uid new file mode 100644 index 0000000..c4fcccd --- /dev/null +++ b/scripts/level/field_rect_offsetter.gd.uid @@ -0,0 +1 @@ +uid://cj8mt02far5np diff --git a/scripts/level/layered_entity_container.gd b/scripts/level/layered_entity_container.gd new file mode 100644 index 0000000..031e800 --- /dev/null +++ b/scripts/level/layered_entity_container.gd @@ -0,0 +1,37 @@ +extends Node + +class_name LayeredEntityContainer + +var entities := { + "under" : [], + "base" : [], + "above" : [] +} + +func _ready() -> void: + LevelEventBus.layer_entity_created.connect(on_entity_spawned) + LevelEventBus.layer_entity_killed.connect(on_entity_killed) + + for layer in entities.keys(): + entities[layer].resize(FieldParams.COLUMNS * FieldParams.ROWS) + +## Checks if tile is occupied. [br] +## If position or layer are invalid, returns true +func is_occupied(position : int, layer : StringName) -> bool: + if position >= FieldParams.COLUMNS * FieldParams.ROWS or entities.has(layer) == false: return true + return not entities[layer][position] == null + +func on_entity_spawned(entity : Entity) -> void: + if entities.has(entity.layer) == false: return + + var index = FieldParams.indexify(entity.get_parent().global_position) + if index >= FieldParams.COLUMNS * FieldParams.ROWS or is_occupied(index,entity.layer): return + + entities[entity.layer][index] = entity + +func on_entity_killed(context : Entity.KilledContext) -> void: + var entity = context.target + var index = FieldParams.indexify(entity.get_parent().global_position) + if is_occupied(index,entity.layer) == false: return + + entities[entity.layer][index] = null diff --git a/scripts/level/layered_entity_container.gd.uid b/scripts/level/layered_entity_container.gd.uid new file mode 100644 index 0000000..f31f728 --- /dev/null +++ b/scripts/level/layered_entity_container.gd.uid @@ -0,0 +1 @@ +uid://cyttjwv888cb4 diff --git a/scripts/level/level_data.gd b/scripts/level/level_data.gd index 2cacf7c..9dbb10e 100644 --- a/scripts/level/level_data.gd +++ b/scripts/level/level_data.gd @@ -3,12 +3,35 @@ extends Node class_name LevelData static var state : LevelStates = LevelStates.NotInGame -static var sun_count : float +static var sun_count : float = 100 var hotbar_seedpackets : Array[SeedpacketResource] func _ready() -> void: - LevelEventBus.packet_selected.connect(on_seedpacket_clicked) + set_state(LevelStates.PlantPick) + LevelEventBus.state_advance_requested.connect(advance_state) + LevelEventBus.packet_placed.connect(on_packet_placed) + +func _exit_tree() -> void: + set_state(LevelStates.NotInGame) + +func advance_state() -> void: + set_state(state + 1) + +func set_state(to : LevelStates): + state = to + match state: + LevelStates.PlantPick: + LevelEventBus.packet_selected.connect(on_seedpacket_clicked) + LevelStates.Pregame: + LevelEventBus.packet_selected.disconnect(on_seedpacket_clicked) + LevelStates.Game: + pass + LevelStates.Postgame: + pass + LevelStates.NotInGame: + pass + LevelEventBus.state_changed.emit(state) func on_seedpacket_clicked(seedpacket : SeedpacketResource): if hotbar_seedpackets.has(seedpacket): @@ -17,6 +40,11 @@ func on_seedpacket_clicked(seedpacket : SeedpacketResource): hotbar_seedpackets.append(seedpacket) LevelEventBus.hotbar_packets_update.emit(hotbar_seedpackets) +func on_packet_placed(seedpacket : SeedpacketResource): + print(seedpacket) + sun_count -= seedpacket.cost + LevelEventBus.sun_count_updated.emit(sun_count) + ## Possible states of level enum LevelStates { ## The game is during plant pick stage @@ -27,6 +55,6 @@ enum LevelStates { Game, ## Game ended Postgame, - ## Not in a level, + ## Not in a level NotInGame } diff --git a/scripts/level/seedpacket_placer.gd b/scripts/level/seedpacket_placer.gd new file mode 100644 index 0000000..a934670 --- /dev/null +++ b/scripts/level/seedpacket_placer.gd @@ -0,0 +1,51 @@ +extends CanvasGroup + +@export var entity_container : LayeredEntityContainer +var can_plant : bool = false +var held_packet : SeedpacketResource = null + +func _ready() -> void: + LevelEventBus.state_changed.connect(on_level_state_changed) + LevelEventBus.packet_deselected.connect(on_seedpacket_deselected) + +func _process(_delta: float) -> void: + var mouse_pos = get_global_mouse_position() + var indexified_mouse = FieldParams.indexify(mouse_pos - FieldParams.field_rect.position) + if FieldParams.field_rect.has_point(mouse_pos) and entity_container.is_occupied(indexified_mouse,"base") == false: + global_position = FieldParams.deindexify(indexified_mouse) + FieldParams.TILE / 2.0 + FieldParams.field_rect.position + can_plant = true + else: + global_position = mouse_pos + can_plant = false + +func _input(event: InputEvent) -> void: + if held_packet != null and event.is_action_pressed("cancel_action"): + stop_placement() + + if held_packet != null and can_plant and event.is_action_pressed("primary_action"): + for child in get_children(): + child.reparent(get_tree().current_scene.get_node("%Plants")) + LevelEventBus.packet_placed.emit(held_packet) + held_packet = null + visible = false + +func on_seedpacket_selected(packet : SeedpacketResource) -> void: + add_child(packet.scene.instantiate()) + held_packet = packet + visible = true + +func on_seedpacket_deselected(packet : SeedpacketResource) -> void: + if packet == held_packet: + stop_placement() + +func on_level_state_changed(state : LevelData.LevelStates) -> void: + if state == LevelData.LevelStates.Game: + LevelEventBus.state_changed.disconnect(on_level_state_changed) + LevelEventBus.packet_selected.connect(on_seedpacket_selected) + + +func stop_placement(): + for child in get_children(): + child.queue_free() + held_packet = null + visible = false diff --git a/scripts/level/seedpacket_placer.gd.uid b/scripts/level/seedpacket_placer.gd.uid new file mode 100644 index 0000000..aba7ab2 --- /dev/null +++ b/scripts/level/seedpacket_placer.gd.uid @@ -0,0 +1 @@ +uid://sjnxv5q4yk2 diff --git a/scripts/utility/field_params.gd b/scripts/utility/field_params.gd new file mode 100644 index 0000000..4a01d2b --- /dev/null +++ b/scripts/utility/field_params.gd @@ -0,0 +1,23 @@ +extends Node + +## Utility class for field parameters and connected functions + +class_name FieldParams + +## Tile size +const TILE : Vector2 = Vector2(50,60) +## Rows count of field +const ROWS : int = 5 +## Columns count of field +const COLUMNS : int = 9 + +## Field rectangle. Origin is set in-game +static var field_rect : Rect2 = Rect2(0,0,COLUMNS*TILE.x,ROWS*TILE.y) + +## Converts vector position into int index. Hash somewhat +static func indexify(position : Vector2) -> int: + var tiled_position = (position/TILE).floor() + return int(tiled_position.x) + int(tiled_position.y * COLUMNS) + +static func deindexify(index : int) -> Vector2: + return Vector2(index % COLUMNS * TILE.x, index / COLUMNS * TILE.y) diff --git a/scripts/utility/field_params.gd.uid b/scripts/utility/field_params.gd.uid new file mode 100644 index 0000000..2ca2c7c --- /dev/null +++ b/scripts/utility/field_params.gd.uid @@ -0,0 +1 @@ +uid://dnsvj0t3oe3ke