Adds fruit to the arena that grow the snake
parent
18aadc0c2d
commit
7de5b50884
|
@ -0,0 +1,18 @@
|
||||||
|
[gd_scene load_steps=4 format=3 uid="uid://bldekmt1rakjl"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://dcdogfvb8xjod" path="res://Scripts/fruit.gd" id="1_o20pv"]
|
||||||
|
|
||||||
|
[sub_resource type="RectangleShape2D" id="RectangleShape2D_hf2pu"]
|
||||||
|
size = Vector2(18, 18)
|
||||||
|
|
||||||
|
[sub_resource type="PlaceholderTexture2D" id="PlaceholderTexture2D_kum7e"]
|
||||||
|
size = Vector2(20, 20)
|
||||||
|
|
||||||
|
[node name="Fruit" type="Area2D" groups=["BlocksSpawn"]]
|
||||||
|
script = ExtResource("1_o20pv")
|
||||||
|
|
||||||
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||||
|
shape = SubResource("RectangleShape2D_hf2pu")
|
||||||
|
|
||||||
|
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||||
|
texture = SubResource("PlaceholderTexture2D_kum7e")
|
|
@ -16,7 +16,7 @@ fill = 2
|
||||||
fill_from = Vector2(0.5, 0.495413)
|
fill_from = Vector2(0.5, 0.495413)
|
||||||
fill_to = Vector2(0, 0)
|
fill_to = Vector2(0, 0)
|
||||||
|
|
||||||
[node name="Level" type="Area2D"]
|
[node name="Level" type="Area2D" groups=["Level"]]
|
||||||
monitorable = false
|
monitorable = false
|
||||||
|
|
||||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
[gd_scene load_steps=3 format=3 uid="uid://bs6an72avch86"]
|
[gd_scene load_steps=4 format=3 uid="uid://bs6an72avch86"]
|
||||||
|
|
||||||
[ext_resource type="PackedScene" uid="uid://gkqku38yb2ng" path="res://Scenes/level.tscn" id="1_bo1nx"]
|
[ext_resource type="PackedScene" uid="uid://gkqku38yb2ng" path="res://Scenes/level.tscn" id="1_bo1nx"]
|
||||||
[ext_resource type="PackedScene" uid="uid://d0okbjqyaoe0w" path="res://Scenes/snake_part.tscn" id="2_8gbba"]
|
[ext_resource type="PackedScene" uid="uid://d0okbjqyaoe0w" path="res://Scenes/snake_part.tscn" id="2_8gbba"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://bldekmt1rakjl" path="res://Scenes/fruit.tscn" id="3_8gbba"]
|
||||||
|
|
||||||
[node name="Main" type="Node2D"]
|
[node name="Main" type="Node2D"]
|
||||||
|
|
||||||
|
@ -16,5 +17,8 @@ autostart = true
|
||||||
[node name="SnakePart" parent="." instance=ExtResource("2_8gbba")]
|
[node name="SnakePart" parent="." instance=ExtResource("2_8gbba")]
|
||||||
position = Vector2(420, 240)
|
position = Vector2(420, 240)
|
||||||
|
|
||||||
|
[node name="Fruit" parent="." instance=ExtResource("3_8gbba")]
|
||||||
|
position = Vector2(707, 325)
|
||||||
|
|
||||||
[connection signal="area_exited" from="Level" to="SnakePart" method="_on_level_area_exited"]
|
[connection signal="area_exited" from="Level" to="SnakePart" method="_on_level_area_exited"]
|
||||||
[connection signal="timeout" from="Timer" to="SnakePart" method="process_movement" binds= [Vector2(0, 0)]]
|
[connection signal="timeout" from="Timer" to="SnakePart" method="process_movement" binds= [Vector2(0, 0)]]
|
||||||
|
|
|
@ -8,7 +8,7 @@ size = Vector2(18, 18)
|
||||||
[sub_resource type="PlaceholderTexture2D" id="PlaceholderTexture2D_kum7e"]
|
[sub_resource type="PlaceholderTexture2D" id="PlaceholderTexture2D_kum7e"]
|
||||||
size = Vector2(20, 20)
|
size = Vector2(20, 20)
|
||||||
|
|
||||||
[node name="SnakePart" type="Area2D"]
|
[node name="SnakePart" type="Area2D" groups=["BlocksSpawn"]]
|
||||||
script = ExtResource("1_iuiyg")
|
script = ExtResource("1_iuiyg")
|
||||||
|
|
||||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
extends Area2D
|
||||||
|
class_name Fruit
|
||||||
|
|
||||||
|
const TILE_SIZE = 20
|
||||||
|
|
||||||
|
var all_positions : Array[Vector2] = []
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
var level : Area2D = get_tree().get_first_node_in_group("Level")
|
||||||
|
var x_bounds : Vector2 = level.position.x * Vector2.ONE + Vector2(-TILE_SIZE, TILE_SIZE) * level.scale.x / 2
|
||||||
|
var y_bounds : Vector2 = level.position.y * Vector2.ONE + Vector2(-TILE_SIZE, TILE_SIZE) * level.scale.y / 2
|
||||||
|
|
||||||
|
var possible_x : Array = range(x_bounds.x, x_bounds.y, TILE_SIZE)
|
||||||
|
var possible_y : Array = range(y_bounds.x, y_bounds.y, TILE_SIZE)
|
||||||
|
|
||||||
|
for x in possible_x:
|
||||||
|
for y in possible_y:
|
||||||
|
all_positions.append(Vector2(x, y))
|
||||||
|
|
||||||
|
respawn()
|
||||||
|
|
||||||
|
func respawn() -> void:
|
||||||
|
var possible_positions = all_positions.duplicate()
|
||||||
|
|
||||||
|
var obstacles : Array[Node] = get_tree().get_nodes_in_group("BlocksSpawn")
|
||||||
|
|
||||||
|
for obstacle in obstacles:
|
||||||
|
if obstacle is Area2D:
|
||||||
|
possible_positions.erase(obstacle.position)
|
||||||
|
|
||||||
|
var chosen_position = possible_positions.pick_random()
|
||||||
|
|
||||||
|
position = chosen_position
|
|
@ -0,0 +1 @@
|
||||||
|
uid://dcdogfvb8xjod
|
|
@ -14,19 +14,22 @@ var inputs : Dictionary[String, Vector2] = {"right": Vector2.RIGHT,
|
||||||
|
|
||||||
|
|
||||||
@onready
|
@onready
|
||||||
var raycast_right = $RightRayCast2D
|
var raycast_right : RayCast2D = $RightRayCast2D
|
||||||
@onready
|
@onready
|
||||||
var raycast_left = $LeftRayCast2D
|
var raycast_left : RayCast2D = $LeftRayCast2D
|
||||||
@onready
|
@onready
|
||||||
var raycast_up = $UpRayCast2D
|
var raycast_up : RayCast2D = $UpRayCast2D
|
||||||
@onready
|
@onready
|
||||||
var raycast_down = $DownRayCast2D
|
var raycast_down : RayCast2D = $DownRayCast2D
|
||||||
|
|
||||||
|
|
||||||
var snake_part_obj = preload("res://Scenes/snake_part.tscn")
|
var snake_part_obj : PackedScene = preload("res://Scenes/snake_part.tscn")
|
||||||
|
|
||||||
@onready
|
@onready
|
||||||
var timer_ref = $"../Timer"
|
var timer_ref : Timer = $"../Timer"
|
||||||
|
|
||||||
|
var next_part : SnakePart = null
|
||||||
|
var skip_next_move_propagation : bool = false
|
||||||
|
|
||||||
signal do_movement(new_dir)
|
signal do_movement(new_dir)
|
||||||
|
|
||||||
|
@ -40,6 +43,7 @@ func _ready() -> void:
|
||||||
var body = snake_part_obj.instantiate()
|
var body = snake_part_obj.instantiate()
|
||||||
body.part_type = PartTypes.BODY
|
body.part_type = PartTypes.BODY
|
||||||
body.position = (position - current_direction * TILE_SIZE).snapped(Vector2.ONE * TILE_SIZE)
|
body.position = (position - current_direction * TILE_SIZE).snapped(Vector2.ONE * TILE_SIZE)
|
||||||
|
next_part = body
|
||||||
get_parent().add_child.call_deferred(body)
|
get_parent().add_child.call_deferred(body)
|
||||||
do_movement.connect(body.process_movement)
|
do_movement.connect(body.process_movement)
|
||||||
|
|
||||||
|
@ -47,26 +51,34 @@ func _ready() -> void:
|
||||||
var tail = snake_part_obj.instantiate()
|
var tail = snake_part_obj.instantiate()
|
||||||
tail.part_type = PartTypes.TAIL
|
tail.part_type = PartTypes.TAIL
|
||||||
tail.position = (position - current_direction * TILE_SIZE * 2).snapped(Vector2.ONE * TILE_SIZE)
|
tail.position = (position - current_direction * TILE_SIZE * 2).snapped(Vector2.ONE * TILE_SIZE)
|
||||||
|
body.next_part = tail
|
||||||
get_parent().add_child.call_deferred(tail)
|
get_parent().add_child.call_deferred(tail)
|
||||||
body.do_movement.connect(tail.process_movement)
|
body.do_movement.connect(tail.process_movement)
|
||||||
else:
|
else:
|
||||||
|
|
||||||
|
# Free raycasts if we don't need them (consider only loading them in for the head for performance if needed)
|
||||||
raycast_down.queue_free()
|
raycast_down.queue_free()
|
||||||
raycast_up.queue_free()
|
raycast_up.queue_free()
|
||||||
raycast_left.queue_free()
|
raycast_left.queue_free()
|
||||||
raycast_right.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:
|
func process_movement(new_direction : Vector2) -> void:
|
||||||
|
|
||||||
|
# The head needs to check if we are about to collide with something
|
||||||
if part_type == PartTypes.HEAD:
|
if part_type == PartTypes.HEAD:
|
||||||
check_movement()
|
check_movement()
|
||||||
|
|
||||||
|
# Update the position of this part
|
||||||
position = (position + current_direction * TILE_SIZE).snapped(Vector2.ONE * TILE_SIZE)
|
position = (position + current_direction * TILE_SIZE).snapped(Vector2.ONE * TILE_SIZE)
|
||||||
#process_collisions();
|
|
||||||
do_movement.emit(current_direction)
|
# Tell the next part to move and give it the direction we are moving
|
||||||
|
if !skip_next_move_propagation:
|
||||||
|
do_movement.emit(current_direction)
|
||||||
|
skip_next_move_propagation = false
|
||||||
|
|
||||||
|
# Unless we are the head, change our direction to the direction given
|
||||||
if new_direction != Vector2.ZERO:
|
if new_direction != Vector2.ZERO:
|
||||||
current_direction = new_direction
|
current_direction = new_direction
|
||||||
|
|
||||||
|
@ -84,24 +96,44 @@ func check_movement() -> void:
|
||||||
|
|
||||||
# Look using the raycast for anything to collide with
|
# Look using the raycast for anything to collide with
|
||||||
var object_in_path : Object = raycast_to_use.get_collider()
|
var object_in_path : Object = raycast_to_use.get_collider()
|
||||||
|
|
||||||
|
# If we found nothing, stop processing collision
|
||||||
if object_in_path == null:
|
if object_in_path == null:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# If we found a snake part, then either end the game or perform an ouroboros maneouvre
|
||||||
if object_in_path is SnakePart:
|
if object_in_path is SnakePart:
|
||||||
match object_in_path.part_type:
|
match object_in_path.part_type:
|
||||||
PartTypes.BODY:
|
PartTypes.BODY:
|
||||||
lose_game()
|
lose_game()
|
||||||
PartTypes.TAIL:
|
PartTypes.TAIL:
|
||||||
ouroboros()
|
ouroboros()
|
||||||
|
if object_in_path is Fruit:
|
||||||
|
object_in_path.respawn()
|
||||||
|
extend()
|
||||||
|
|
||||||
#func process_collisions() -> void:
|
func extend() -> void:
|
||||||
#var colliding_areas = get_overlapping_areas()
|
# Remove old connection to previous next part
|
||||||
#for area in colliding_areas:
|
do_movement.disconnect(next_part.process_movement)
|
||||||
#if area is SnakePart:
|
|
||||||
#match area.part_type:
|
# Set up a body part to be in the chain
|
||||||
#PartTypes.BODY:
|
var new_body = snake_part_obj.instantiate()
|
||||||
#lose_game()
|
new_body.part_type = PartTypes.BODY
|
||||||
#PartTypes.TAIL:
|
new_body.position = (position).snapped(Vector2.ONE * TILE_SIZE)
|
||||||
#ouroboros()
|
get_parent().add_child(new_body)
|
||||||
|
do_movement.connect(new_body.process_movement)
|
||||||
|
new_body.do_movement.connect(next_part.process_movement)
|
||||||
|
new_body.next_part = next_part
|
||||||
|
|
||||||
|
# Set direction of new part
|
||||||
|
new_body.current_direction = current_direction
|
||||||
|
|
||||||
|
# Update reference to next part
|
||||||
|
next_part = new_body
|
||||||
|
|
||||||
|
# Mark the next movement to not propagate the movement down the chain
|
||||||
|
skip_next_move_propagation = true
|
||||||
|
|
||||||
|
|
||||||
func lose_game() -> void:
|
func lose_game() -> void:
|
||||||
# You lose!
|
# You lose!
|
||||||
|
@ -112,18 +144,14 @@ func ouroboros() -> void:
|
||||||
print("You have achieved the ouroboros!")
|
print("You have achieved the ouroboros!")
|
||||||
|
|
||||||
func _unhandled_input(event: InputEvent) -> void:
|
func _unhandled_input(event: InputEvent) -> void:
|
||||||
|
|
||||||
|
# Change direction if we are the head
|
||||||
if event is InputEventKey and part_type == PartTypes.HEAD:
|
if event is InputEventKey and part_type == PartTypes.HEAD:
|
||||||
for dir in inputs.keys():
|
for dir in inputs.keys():
|
||||||
if event.is_action_pressed(dir):
|
if event.is_action_pressed(dir):
|
||||||
current_direction = inputs[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()
|
|
||||||
|
|
||||||
|
# If we leave the arena
|
||||||
func _on_level_area_exited(area: Area2D) -> void:
|
func _on_level_area_exited(area: Area2D) -> void:
|
||||||
lose_game()
|
lose_game()
|
||||||
|
|
|
@ -14,6 +14,11 @@ config/name="Ouroboros"
|
||||||
config/features=PackedStringArray("4.4", "GL Compatibility")
|
config/features=PackedStringArray("4.4", "GL Compatibility")
|
||||||
config/icon="res://icon.svg"
|
config/icon="res://icon.svg"
|
||||||
|
|
||||||
|
[global_group]
|
||||||
|
|
||||||
|
Level=""
|
||||||
|
BlocksSpawn=""
|
||||||
|
|
||||||
[input]
|
[input]
|
||||||
|
|
||||||
right={
|
right={
|
||||||
|
|
Loading…
Reference in New Issue