Jam10/Scripts/GameScene.gd

203 lines
6.6 KiB
GDScript3
Raw Permalink Normal View History

2023-01-26 18:25:40 +00:00
extends Node
# _process(delta) is called by this class
# player input is handled here
# unit declares its intention in process_unit()
# stage environment interacts with the unit in interact()
# unit executes its resulting state in react()
# stage environment interacts with the unit once more in interact_post()
class_name GameScene
export var tile_set_name: String
2023-01-30 08:02:47 +00:00
export var camera_h_offset : float = 3
export var camera_v_offset : float = 1
2023-01-30 08:40:31 +00:00
export var finish_x_pos : int
export var target_time : float
export var defeat_cutscene : String
export var victory_cutscene : String
2023-01-30 13:54:29 +00:00
export var level : int
2023-01-26 18:25:40 +00:00
const Constants = preload("res://Scripts/Constants.gd")
const UNIT_DIRECTORY = {
2023-01-29 22:46:06 +00:00
Constants.UnitType.CIRNO: preload("res://Units/DownhillAutoscrollerNPCCirno.tscn"),
Constants.UnitType.SANAE: preload("res://Units/DownhillAutoscrollerNPCSanae.tscn"),
2023-01-26 18:25:40 +00:00
}
# positions to unit string
2023-01-30 13:54:29 +00:00
var spawning : Dictionary = {}
2023-01-26 18:25:40 +00:00
var spawning_map = {} # keeps track of what's alive
var paused : bool = false
2023-01-30 08:40:31 +00:00
var race_over : bool = false
2023-01-26 18:25:40 +00:00
var units = []
var player : Player
var player_cam : Camera2D
2023-01-30 08:02:47 +00:00
var player_cam_easing_cum_time : float = 0
2023-01-26 18:25:40 +00:00
# [pressed?, just pressed?, just released?]
var input_table = {
Constants.PlayerInput.UP: [false, false, false],
Constants.PlayerInput.DOWN: [false, false, false],
Constants.PlayerInput.LEFT: [false, false, false],
Constants.PlayerInput.RIGHT: [false, false, false],
Constants.PlayerInput.GBA_A: [false, false, false],
Constants.PlayerInput.GBA_B: [false, false, false],
Constants.PlayerInput.GBA_SELECT: [false, false, false],
}
const I_T_PRESSED : int = 0
const I_T_JUST_PRESSED : int = 1
const I_T_JUST_RELEASED : int = 2
var stage_env
var time_elapsed : float = 0
var stage_finished : bool = false
# for UI
var time_elapsed_in_race : float = 0
2023-01-27 22:30:20 +00:00
var player_speed_mph : float = 0
2023-01-26 18:25:40 +00:00
var rng = RandomNumberGenerator.new()
# Called when the node enters the scene tree for the first time.
func _ready():
2023-01-30 13:54:29 +00:00
if level == 1:
MusicController.play_kyouko_snow()
else:
MusicController.play_letty_snow()
2023-01-30 02:39:59 +00:00
2023-01-30 10:12:53 +00:00
units.append($Player)
2023-01-26 18:25:40 +00:00
player = units[0]
player.init_unit_w_scene(self)
2023-01-30 10:12:53 +00:00
player_cam = $Player/Camera2D
2023-01-26 18:25:40 +00:00
player_cam.make_current()
2023-01-30 08:02:47 +00:00
player_cam.offset_v = camera_v_offset
2023-01-26 18:25:40 +00:00
2023-01-30 10:12:53 +00:00
units.append($Rival)
$Rival.init_unit_w_scene(self)
2023-01-29 07:24:33 +00:00
2023-01-26 18:25:40 +00:00
stage_env = load("res://Scripts/StageEnvironment.gd").new(self)
2023-01-30 10:12:53 +00:00
$Player/Camera2D.make_current()
2023-01-26 18:25:40 +00:00
for spawning_key in spawning:
spawning_map[spawning_key] = null
2023-01-30 01:07:02 +00:00
find_node("PitTransitionPlayer").play("InitialFade")
2023-01-30 10:12:53 +00:00
target_time = $Rival.replay.length()
2023-01-26 18:25:40 +00:00
# Called every frame. 'delta' is the elapsed time since the previous frame.
2023-01-30 08:02:47 +00:00
func _process(delta):
2023-01-26 18:25:40 +00:00
# visual effects
if (player.facing == Constants.Direction.RIGHT):
2023-01-27 21:55:12 +00:00
player_cam.offset_h = camera_h_offset
2023-01-26 18:25:40 +00:00
else:
2023-01-27 21:55:12 +00:00
player_cam.offset_h = -camera_h_offset
2023-01-26 18:25:40 +00:00
read_paused()
if not paused:
# game logic
process_spawning()
for unit in units:
unit.reset_actions()
unit.handle_input(delta)
unit.process_unit(delta, time_elapsed)
stage_env.interact(unit, delta)
unit.react(delta)
time_elapsed += delta
if !stage_finished:
time_elapsed_in_race += delta
2023-01-27 22:30:20 +00:00
# 1 grid unit = 2ft, 1 grid unit / s = 1.36 mph
2023-01-30 08:40:31 +00:00
player_speed_mph = player.h_speed * 1.36
if not race_over and player.pos.x >= finish_x_pos:
race_over = true
2023-01-30 10:12:53 +00:00
if is_instance_valid(player.recorder):
player.recorder.save()
2023-01-30 08:40:31 +00:00
if time_elapsed_in_race > target_time:
# lost race
get_tree().change_scene("res://Scenes/" + defeat_cutscene + ".tscn")
else:
# won race
get_tree().change_scene("res://Scenes/" + victory_cutscene + ".tscn")
2023-01-26 18:25:40 +00:00
func read_paused():
if Input.is_action_just_pressed(Constants.INPUT_MAP[Constants.PlayerInput.GBA_START]):
paused = !paused
func process_spawning():
for one_spawn in spawning.keys():
if spawning_map[one_spawn] != null:
continue
if abs(one_spawn[0] - player.pos.x) >= Constants.SPAWN_DISTANCE + 1 or abs(one_spawn[1] - player.pos.y) >= Constants.SPAWN_DISTANCE + 1:
continue
if abs(one_spawn[0] - player.pos.x) <= Constants.SPAWN_DISTANCE:
continue
# NPCUnit
var npc_scene = UNIT_DIRECTORY[Constants.UnitType.get(spawning[one_spawn])]
var npc_instance = npc_scene.instance()
add_child(npc_instance)
units.append(npc_instance)
npc_instance.spawn_point = one_spawn
spawning_map[one_spawn] = npc_instance
npc_instance.pos.x = one_spawn[0]
npc_instance.pos.y = one_spawn[1]
npc_instance.position.x = npc_instance.pos.x * Constants.GRID_SIZE
npc_instance.position.y = -1 * npc_instance.pos.y * Constants.GRID_SIZE
npc_instance.init_unit_w_scene(self)
func handle_player_input():
# early exit
if player.get_current_action() == Constants.UnitCurrentAction.RECOILING:
player.set_action(Constants.ActionType.RECOIL)
return
for input_num in input_table.keys():
if Input.is_action_pressed(Constants.INPUT_MAP[input_num]):
input_table[input_num][I_T_PRESSED] = true
input_table[input_num][I_T_JUST_RELEASED] = false
if Input.is_action_just_pressed(Constants.INPUT_MAP[input_num]):
input_table[input_num][I_T_JUST_PRESSED] = true
else:
input_table[input_num][I_T_JUST_PRESSED] = false
else:
input_table[input_num][I_T_PRESSED] = false
input_table[input_num][I_T_JUST_PRESSED] = false
if Input.is_action_just_released(Constants.INPUT_MAP[input_num]):
input_table[input_num][I_T_JUST_RELEASED] = true
else:
input_table[input_num][I_T_JUST_RELEASED] = false
# process input_table
if input_table[Constants.PlayerInput.LEFT][I_T_PRESSED] or input_table[Constants.PlayerInput.RIGHT][I_T_PRESSED]:
if input_table[Constants.PlayerInput.LEFT][I_T_PRESSED] and input_table[Constants.PlayerInput.RIGHT][I_T_PRESSED]:
input_table[Constants.PlayerInput.LEFT][I_T_PRESSED] = false
input_table[Constants.PlayerInput.LEFT][I_T_JUST_PRESSED] = false
var input_dir
if input_table[Constants.PlayerInput.LEFT][I_T_PRESSED]:
input_dir = Constants.Direction.LEFT
else:
input_dir = Constants.Direction.RIGHT
# if action-idle or action-jumping
if (player.get_current_action() == Constants.UnitCurrentAction.IDLE
or player.get_current_action() == Constants.UnitCurrentAction.JUMPING):
# set move
player.set_action(Constants.ActionType.MOVE)
# set facing
player.facing = input_dir
if input_table[Constants.PlayerInput.GBA_A][I_T_PRESSED]:
if (player.get_current_action() == Constants.UnitCurrentAction.JUMPING
2023-01-30 16:26:49 +00:00
or ((player.get_current_action() == Constants.UnitCurrentAction.IDLE)
2023-01-26 18:25:40 +00:00
and input_table[Constants.PlayerInput.GBA_A][I_T_JUST_PRESSED])):
2023-01-30 13:54:29 +00:00
if player.unit_conditions[Constants.UnitCondition.IS_ON_GROUND] or player.get_current_action() == Constants.UnitCurrentAction.JUMPING:
player.set_action(Constants.ActionType.JUMP)
else:
player.buffer_jump()
2023-01-28 01:56:15 +00:00
player.custom_inputs()