extends Area2D class_name SnakePart const TILE_SIZE = 20 enum PartTypes {HEAD, BODY, TAIL, DEAD} var part_type : PartTypes = PartTypes.HEAD var current_direction : Vector2 = Vector2.RIGHT var inputs : Dictionary[String, Vector2] = {"right": Vector2.RIGHT, "left": Vector2.LEFT, "up": Vector2.UP, "down": Vector2.DOWN} @onready var raycast_right = $RightRayCast2D @onready var raycast_left = $LeftRayCast2D @onready var raycast_up = $UpRayCast2D @onready var raycast_down = $DownRayCast2D var snake_part_obj = preload("res://Scenes/snake_part.tscn") @onready var timer_ref = $"../Timer" signal do_movement(new_dir) func _ready() -> void: if part_type == PartTypes.HEAD: # Add to group for easy access from other nodes add_to_group("Head") # Set up a body part var body = snake_part_obj.instantiate() body.part_type = PartTypes.BODY body.position = (position - current_direction * TILE_SIZE).snapped(Vector2.ONE * TILE_SIZE) get_parent().add_child.call_deferred(body) do_movement.connect(body.process_movement) # Set up a tail part var tail = snake_part_obj.instantiate() tail.part_type = PartTypes.TAIL tail.position = (position - current_direction * TILE_SIZE * 2).snapped(Vector2.ONE * TILE_SIZE) get_parent().add_child.call_deferred(tail) body.do_movement.connect(tail.process_movement) else: raycast_down.queue_free() raycast_up.queue_free() raycast_left.queue_free() raycast_right.queue_free() #elif part_type == PartTypes.BODY: #area_entered.connect(_on_part_area_entered) #elif part_type == PartTypes.TAIL: #area_entered.connect(_on_part_area_entered) func process_movement(new_direction : Vector2) -> void: if part_type == PartTypes.HEAD: check_movement() position = (position + current_direction * TILE_SIZE).snapped(Vector2.ONE * TILE_SIZE) #process_collisions(); do_movement.emit(current_direction) if new_direction != Vector2.ZERO: current_direction = new_direction func check_movement() -> void: # Get the correct raycast for the direction we are moving var raycast_to_use : RayCast2D if current_direction == Vector2.RIGHT: raycast_to_use = raycast_right elif current_direction == Vector2.LEFT: raycast_to_use = raycast_left elif current_direction == Vector2.UP: raycast_to_use = raycast_up elif current_direction == Vector2.DOWN: raycast_to_use = raycast_down # Look using the raycast for anything to collide with var object_in_path : Object = raycast_to_use.get_collider() if object_in_path == null: return if object_in_path is SnakePart: match object_in_path.part_type: PartTypes.BODY: lose_game() PartTypes.TAIL: ouroboros() #func process_collisions() -> void: #var colliding_areas = get_overlapping_areas() #for area in colliding_areas: #if area is SnakePart: #match area.part_type: #PartTypes.BODY: #lose_game() #PartTypes.TAIL: #ouroboros() func lose_game() -> void: # You lose! print("Game lost") timer_ref.stop() func ouroboros() -> void: print("You have achieved the ouroboros!") func _unhandled_input(event: InputEvent) -> void: if event is InputEventKey and part_type == PartTypes.HEAD: for dir in inputs.keys(): if event.is_action_pressed(dir): current_direction = inputs[dir] #func _on_part_area_entered(area: Area2D) -> void: #if area.get("part_type") != PartTypes.HEAD: #return #if part_type == PartTypes.BODY or part_type == PartTypes.DEAD: #lose_game() #elif part_type == PartTypes.TAIL: #ouroboros() func _on_level_area_exited(area: Area2D) -> void: lose_game()