diff options
Diffstat (limited to 'Towers')
-rw-r--r-- | Towers/Tower.gd | 164 | ||||
-rw-r--r-- | Towers/Tower.tscn | 46 | ||||
-rw-r--r-- | Towers/replicated_tower.gd | 7 |
3 files changed, 217 insertions, 0 deletions
diff --git a/Towers/Tower.gd b/Towers/Tower.gd new file mode 100644 index 0000000..f3b6667 --- /dev/null +++ b/Towers/Tower.gd @@ -0,0 +1,164 @@ +class_name Tower +extends StaticBody2D + + +signal selected +signal deselected + +static var selected_towers: Array[Tower] + +var is_selected = false : + set(value): + if value: + if not Tower.selected_towers.has(self): + Tower.selected_towers.append(self) + selected.emit() + else: + Tower.selected_towers.erase(self) + deselected.emit() + Client.stage.hud.tower.text = "" + is_selected = value + queue_redraw() + +var is_hovered = false : + set(value): + is_hovered = value + queue_redraw() + +var mobs_in_range: Array = [] + +var selection_area: Area2D + +# rpc owner id +var owner_id = 1 + +# unique shared id on the network on all clients +var network_id + +@export var attack_range: int = 32 +@export var attack_power: int = 1 +@export var attack_speed: int = 1 + + +func _ready(): + $Range/CollisionShape2D.shape.radius = attack_range + $ShootCooldown.wait_time = attack_speed + + +func _draw(): + if is_selected: + draw_circle( + Client.stage.map.tile_set.tile_size, + 8 + attack_range, + Color(1, 1, 1, 0.75), + false, + 1.0 + ) + modulate = Color(1.5, 1.5, 1.5) + elif is_hovered: + if Client.state is StateDefault: + draw_circle( + Client.stage.map.tile_set.tile_size, + 8 + attack_range, + Color(1, 1, 1, 0.5), + false, + 1.0 + ) + modulate = Color(1.25, 1.25, 1.25) + else: + modulate = Color(1, 1, 1) + + +func _process(_delta: float) -> void: + if $ShootCooldown.is_stopped() and not mobs_in_range.is_empty(): + shoot() + $ShootCooldown.start() + + if selection_area and is_instance_valid(selection_area): + var bodies = selection_area.get_overlapping_bodies() + if bodies.size() > 0: + selection_area.queue_free() + for body in bodies: + Client.select_tower(body) + + +func _on_input_event(_viewport: Node, event: InputEvent, _shape_idx: int): + # disable remote select for now + if owner_id != multiplayer.get_unique_id(): + return + + if Client.state is StateDefault: + if event.is_action_pressed("builder_tower_select"): + Client.select_tower(self) + + if event is InputEventMouseButton: + if event.is_double_click(): + selection_area = Area2D.new() + selection_area.position = ( + Client.stage.get_node("Camera").get_rect().position + + Client.stage.get_node("Camera").get_rect().size / 2 + ) + selection_area.set_collision_mask_value(3, true) + var collision_shape = CollisionShape2D.new() + var shape = RectangleShape2D.new() + shape.size = Client.stage.get_node("Camera").get_rect().size + collision_shape.shape = shape + selection_area.add_child(collision_shape) + get_tree().current_scene.add_child(selection_area) + + if event.is_action_pressed("builder_cancel"): + Client.remove_tower(self) + + +func _on_range_body_entered(body: Node2D) -> void: + mobs_in_range.append(body) + +func _on_range_body_exited(body: Node2D) -> void: + mobs_in_range.remove_at(mobs_in_range.find(body)) + + +func _on_mouse_entered() -> void: + is_hovered = true + +func _on_mouse_exited() -> void: + is_hovered = false + + +func is_melee_range(): + return attack_range <= (Client.stage.map.tile_set.tile_size.x * 2) + + +func shoot(): + var target = mobs_in_range.pick_random() as Unit + + if is_melee_range(): + target.set_hp(target.hp - 1) + else: # TODO + target.set_hp(target.hp - 1) + + +func show_ui(): + # todo: show ui + pass + + +func get_region(): + var collision_shape := $CollisionShape2D + var shape = $CollisionShape2D.shape as RectangleShape2D + + return Rect2( + collision_shape.position, + shape.size + ) + + +func _on_tree_exiting() -> void: + is_selected = false + + +func get_rpc_properties() -> Dictionary: + return { + "global_position": null, + "owner_id": null, + "network_id": null, + } diff --git a/Towers/Tower.tscn b/Towers/Tower.tscn new file mode 100644 index 0000000..dfb2364 --- /dev/null +++ b/Towers/Tower.tscn @@ -0,0 +1,46 @@ +[gd_scene load_steps=5 format=3 uid="uid://by1x56w21o165"] + +[ext_resource type="Script" path="res://Towers/Tower.gd" id="1_axo1d"] +[ext_resource type="Texture2D" uid="uid://b1b18rd0tqbar" path="res://core_outdoor.png" id="1_mrep8"] + +[sub_resource type="RectangleShape2D" id="RectangleShape2D_atm5x"] +size = Vector2(31, 31) + +[sub_resource type="CircleShape2D" id="CircleShape2D_qa8kt"] + +[node name="Tower" type="StaticBody2D"] +y_sort_enabled = true +collision_layer = 4 +collision_mask = 5 +input_pickable = true +script = ExtResource("1_axo1d") + +[node name="Sprite2D" type="Sprite2D" parent="."] +texture_filter = 1 +position = Vector2(0, -19) +scale = Vector2(1.0625, 1.0625) +texture = ExtResource("1_mrep8") +centered = false +region_enabled = true +region_rect = Rect2(400, 432, 32, 48) + +[node name="CollisionShape2D" type="CollisionShape2D" parent="."] +position = Vector2(16, 16) +shape = SubResource("RectangleShape2D_atm5x") + +[node name="Range" type="Area2D" parent="."] +collision_layer = 0 + +[node name="CollisionShape2D" type="CollisionShape2D" parent="Range"] +position = Vector2(16, 16) +shape = SubResource("CircleShape2D_qa8kt") + +[node name="ShootCooldown" type="Timer" parent="."] +one_shot = true + +[connection signal="input_event" from="." to="." method="_on_input_event"] +[connection signal="mouse_entered" from="." to="." method="_on_mouse_entered"] +[connection signal="mouse_exited" from="." to="." method="_on_mouse_exited"] +[connection signal="tree_exiting" from="." to="." method="_on_tree_exiting"] +[connection signal="body_entered" from="Range" to="." method="_on_range_body_entered"] +[connection signal="body_exited" from="Range" to="." method="_on_range_body_exited"] diff --git a/Towers/replicated_tower.gd b/Towers/replicated_tower.gd new file mode 100644 index 0000000..de69ae1 --- /dev/null +++ b/Towers/replicated_tower.gd @@ -0,0 +1,7 @@ +extends Tower +# supposed to be attached to a tower that should just have client-synced behavior + + +# overwrite functions, that behave differently or not at all if called by another peer +func show_ui(): + pass |