BeltTest/ConveyorBelt.gd
Manuel Erdmann 94bfe2754e 🎉
2025-06-10 19:16:45 +02:00

141 lines
4.6 KiB
GDScript

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)