class_name Mob extends CharacterBody2D signal selected static var selected_unit: Mob var is_selected = false : set(value): if value: Mob.selected_unit = self selected.emit() else: if Mob.selected_unit == self: Mob.selected_unit = null 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 var previous_path: PackedVector2Array var previous_path_idx = 0 var previous_position: Vector2 var recent_closest_paths: Array[PackedVector2Array] var roaming_mode = false @export var speed: float = 100 @export var hp = 50 # Called when the node enters the scene tree for the first time. func _ready(): if not target: target = get_tree().current_scene.find_child("Goal") reset_path() Game.path_grid_changed.connect(func(): reset_path() current_path_idx = min(1, current_path.size() - 1) ) %HPBar.init(hp) set_hp(hp) 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 Game.destroy_tower(tower) # if unit stuck in tower if previous_position == global_position: # doesn't work with 0.05 fluctuating position reset_path() roaming_mode = true func _draw(): if is_selected: draw_circle( Vector2.ZERO, 8, Color(1, 1, 1, 0.75), false, 1.0 ) modulate = Color(1.5, 1.5, 1.5) elif is_hovered: draw_circle( Vector2.ZERO, 8, 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"): Game.score += 1 queue_free() if area.is_in_group("path"): var path_node = area.get_parent() if path_node == target: 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) move_and_slide() func set_hp(value): hp = value %HPBar.set_value(value) if is_selected: $Label.text = str(hp) else: $Label.text = "" if hp <= 0: queue_free() 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.global_position]) # iterating between one or more closest paths elif recent_closest_paths.count(current_path) >= 2: roaming_mode = true current_path = PackedVector2Array([target.global_position]) recent_closest_paths = [] else: recent_closest_paths = [] roaming_mode = false current_path_idx = 0 func get_grid_path(partial = false): #return Game.path_grid.get_point_path( #Game.map.local_to_map(global_position) * 2, #Game.map.local_to_map(target.global_position) * 2, #partial #) return Game.path_grid.get_point_path( Game.map.local_to_map(global_position), Game.map.local_to_map(target.global_position), partial ) func _on_input_event(_viewport: Node, event: InputEvent, _shape_idx: int) -> void: if Game.mode == Game.Mode.DEFAULT: if event.is_action_pressed("select"): is_selected = true $Label.text = str(hp) func _on_mouse_entered() -> void: is_hovered = true func _on_mouse_exited() -> void: is_hovered = false func _on_tree_exiting() -> void: is_selected = false