From 4b42a8ba26f21e2c6c766fa747c8b93a115a53b2 Mon Sep 17 00:00:00 2001
From: David Luevano Alvarado <david@luevano.xyz>
Date: Sun, 5 Jun 2022 09:18:35 -0600
Subject: added new tiles to ground tilemap, moved player to state machine
 paradigm

---
 src/entities/actors/snake/scripts/dash_state.gd    | 25 ++++++++
 .../actors/snake/scripts/generic_segment.gd        |  2 +-
 src/entities/actors/snake/scripts/head.gd          | 61 +++++++++---------
 src/entities/actors/snake/scripts/jump_state.gd    | 27 ++++++++
 src/entities/actors/snake/scripts/normal_state.gd  | 28 +++++++++
 src/entities/actors/snake/scripts/slow_state.gd    | 27 ++++++++
 src/entities/actors/snake/scripts/state_machine.gd | 72 ++++++++++++++++++++++
 7 files changed, 210 insertions(+), 32 deletions(-)
 create mode 100644 src/entities/actors/snake/scripts/dash_state.gd
 create mode 100644 src/entities/actors/snake/scripts/jump_state.gd
 create mode 100644 src/entities/actors/snake/scripts/normal_state.gd
 create mode 100644 src/entities/actors/snake/scripts/slow_state.gd
 create mode 100644 src/entities/actors/snake/scripts/state_machine.gd

(limited to 'src/entities/actors/snake/scripts')

diff --git a/src/entities/actors/snake/scripts/dash_state.gd b/src/entities/actors/snake/scripts/dash_state.gd
new file mode 100644
index 0000000..3eb0bdf
--- /dev/null
+++ b/src/entities/actors/snake/scripts/dash_state.gd
@@ -0,0 +1,25 @@
+extends Node
+
+var fsm: StateMachine
+
+
+func enter():
+	if fsm.DEBUG:
+		print("Got inside %s." % name)
+	Event.emit_signal("snake_started_dash")
+	Global.SNAKE_SPEED = Global.SNAKE_DASH_SPEED
+	yield(get_tree().create_timer(Global.SNAKE_DASH_TIME), "timeout")
+	exit()
+
+
+func exit():
+	Event.emit_signal("snake_finished_dash")
+	Global.SNAKE_SPEED = Global.SNAKE_SPEED_BACKUP
+	fsm.back()
+
+
+func physics_process(delta: float) -> void:
+	fsm.player.velocity = fsm.player.direction * Global.SNAKE_SPEED
+	fsm.player.velocity = fsm.player.move_and_slide(fsm.player.velocity)
+
+	fsm.slow_down_on_collisions(Global.SNAKE_DASH_SPEED)
diff --git a/src/entities/actors/snake/scripts/generic_segment.gd b/src/entities/actors/snake/scripts/generic_segment.gd
index d0bb944..a1a930a 100644
--- a/src/entities/actors/snake/scripts/generic_segment.gd
+++ b/src/entities/actors/snake/scripts/generic_segment.gd
@@ -21,4 +21,4 @@ func _on_body_entered(body: Node) -> void:
 func _on_snake_rotated() -> void:
 	# this is just random, i need to offset a tiny bit whenever the snake rotates
 	#	so that the first body segmetn doesn't catch up with the head
-	offset -= Global.SNAKE_SPEED * pow(get_physics_process_delta_time(), 2)
\ No newline at end of file
+	offset -= 0.75 * Global.SNAKE_SPEED * pow(get_physics_process_delta_time(), 2)
\ No newline at end of file
diff --git a/src/entities/actors/snake/scripts/head.gd b/src/entities/actors/snake/scripts/head.gd
index 8747910..e6824a7 100644
--- a/src/entities/actors/snake/scripts/head.gd
+++ b/src/entities/actors/snake/scripts/head.gd
@@ -9,49 +9,30 @@ onready var tongue_sprite: AnimatedSprite = $Tongue
 
 var _initial_speed: float = Global.SNAKE_SPEED
 var velocity: Vector2 = Vector2.ZERO
-var _direction: Vector2 = Vector2.UP
+var direction: Vector2 = Vector2.UP
 var _time_elapsed: float = 0.0
 
+var can_dash: bool = true
+var can_slow: bool = true
+var can_jump: bool = true
+
 
 func _ready() -> void:
 	Event.connect("food_eaten", self, "_on_food_eaten")
+	Event.connect("snake_started_dash", self, "_on_snake_started_dash")
+	Event.connect("snake_started_slow", self, "_on_snake_started_slow")
+	Event.connect("snake_started_jump", self, "_on_snake_started_jump")
 	tongue_sprite.visible = false
 
 
-func _physics_process(delta: float) -> void:
-	if Input.is_action_pressed("move_left"):
-		_rotate_to(LEFT)
-	if Input.is_action_pressed("move_right"):
-		_rotate_to(RIGHT)
-
-	velocity = _direction * Global.SNAKE_SPEED
-
-	# not sure if needed, worked wonders when using a Node2D instead of KB2D
-	velocity = move_and_slide(velocity)
-
-	# slow down on collisions, so it isn't as unfair
-	if get_last_slide_collision():
-		var speed: float = velocity.length()
-		Global.SNAKE_SPEED = speed
-	else:
-		Global.SNAKE_SPEED = Global.SNAKE_SPEED_BACKUP
-
-	# handle slow speeds
-	if Global.SNAKE_SPEED <= Global.SNAKE_SPEED_BACKUP / 4.0:
-		Global.SNAKE_SPEED = Global.SNAKE_SPEED_BACKUP
-		Event.emit_signal("game_over")
-
-	_handle_time_elapsed(delta)
-
-
-func _rotate_to(direction: int) -> void:
-	rotate(deg2rad(direction * Global.SNAKE_ROT_SPEED * get_physics_process_delta_time()))
-	_direction = _direction.rotated(deg2rad(direction * Global.SNAKE_ROT_SPEED * get_physics_process_delta_time()))
+func rotate_to(_direction: int) -> void:
+	rotate(deg2rad(_direction * Global.SNAKE_ROT_SPEED * get_physics_process_delta_time()))
+	direction = direction.rotated(deg2rad(_direction * Global.SNAKE_ROT_SPEED * get_physics_process_delta_time()))
 	Event.emit_signal("snake_rotated")
 
 
 # using a timer is not recommended for < 0.01
-func _handle_time_elapsed(delta: float) -> void:
+func handle_time_elapsed(delta: float) -> void:
 	if _time_elapsed >= Global.SNAKE_POSITION_UPDATE_INTERVAL:
 		Event.emit_signal("snake_path_new_point", global_position)
 		_time_elapsed = 0.0
@@ -65,3 +46,21 @@ func _on_food_eaten(properties: Dictionary) -> void:
 	yield(tongue_sprite, "animation_finished")
 	tongue_sprite.stop()
 	tongue_sprite.frame = 0
+
+
+func _on_snake_started_dash() -> void:
+	can_dash = false
+	yield(get_tree().create_timer(Global.SNAKE_DASH_COOLDOWN), "timeout")
+	can_dash = true
+
+
+func _on_snake_started_slow() -> void:
+	can_slow = false
+	yield(get_tree().create_timer(Global.SNAKE_SLOW_COOLDOWN), "timeout")
+	can_slow = true
+
+
+func _on_snake_started_jump() -> void:
+	can_jump = false
+	yield(get_tree().create_timer(Global.SNAKE_JUMP_COOLDOWN), "timeout")
+	can_jump = true
diff --git a/src/entities/actors/snake/scripts/jump_state.gd b/src/entities/actors/snake/scripts/jump_state.gd
new file mode 100644
index 0000000..396ceb4
--- /dev/null
+++ b/src/entities/actors/snake/scripts/jump_state.gd
@@ -0,0 +1,27 @@
+extends Node
+
+var fsm: StateMachine
+
+
+func enter():
+	if fsm.DEBUG:
+		print("Got inside %s." % name)
+	Event.emit_signal("snake_started_dash")
+	Global.SNAKE_SPEED = Global.SNAKE_DASH_SPEED
+	yield(get_tree().create_timer(Global.SNAKE_DASH_TIME), "timeout")
+	exit()
+
+
+func exit():
+	Event.emit_signal("snake_finished_dash")
+	Global.SNAKE_SPEED = Global.SNAKE_SPEED_BACKUP
+	fsm.back()
+
+
+func physics_process(delta: float) -> float:
+	fsm.player.velocity = fsm.player.direction * Global.SNAKE_SPEED
+	fsm.player.velocity = fsm.player.move_and_slide(fsm.player.velocity)
+
+	fsm.slow_down_on_collisions(Global.SNAKE_DASH_SPEED)
+
+	return delta
diff --git a/src/entities/actors/snake/scripts/normal_state.gd b/src/entities/actors/snake/scripts/normal_state.gd
new file mode 100644
index 0000000..11981a3
--- /dev/null
+++ b/src/entities/actors/snake/scripts/normal_state.gd
@@ -0,0 +1,28 @@
+extends Node
+
+var fsm: StateMachine
+
+
+func enter():
+	if fsm.DEBUG:
+		print("Got inside %s." % name)
+
+
+func exit(next_state):
+	fsm.change_to(next_state)
+
+
+func physics_process(delta: float) -> void:
+	fsm.player.velocity = fsm.player.direction * Global.SNAKE_SPEED
+	fsm.player.velocity = fsm.player.move_and_slide(fsm.player.velocity)
+
+	fsm.slow_down_on_collisions(Global.SNAKE_SPEED_BACKUP)
+
+
+func input(event: InputEvent) -> void:
+	if fsm.player.can_dash and event.is_action_pressed("dash"):
+		exit("DashState")
+	if fsm.player.can_slow and event.is_action_pressed("slow"):
+		exit("SlowState")
+	# if fsm.player.can_jump and event.is_action_pressed("jump"):
+	# 	exit("JumpState")
diff --git a/src/entities/actors/snake/scripts/slow_state.gd b/src/entities/actors/snake/scripts/slow_state.gd
new file mode 100644
index 0000000..8d54bfb
--- /dev/null
+++ b/src/entities/actors/snake/scripts/slow_state.gd
@@ -0,0 +1,27 @@
+extends Node
+
+var fsm: StateMachine
+
+
+func enter():
+	if fsm.DEBUG:
+		print("Got inside %s." % name)
+	Event.emit_signal("snake_started_slow")
+	Global.SNAKE_SPEED = Global.SNAKE_SLOW_SPEED
+	yield(get_tree().create_timer(Global.SNAKE_SLOW_TIME), "timeout")
+	exit()
+
+
+func exit():
+	Event.emit_signal("snake_finished_dash")
+	Global.SNAKE_SPEED = Global.SNAKE_SPEED_BACKUP
+	fsm.back()
+
+
+func physics_process(delta: float) -> float:
+	fsm.player.velocity = fsm.player.direction * Global.SNAKE_SPEED
+	fsm.player.velocity = fsm.player.move_and_slide(fsm.player.velocity)
+
+	fsm.slow_down_on_collisions(Global.SNAKE_SLOW_SPEED)
+
+	return delta
diff --git a/src/entities/actors/snake/scripts/state_machine.gd b/src/entities/actors/snake/scripts/state_machine.gd
new file mode 100644
index 0000000..b63f272
--- /dev/null
+++ b/src/entities/actors/snake/scripts/state_machine.gd
@@ -0,0 +1,72 @@
+class_name StateMachine
+extends Node
+
+const DEBUG: bool = false
+
+var player: KinematicBody2D
+var state: Node
+var history: Array = []
+
+
+func _ready() -> void:
+	player = get_parent()
+	state = get_child(0)
+	_enter_state()
+
+
+func change_to(new_state: String) -> void:
+	history.append(state.name)
+	state = get_node(new_state)
+	_enter_state()
+
+
+func back() -> void:
+	if history.size() > 0:
+		state = get_node(history.pop_back())
+		_enter_state()
+
+
+func _enter_state() -> void:
+	if DEBUG:
+		print("Entering state %s" % state.name)
+	state.fsm = self
+	state.enter()
+
+
+# routing game loop functions
+func _process(delta: float) -> void:
+	if state.has_method("process"):
+		state.process(delta)
+
+
+func _physics_process(delta: float) -> void:
+	if Input.is_action_pressed("move_left"):
+		player.rotate_to(player.LEFT)
+	if Input.is_action_pressed("move_right"):
+		player.rotate_to(player.RIGHT)
+
+	# state specific code, move_and_slide is called here
+	if state.has_method("physics_process"):
+		state.physics_process(delta)
+
+	handle_slow_speeds()
+
+	player.handle_time_elapsed(delta)
+
+
+func slow_down_on_collisions(speed_backup: float):
+	if player.get_last_slide_collision():
+		Global.SNAKE_SPEED = player.velocity.length()
+	else:
+		Global.SNAKE_SPEED = speed_backup
+
+
+func handle_slow_speeds() -> void:
+	if Global.SNAKE_SPEED <= Global.SNAKE_SPEED_BACKUP / 4.0:
+		Global.SNAKE_SPEED = Global.SNAKE_SPEED_BACKUP
+		Event.emit_signal("game_over")
+
+
+func _input(event: InputEvent) -> void:
+	if state.has_method("input"):
+		state.input(event)
-- 
cgit v1.2.3-70-g09d2