diff options
Diffstat (limited to 'Units/Unit.gd')
-rw-r--r-- | Units/Unit.gd | 256 |
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, + } |