summaryrefslogtreecommitdiff
path: root/Units/Unit.gd
diff options
context:
space:
mode:
Diffstat (limited to 'Units/Unit.gd')
-rw-r--r--Units/Unit.gd256
1 files changed, 256 insertions, 0 deletions
diff --git a/Units/Unit.gd b/Units/Unit.gd
new file mode 100644
index 0000000..6c3b254
--- /dev/null
+++ b/Units/Unit.gd
@@ -0,0 +1,256 @@
+class_name Unit
+extends CharacterBody2D
+
+
+signal selected
+
+static var selected_unit: Unit
+
+var is_selected = false :
+ set(value):
+ if value:
+ Unit.selected_unit = self
+ selected.emit()
+ $Label.visible = true
+ line.visible = true
+ else:
+ if Unit.selected_unit == self:
+ Unit.selected_unit = null
+ $Label.visible = false
+ line.visible = false
+ is_selected = value
+ queue_redraw()
+
+var is_hovered = false :
+ set(value):
+ is_hovered = value
+ queue_redraw()
+
+var target: Node2D :
+ set(value):
+ target = value
+ reset_path()
+var immediate_target: Vector2
+
+var current_path: PackedVector2Array
+var current_path_idx = 0 :
+ set(value):
+ current_path_idx = value
+ if line:
+ line.points = PackedVector2Array(current_path.slice(value))
+
+var previous_path: PackedVector2Array
+var previous_path_idx = 0
+
+var previous_position: Vector2
+var recent_closest_paths: Array[PackedVector2Array]
+
+var stuck_position_accumulator = 0.0
+
+var roaming_mode = false
+
+# rpc owner id
+var owner_id = 1
+
+# unique shared id on the network on all clients
+var network_id
+
+@export var base_speed: float = 100
+@export var speed: float = base_speed
+@export var hp = 50
+
+@onready var line: Line2D = $UnitPathLine.duplicate()
+
+
+func _ready():
+ if not target:
+ target = Client.stage.get_node("%Goal")
+
+ Client.stage.units.add_child(line)
+
+ reset_path()
+ Client.stage.path_grid_changed.connect(func():
+ # TODO: get current position from owner_id rpc
+
+ var has_intersection = Client.array_intersect(current_path, Stage.last_solid_set_points)
+ # bug: when setting two towers in close succession, new tower overwrites old last solid points
+ #print(current_path)
+ #print(Stage.last_solid_set_points)
+ if has_intersection:
+ #print("true")
+ reset_path()
+ current_path_idx = min(1, current_path.size() - 1)
+ )
+
+ %HPBar.init(hp)
+ set_hp(hp)
+
+ $SelectionArea/CollisionShape2D.shape.size = $Sprite2D.texture.get_size() * $Sprite2D.scale
+
+
+func _physics_process(delta):
+ previous_position = global_position
+
+ if not current_path.is_empty():
+ if (global_position - current_path[current_path_idx]).is_zero_approx():
+ current_path_idx += 1
+ if current_path_idx >= current_path.size():
+ reset_path()
+
+ walk_along_path(current_path, current_path_idx, delta)
+
+ if roaming_mode:
+ var collision = get_last_slide_collision()
+ if collision:
+ var tower = collision.get_collider() as Node2D
+ Client.destroy_tower(tower)
+
+ # if unit stuck in tower
+ var position_difference = abs(previous_position - global_position)
+ if position_difference.x < 0.1 and position_difference.y < 0.1:
+ stuck_position_accumulator += delta
+ if stuck_position_accumulator >= 1.0:
+ reset_path()
+ else:
+ stuck_position_accumulator = 0
+
+
+func _draw():
+ if is_selected:
+ draw_circle(
+ Vector2.ZERO,
+ Client.stage.map.tile_set.tile_size.x * 0.75,
+ Color(1, 1, 1, 0.75),
+ false,
+ 1.0
+ )
+ modulate = Color(1.5, 1.5, 1.5)
+ elif is_hovered:
+ draw_circle(
+ Vector2.ZERO,
+ Client.stage.map.tile_set.tile_size.x * 0.75,
+ Color(1, 1, 1, 0.5),
+ false,
+ 1.0
+ )
+ modulate = Color(1.25, 1.25, 1.25)
+ else:
+ modulate = Color(1, 1, 1)
+
+
+func _on_navigation_base_area_entered(area: Area2D):
+ if area.is_in_group("goal"):
+ Client.player.score += 1
+ queue_free()
+ if area.is_in_group("path"):
+ var path_node = area.get_parent()
+ if path_node.path_position == target.path_position:
+ target = path_node.next_node
+
+
+func walk_along_path(path: PackedVector2Array, index: int, delta: float):
+ immediate_target = path[index]
+ var displacement := (path[index]) - global_position
+ var direction := displacement.normalized()
+ var distance := displacement.length()
+
+ var max_speed: float = (distance / delta)
+ velocity = direction * minf(speed, max_speed)
+
+ for effect in get_effects():
+ if effect.has_method("apply_physics"):
+ effect.apply_physics(delta)
+ # todo: changing velocity here doesn't work nicely
+ # todo: because the velocity expects to each the point, so it stutters
+
+ move_and_slide()
+
+
+func set_hp(value):
+ # TODO: rpc on damage
+
+ hp = value
+ %HPBar.set_value(value)
+
+ $Label.text = str(hp)
+
+ if hp <= 0:
+ queue_free()
+
+
+func get_effects():
+ var effects = []
+ for node in get_children():
+ if is_instance_of(node, Effect):
+ effects.append(node)
+
+ return effects
+
+
+func reset_path():
+ roaming_mode = false
+ current_path = get_grid_path()
+
+ if current_path.is_empty():
+ current_path = get_grid_path(true)
+ recent_closest_paths.append(current_path)
+
+ # reached end of partial path
+ if current_path.size() == 1 and current_path[0] == global_position:
+ roaming_mode = true
+ current_path = PackedVector2Array([target.path_position + Vector2(16,16)])
+
+ # iterating between one or more closest paths
+ elif recent_closest_paths.count(current_path) >= 2:
+ roaming_mode = true
+ current_path = PackedVector2Array([target.path_position + Vector2(16,16)])
+ recent_closest_paths = []
+ else:
+ recent_closest_paths = []
+ roaming_mode = false
+
+ current_path_idx = 0
+
+ if line:
+ line.points = PackedVector2Array(current_path)
+
+
+func get_grid_path(partial = false):
+ return Client.stage.path_grid.get_point_path(
+ Client.stage.map.local_to_map(global_position),
+ Client.stage.map.local_to_map(target.path_position),
+ partial
+ )
+
+
+func _on_selection_area_input_event(_viewport: Node, event: InputEvent, _shape_idx: int) -> void:
+ if Client.state is StateDefault:
+ if event.is_action_pressed("select"):
+ if selected_unit:
+ selected_unit.is_selected = false
+ is_selected = true
+ $Label.text = str(hp)
+ add_child(preload("res://Effects/SlowEffect.tscn").instantiate())
+
+
+func _on_selection_area_mouse_entered() -> void:
+ is_hovered = true
+
+func _on_selection_area_mouse_exited() -> void:
+ is_hovered = false
+
+
+func _on_tree_exiting() -> void:
+ is_selected = false
+ line.queue_free()
+
+
+func get_rpc_properties():
+ return {
+ "global_position": null,
+ "target": "res://Stages/Paths/PathNode.tscn",
+ "hp": null,
+ "speed": null,
+ "current_path": null,
+ "current_path_idx": null,
+ }