extends Building class_name ConveyorBelt @export var belt_speed_tiles_per_second: float = 1.0 @export var num_slots: int = 2 var items_on_belt: Array[Dictionary] = [] # [{ "item": ItemNode, "progress": float }] @onready var belt_sprite: AnimatedSprite2D = $Sprite2D func _ready(): super() _on_direction_changed() if belt_sprite: belt_sprite.speed_scale = belt_speed_tiles_per_second belt_sprite.play("default") func _on_grid_position_changed(): super() name = "ConveyorBelt_%s,%s" % [current_grid_pos.x, current_grid_pos.y] func _on_direction_changed(): if belt_sprite: belt_sprite.rotation_degrees = calculate_rotation_degrees(direction) func can_accept_item() -> bool: if items_on_belt.is_empty(): return true if items_on_belt.size() >= num_slots: return false var item_length_on_belt = 1.0 / float(num_slots) return items_on_belt.back().progress > item_length_on_belt func handle_item_entry(item: Item, initial_progress: float = 0.0): if not can_accept_item(): print("Belt at %s received item but cannot accept. Item freed." % current_grid_pos) #item.queue_free() return items_on_belt.append({"item": item, "progress": initial_progress}) var world_start_point = game_grid.tile_map.map_to_local(current_grid_pos) + (Vector2.ONE * game_grid.tile_map.rendering_quadrant_size) / 2 var world_end_point = game_grid.tile_map.map_to_local(current_grid_pos + direction) + (Vector2.ONE * game_grid.tile_map.rendering_quadrant_size) / 2 item.global_position = world_start_point.lerp(world_end_point, initial_progress) const dir_to_rotation: Dictionary = { Vector2i.RIGHT: 0.0, Vector2i.DOWN: 90.0, Vector2i.LEFT: 180.0, Vector2i.UP: 270.0 } func calculate_rotation_degrees(dir: Vector2i) -> float: return dir_to_rotation.get(dir, 0.0) func _physics_process(delta: float): if items_on_belt.is_empty(): return _process_belt_movement(delta) _hand_off_items_if_ready() func _process_belt_movement(mut_delta: float): var world_start_point = game_grid.tile_map.map_to_local(current_grid_pos) + (Vector2.ONE * game_grid.tile_map.rendering_quadrant_size) / 2 var world_end_point = game_grid.tile_map.map_to_local(current_grid_pos + direction) + (Vector2.ONE * game_grid.tile_map.rendering_quadrant_size) / 2 var segment_length_pixels = game_grid.tile_map.rendering_quadrant_size var current_pixel_speed = belt_speed_tiles_per_second * segment_length_pixels var item_length_on_belt = 1.0 / float(num_slots) for i: int in items_on_belt.size(): var item_data = items_on_belt[i] var item: Item = item_data.item var item_current_progress: float = item_data.progress var distance_this_frame_progress = (current_pixel_speed * mut_delta) / segment_length_pixels var potential_new_progress = item_current_progress + distance_this_frame_progress var target_progress_for_this_item = potential_new_progress if i > 0: var prev_item_data = items_on_belt[i - 1] var prev_item = prev_item_data.item var prev_item_progress = prev_item_data.progress var max_allowed_front_progress = prev_item_progress - item_length_on_belt target_progress_for_this_item = min(potential_new_progress, max_allowed_front_progress) target_progress_for_this_item = max(item_current_progress, target_progress_for_this_item) item_data.progress = max(0.0, target_progress_for_this_item) item.global_position = world_start_point.lerp(world_end_point, item_data.progress) func _hand_off_items_if_ready(): if items_on_belt.is_empty(): return # var items_to_remove_indices = [] for i in items_on_belt.size(): var item_data = items_on_belt[i] var item_to_hand_off = item_data.item if item_data.progress < 1.0: continue var next_grid_cell_pos = current_grid_pos + direction var next_entity: Building = game_grid.get_content_at_grid(next_grid_cell_pos) if next_entity: if next_entity.can_accept_item(): item_data.progress -= 1.0 #var overshoot_progress_on_old_belt = item_data.progress - 1.0 next_entity.handle_item_entry(item_to_hand_off, item_data.progress) items_to_remove_indices.push_back(i) else: item_data.progress = 1.0 item_to_hand_off.global_position = game_grid.tile_map.map_to_local(current_grid_pos + direction) + (Vector2.ONE * game_grid.tile_map.rendering_quadrant_size) / 2 break else: item_data.progress = 1.0 item_to_hand_off.global_position = game_grid.tile_map.map_to_local(current_grid_pos + direction) + (Vector2.ONE * game_grid.tile_map.rendering_quadrant_size) / 2 break for i_to_remove in range(items_to_remove_indices.size() - 1, -1, -1): var index_to_remove = items_to_remove_indices[i_to_remove] items_on_belt.remove_at(index_to_remove)