From 898877f09808691a5e5d45850d27ae85f270db16 Mon Sep 17 00:00:00 2001
From: David Luevano Alvarado <david@luevano.xyz>
Date: Thu, 2 Jun 2022 02:35:03 -0600
Subject: add food system

---
 assets/food/apple.aseprite                         | Bin 0 -> 599 bytes
 assets/food/apple.png                              | Bin 0 -> 148 bytes
 src/Main.tscn                                      |   9 +++--
 src/entities/actors/snake/scenes/Body.tscn         |   2 +-
 src/entities/actors/snake/scenes/Head.tscn         |   7 ++--
 .../actors/snake/scripts/generic_segment.gd        |  10 ++++++
 src/entities/actors/snake/scripts/snake.gd         |  22 +++++++-----
 src/entities/food/scenes/Food.tscn                 |  16 +++++++++
 src/entities/food/scenes/FoodManager.tscn          |   8 +++++
 src/entities/food/scripts/food.gd                  |  23 ++++++++++++
 src/entities/food/scripts/food_manager.gd          |  39 +++++++++++++++++++++
 src/entities/food/sprites/apple.png                | Bin 0 -> 148 bytes
 src/entities/food/sprites/apple.png.import         |  35 ++++++++++++++++++
 src/event.gd                                       |   9 +++--
 src/global.gd                                      |   5 +--
 src/main.gd                                        |  20 +++++++++++
 src/project.godot                                  |  28 ++++++++++++++-
 src/tools/ScreenRecorder.tscn                      |  10 ++----
 src/ui/UI.tscn                                     |  24 +++++++++++++
 src/ui/ui.gd                                       |  17 +++++++++
 20 files changed, 256 insertions(+), 28 deletions(-)
 create mode 100644 assets/food/apple.aseprite
 create mode 100644 assets/food/apple.png
 create mode 100644 src/entities/food/scenes/Food.tscn
 create mode 100644 src/entities/food/scenes/FoodManager.tscn
 create mode 100644 src/entities/food/scripts/food.gd
 create mode 100644 src/entities/food/scripts/food_manager.gd
 create mode 100644 src/entities/food/sprites/apple.png
 create mode 100644 src/entities/food/sprites/apple.png.import
 create mode 100644 src/ui/UI.tscn
 create mode 100644 src/ui/ui.gd

diff --git a/assets/food/apple.aseprite b/assets/food/apple.aseprite
new file mode 100644
index 0000000..9dd7a6b
Binary files /dev/null and b/assets/food/apple.aseprite differ
diff --git a/assets/food/apple.png b/assets/food/apple.png
new file mode 100644
index 0000000..d4fd6ad
Binary files /dev/null and b/assets/food/apple.png differ
diff --git a/src/Main.tscn b/src/Main.tscn
index ef84fce..1442e36 100644
--- a/src/Main.tscn
+++ b/src/Main.tscn
@@ -1,16 +1,21 @@
-[gd_scene load_steps=4 format=2]
+[gd_scene load_steps=6 format=2]
 
 [ext_resource path="res://entities/actors/snake/scenes/Snake.tscn" type="PackedScene" id=1]
 [ext_resource path="res://tools/ScreenRecorder.tscn" type="PackedScene" id=2]
+[ext_resource path="res://ui/UI.tscn" type="PackedScene" id=3]
 [ext_resource path="res://main.gd" type="Script" id=4]
+[ext_resource path="res://entities/food/scenes/FoodManager.tscn" type="PackedScene" id=5]
 
 [node name="Main" type="Node2D"]
 script = ExtResource( 4 )
 
+[node name="FoodManager" parent="." instance=ExtResource( 5 )]
+
 [node name="Snake" parent="." instance=ExtResource( 1 )]
 
 [node name="Camera" type="Camera2D" parent="."]
 current = true
-zoom = Vector2( 0.5, 0.5 )
+
+[node name="UI" parent="." instance=ExtResource( 3 )]
 
 [node name="ScreenRecorder" parent="." instance=ExtResource( 2 )]
diff --git a/src/entities/actors/snake/scenes/Body.tscn b/src/entities/actors/snake/scenes/Body.tscn
index 8e4a8a4..49694c0 100644
--- a/src/entities/actors/snake/scenes/Body.tscn
+++ b/src/entities/actors/snake/scenes/Body.tscn
@@ -4,7 +4,7 @@
 [ext_resource path="res://entities/actors/snake/scripts/generic_segment.gd" type="Script" id=2]
 
 [sub_resource type="CapsuleShape2D" id=1]
-radius = 5.99999
+radius = 4.99999
 height = 4.00002
 
 [node name="BodyPathFollow" type="PathFollow2D"]
diff --git a/src/entities/actors/snake/scenes/Head.tscn b/src/entities/actors/snake/scenes/Head.tscn
index 22aa7e6..d118fbf 100644
--- a/src/entities/actors/snake/scenes/Head.tscn
+++ b/src/entities/actors/snake/scenes/Head.tscn
@@ -3,12 +3,11 @@
 [ext_resource path="res://entities/actors/snake/sprites/head.png" type="Texture" id=1]
 [ext_resource path="res://entities/actors/snake/scripts/head.gd" type="Script" id=2]
 
-[sub_resource type="CircleShape2D" id=1]
-radius = 5.0
+[sub_resource type="ConvexPolygonShape2D" id=1]
+points = PoolVector2Array( -5, 0, 5, 0, 5, -3, 3, -4, 1, -5, -1, -5, -3, -4, -5, -3 )
 
 [node name="Head" type="KinematicBody2D"]
-position = Vector2( -1, 0 )
-collision_mask = 0
+collision_mask = 262
 script = ExtResource( 2 )
 
 [node name="Sprite" type="Sprite" parent="."]
diff --git a/src/entities/actors/snake/scripts/generic_segment.gd b/src/entities/actors/snake/scripts/generic_segment.gd
index 6c65d11..e2db91d 100644
--- a/src/entities/actors/snake/scripts/generic_segment.gd
+++ b/src/entities/actors/snake/scripts/generic_segment.gd
@@ -2,6 +2,16 @@ extends PathFollow2D
 
 export(String, "body", "tail") var TYPE: String = "body"
 
+onready var _segment: Area2D = get_child(0)
+
+
+func _ready() -> void:
+	_segment.connect("body_entered", self, "_on_body_entered")
+
 
 func _physics_process(delta: float) -> void:
 	offset += Global.SNAKE_SPEED * delta
+
+
+func _on_body_entered(body: Node) -> void:
+	Event.emit_signal("snake_segment_body_entered", body)
diff --git a/src/entities/actors/snake/scripts/snake.gd b/src/entities/actors/snake/scripts/snake.gd
index 76b8bee..ead6254 100644
--- a/src/entities/actors/snake/scripts/snake.gd
+++ b/src/entities/actors/snake/scripts/snake.gd
@@ -18,9 +18,11 @@ var body_segment_queue: Array
 func _ready():
 	set_physics_process(false)
 	set_process_input(false)
-	Event.connect("snake_path_new_point", self, "_on_Head_snake_path_new_point")
-	Event.connect("snake_added_new_segment", self, "_on_Snake_snake_added_new_segment")
-	Event.connect("snake_added_initial_segments", self, "_on_Snake_snake_added_initial_segments")
+	Event.connect("snake_path_new_point", self, "_on_snake_path_new_point")
+	Event.connect("snake_added_new_segment", self, "_on_snake_added_new_segment")
+	Event.connect("snake_added_initial_segments", self, "_on_snake_added_initial_segments")
+
+	Event.connect("food_eaten", self, "_on_food_eaten")
 
 
 func _physics_process(delta: float) -> void:
@@ -42,7 +44,7 @@ func _add_new_segment() -> void:
 	var _path_length_threshold: float = body_segment_queue[0] + Global.SNAKE_SEGMENT_SIZE
 	if path.curve.get_baked_length() >= _path_length_threshold:
 		var _temp_body_segment: PathFollow2D = BODY_SEGMENT_NP.instance()
-		Event.emit_signal("snake_add_new_segment", "body")
+		Event.emit_signal("snake_adding_new_segment", "body")
 		var _new_body_offset: float = body_segment_stack.back().offset - Global.SNAKE_SEGMENT_SIZE
 
 		_temp_body_segment.offset = _new_body_offset
@@ -58,7 +60,7 @@ func _add_new_segment() -> void:
 func _add_initial_segment(type: PackedScene) -> void:
 	if path.curve.get_baked_length() >= (current_body_segments + 1.0) * Global.SNAKE_SEGMENT_SIZE:
 		var _temp_body_segment: PathFollow2D = type.instance()
-		Event.emit_signal("snake_add_new_segment", _temp_body_segment.TYPE)
+		Event.emit_signal("snake_adding_new_segment", _temp_body_segment.TYPE)
 		if _temp_body_segment.TYPE == "body":
 			body_segment_stack.append(_temp_body_segment)
 		else:
@@ -78,7 +80,7 @@ func _add_segment_to_queue() -> void:
 		body_segment_queue.append(body_segment_queue.back() + Global.SNAKE_SEGMENT_SIZE)
 
 
-func _on_Head_snake_path_new_point(coordinates: Vector2) -> void:
+func _on_snake_path_new_point(coordinates: Vector2) -> void:
 	path.curve.add_point(coordinates)
 	# update call is to draw curve as there are new points to the path's curve
 	update()
@@ -89,11 +91,15 @@ func _on_Head_snake_path_new_point(coordinates: Vector2) -> void:
 		_add_initial_segment(TAIL_SEGMENT_NP)
 
 
-func _on_Snake_snake_added_new_segment(type: String) -> void:
+func _on_snake_added_new_segment(type: String) -> void:
 	if type == "tail":
 		Event.emit_signal("snake_added_initial_segments")
 
 
-func _on_Snake_snake_added_initial_segments() -> void:
+func _on_snake_added_initial_segments() -> void:
 	set_physics_process(true)
 	set_process_input(true)
+
+
+func _on_food_eaten(type: int) -> void:
+	_add_segment_to_queue()
\ No newline at end of file
diff --git a/src/entities/food/scenes/Food.tscn b/src/entities/food/scenes/Food.tscn
new file mode 100644
index 0000000..bc330e2
--- /dev/null
+++ b/src/entities/food/scenes/Food.tscn
@@ -0,0 +1,16 @@
+[gd_scene load_steps=3 format=2]
+
+[ext_resource path="res://entities/food/scripts/food.gd" type="Script" id=2]
+
+[sub_resource type="CircleShape2D" id=1]
+radius = 7.0
+
+[node name="Food" type="Area2D"]
+collision_layer = 256
+collision_mask = 0
+script = ExtResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="."]
+
+[node name="Collision" type="CollisionShape2D" parent="."]
+shape = SubResource( 1 )
diff --git a/src/entities/food/scenes/FoodManager.tscn b/src/entities/food/scenes/FoodManager.tscn
new file mode 100644
index 0000000..3287271
--- /dev/null
+++ b/src/entities/food/scenes/FoodManager.tscn
@@ -0,0 +1,8 @@
+[gd_scene load_steps=3 format=2]
+
+[ext_resource path="res://entities/food/scenes/Food.tscn" type="PackedScene" id=1]
+[ext_resource path="res://entities/food/scripts/food_manager.gd" type="Script" id=2]
+
+[node name="FoodManager" type="Node2D"]
+script = ExtResource( 2 )
+FOOD = ExtResource( 1 )
diff --git a/src/entities/food/scripts/food.gd b/src/entities/food/scripts/food.gd
new file mode 100644
index 0000000..1689837
--- /dev/null
+++ b/src/entities/food/scripts/food.gd
@@ -0,0 +1,23 @@
+class_name Food
+extends Area2D
+
+enum Type {
+	APPLE
+}
+
+var _type_texture: Dictionary = {
+	Type.APPLE: preload("res://entities/food/sprites/apple.png")
+}
+
+export(Type) var TYPE
+onready var _sprite: Sprite = $Sprite
+
+
+func _ready():
+	connect("body_entered", self, "_on_body_entered")
+	_sprite.texture = _type_texture[TYPE]
+
+
+func _on_body_entered(body: Node) -> void:
+	Event.emit_signal("food_eaten", TYPE)
+	queue_free()
\ No newline at end of file
diff --git a/src/entities/food/scripts/food_manager.gd b/src/entities/food/scripts/food_manager.gd
new file mode 100644
index 0000000..20772db
--- /dev/null
+++ b/src/entities/food/scripts/food_manager.gd
@@ -0,0 +1,39 @@
+class_name FoodManager
+extends Node2D
+
+export(PackedScene) var FOOD: PackedScene
+
+var max_apples: int = 10
+var current_apples: int = 0
+
+
+func _ready():
+	Event.connect("food_eaten", self, "_on_food_eaten")
+	randomize()
+
+
+func _process(delta) -> void:
+	if current_apples < max_apples:
+		_place_new_food()
+		current_apples += 1
+
+
+func _place_new_food() -> void:
+	var food: Area2D = FOOD.instance()
+	Event.emit_signal("food_placing_new_food", food.TYPE)
+	var position: Vector2 = _get_random_pos()
+	food.global_position = position
+	add_child(food)
+	Event.emit_signal("food_placed_new_food", food.TYPE)
+
+
+func _get_random_pos() -> Vector2:
+	var screen_size: Vector2 = get_viewport().get_visible_rect().size
+	var temp_x: float = randf() * screen_size.x - screen_size.x / 2.0
+	var temp_y: float = randf() * screen_size.y - screen_size.y / 2.0
+
+	return Vector2(temp_x, temp_y)
+
+
+func _on_food_eaten(type: int) -> void:
+	current_apples -= 1
\ No newline at end of file
diff --git a/src/entities/food/sprites/apple.png b/src/entities/food/sprites/apple.png
new file mode 100644
index 0000000..d4fd6ad
Binary files /dev/null and b/src/entities/food/sprites/apple.png differ
diff --git a/src/entities/food/sprites/apple.png.import b/src/entities/food/sprites/apple.png.import
new file mode 100644
index 0000000..c007dad
--- /dev/null
+++ b/src/entities/food/sprites/apple.png.import
@@ -0,0 +1,35 @@
+[remap]
+
+importer="texture"
+type="StreamTexture"
+path="res://.import/apple.png-3f0e1c07d45c9f73006d6dd04c7dfa93.stex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://entities/food/sprites/apple.png"
+dest_files=[ "res://.import/apple.png-3f0e1c07d45c9f73006d6dd04c7dfa93.stex" ]
+
+[params]
+
+compress/mode=0
+compress/lossy_quality=0.7
+compress/hdr_mode=0
+compress/bptc_ldr=0
+compress/normal_map=0
+flags/repeat=0
+flags/filter=false
+flags/mipmaps=false
+flags/anisotropic=false
+flags/srgb=2
+process/fix_alpha_border=false
+process/premult_alpha=false
+process/HDR_as_SRGB=false
+process/invert_color=false
+process/normal_map_invert_y=false
+stream=false
+size_limit=0
+detect_3d=false
+svg/scale=1.0
diff --git a/src/event.gd b/src/event.gd
index e03c159..7e72aca 100644
--- a/src/event.gd
+++ b/src/event.gd
@@ -1,6 +1,11 @@
 extends Node
 
 signal snake_path_new_point(coordinates)
-signal snake_add_new_segment(type)
+signal snake_adding_new_segment(type)
 signal snake_added_new_segment(type)
-signal snake_added_initial_segments
\ No newline at end of file
+signal snake_added_initial_segments
+signal snake_segment_body_entered(body)
+
+signal food_placing_new_food(type)
+signal food_placed_new_food(type)
+signal food_eaten(type)
\ No newline at end of file
diff --git a/src/global.gd b/src/global.gd
index 1682819..2885443 100644
--- a/src/global.gd
+++ b/src/global.gd
@@ -1,8 +1,9 @@
 extends Node
 
+var GAME_SCALE: float = 2.0
+
 var SNAKE_SPEED: float = 50.0
 var SNAKE_ROT_SPEED: float = 200.0
-var SNAKE_SEGMENT_ROT_SPEED: float = 80.0
 var SNAKE_POSITION_UPDATE_INTERVAL: float = 0.01
 # this usually corresponds to the sprite size
-var SNAKE_SEGMENT_SIZE: float = 14.0
\ No newline at end of file
+var SNAKE_SEGMENT_SIZE: float = 14.0
diff --git a/src/main.gd b/src/main.gd
index 3e709ef..cdfbbf1 100644
--- a/src/main.gd
+++ b/src/main.gd
@@ -1,2 +1,22 @@
 class_name Main
 extends Node
+
+onready var _snake: Node2D = $Snake
+
+
+func _ready() -> void:
+	Event.connect("snake_segment_body_entered", self, "_on_snake_segment_body_entered")
+	# OS.window_size = Global.GAME_SCALE * OS.window_size
+
+
+func _on_snake_segment_body_entered(body: Node) -> void:
+	if body is KinematicBody2D:
+		_snake_disabled(false)
+
+
+func _snake_disabled(on_off: bool) -> void:
+	_snake.propagate_call("set_process", [on_off])
+	_snake.propagate_call("set_process_internal", [on_off])
+	_snake.propagate_call("set_physics_process", [on_off])
+	_snake.propagate_call("set_physics_process_internal", [on_off])
+	_snake.propagate_call("set_process_input", [on_off])
diff --git a/src/project.godot b/src/project.godot
index 941300b..bf55ea9 100644
--- a/src/project.godot
+++ b/src/project.godot
@@ -9,6 +9,16 @@
 config_version=4
 
 _global_script_classes=[ {
+"base": "Area2D",
+"class": "Food",
+"language": "GDScript",
+"path": "res://entities/food/scripts/food.gd"
+}, {
+"base": "Node2D",
+"class": "FoodManager",
+"language": "GDScript",
+"path": "res://entities/food/scripts/food_manager.gd"
+}, {
 "base": "Node",
 "class": "GifDecoder",
 "language": "GDScript",
@@ -33,13 +43,21 @@ _global_script_classes=[ {
 "class": "Snake",
 "language": "GDScript",
 "path": "res://entities/actors/snake/scripts/snake.gd"
+}, {
+"base": "CanvasLayer",
+"class": "UI",
+"language": "GDScript",
+"path": "res://ui/ui.gd"
 } ]
 _global_script_class_icons={
+"Food": "",
+"FoodManager": "",
 "GifDecoder": "",
 "GifRecorder": "res://addons/GifMaker/gif.svg",
 "GifRectangle": "res://addons/GifMaker/GifRectangle.svg",
 "Main": "",
-"Snake": ""
+"Snake": "",
+"UI": ""
 }
 
 [application]
@@ -59,6 +77,13 @@ gdscript/warnings/unused_argument=false
 gdscript/warnings/unused_signal=false
 gdscript/warnings/return_value_discarded=false
 
+[display]
+
+window/size/width=320
+window/size/height=180
+window/stretch/mode="2d"
+window/stretch/aspect="keep"
+
 [editor_plugins]
 
 enabled=PoolStringArray( "res://addons/GifMaker/plugin.cfg" )
@@ -98,6 +123,7 @@ add_body_part={
 2d_physics/layer_1="snake_head"
 2d_physics/layer_2="snake_body"
 2d_physics/layer_3="snake_tail"
+2d_physics/layer_9="food"
 
 [physics]
 
diff --git a/src/tools/ScreenRecorder.tscn b/src/tools/ScreenRecorder.tscn
index d29753a..96d6dff 100644
--- a/src/tools/ScreenRecorder.tscn
+++ b/src/tools/ScreenRecorder.tscn
@@ -12,14 +12,8 @@ anchor_right = 1.0
 anchor_bottom = 1.0
 
 [node name="GifRectangle" type="ReferenceRect" parent="Control"]
-anchor_left = 0.5
-anchor_top = 0.5
-anchor_right = 0.5
-anchor_bottom = 0.5
-margin_left = -128.0
-margin_top = -128.0
-margin_right = 128.0
-margin_bottom = 128.0
+anchor_right = 1.0
+anchor_bottom = 1.0
 script = ExtResource( 1 )
 
 [node name="GifRecorder" type="Viewport" parent="Control"]
diff --git a/src/ui/UI.tscn b/src/ui/UI.tscn
new file mode 100644
index 0000000..f5b0ac3
--- /dev/null
+++ b/src/ui/UI.tscn
@@ -0,0 +1,24 @@
+[gd_scene load_steps=2 format=2]
+
+[ext_resource path="res://ui/ui.gd" type="Script" id=1]
+
+[node name="UI" type="CanvasLayer"]
+script = ExtResource( 1 )
+
+[node name="Root" type="Control" parent="."]
+anchor_right = 1.0
+anchor_bottom = 1.0
+
+[node name="StatsHUD" type="MarginContainer" parent="Root"]
+margin_left = 10.0
+margin_top = 10.0
+margin_right = 310.0
+margin_bottom = 110.0
+
+[node name="VBox" type="VBoxContainer" parent="Root/StatsHUD"]
+margin_right = 300.0
+margin_bottom = 100.0
+
+[node name="SnakeSize" type="Label" parent="Root/StatsHUD/VBox"]
+margin_right = 300.0
+margin_bottom = 14.0
diff --git a/src/ui/ui.gd b/src/ui/ui.gd
new file mode 100644
index 0000000..cb7353e
--- /dev/null
+++ b/src/ui/ui.gd
@@ -0,0 +1,17 @@
+class_name UI
+extends CanvasLayer
+
+onready var _snake_size_label: Label = $Root/StatsHUD/VBox/SnakeSize
+
+var snake_size: int = 0
+var _snake_size_fmt: String = "Snake size: %s"
+
+
+func _ready():
+	Event.connect("snake_added_new_segment", self, "_on_Snake_added_new_segment")
+	_snake_size_label.text =_snake_size_fmt % snake_size
+
+
+func _on_Snake_added_new_segment(type: String) -> void:
+	snake_size += 1
+	_snake_size_label.text =_snake_size_fmt % snake_size
-- 
cgit v1.2.3-70-g09d2