diff --git a/Replays/Rival.dat b/Replays/Rival.dat new file mode 100644 index 0000000..bdbc7f4 Binary files /dev/null and b/Replays/Rival.dat differ diff --git a/Scenes/DownhillAutoscroller.tscn b/Scenes/DownhillAutoscroller.tscn index 16656cf..a12ff84 100644 --- a/Scenes/DownhillAutoscroller.tscn +++ b/Scenes/DownhillAutoscroller.tscn @@ -1,8 +1,4 @@ -<<<<<<< HEAD -[gd_scene load_steps=17 format=2] -======= -[gd_scene load_steps=18 format=2] ->>>>>>> e02aaa26c207234404f2d1f585dca170392fddfe +[gd_scene load_steps=20 format=2] [ext_resource path="res://Tile Sets/SnowySlopes.tres" type="TileSet" id=1] [ext_resource path="res://Units/DownhillAutoscrollerPlayer.tscn" type="PackedScene" id=2] @@ -18,6 +14,8 @@ [ext_resource path="res://Fonts/squares/squares.tres" type="DynamicFont" id=12] [ext_resource path="res://Scripts/InGameUI.gd" type="Script" id=13] [ext_resource path="res://Fonts/squares/squares_big.tres" type="DynamicFont" id=14] +[ext_resource path="res://Scripts/Units/FollowReplay.gd" type="Script" id=15] +[ext_resource path="res://Scripts/PlayerRecorder.gd" type="Script" id=16] [sub_resource type="Animation" id=3] resource_name = "InitialFade" @@ -126,15 +124,16 @@ offset = Vector2( 0, -15 ) smoothing_speed = 7.0 [node name="PlayerRecorder" type="Node" parent="Player"] -script = ExtResource( 13 ) +script = ExtResource( 16 ) +save_to = "res://Replays/ReplayOutput.dat" [node name="SpectatorCam" type="Camera2D" parent="."] offset = Vector2( 0, -15 ) [node name="Rival" parent="." instance=ExtResource( 6 )] position = Vector2( 91, -197 ) -script = ExtResource( 12 ) -unit_type = 0 +script = ExtResource( 15 ) +replay_file = "res://Replays/Rival.dat" [node name="CanvasLayer" type="CanvasLayer" parent="."] script = ExtResource( 13 ) diff --git a/Scripts/GameScene.gd b/Scripts/GameScene.gd index 06bffe6..d9e9fef 100644 --- a/Scripts/GameScene.gd +++ b/Scripts/GameScene.gd @@ -16,7 +16,6 @@ export var target_time : float export var defeat_cutscene : String export var victory_cutscene : String const Constants = preload("res://Scripts/Constants.gd") -const Unit = preload("res://Scripts/Unit.gd") const UNIT_DIRECTORY = { Constants.UnitType.CIRNO: preload("res://Units/DownhillAutoscrollerNPCCirno.tscn"), Constants.UnitType.SANAE: preload("res://Units/DownhillAutoscrollerNPCSanae.tscn"), @@ -64,22 +63,24 @@ var rng = RandomNumberGenerator.new() func _ready(): MusicController.play_kyouko_snow() - units.append(get_node("Player")) + units.append($Player) player = units[0] player.init_unit_w_scene(self) - player_cam = player.get_node("Camera2D") + player_cam = $Player/Camera2D player_cam.make_current() player_cam.offset_v = camera_v_offset - units.append(get_node("Rival")) - get_node("Rival").init_unit_w_scene(self) + units.append($Rival) + $Rival.init_unit_w_scene(self) stage_env = load("res://Scripts/StageEnvironment.gd").new(self) - player.get_node("Camera2D").make_current() + $Player/Camera2D.make_current() for spawning_key in spawning: spawning_map[spawning_key] = null find_node("PitTransitionPlayer").play("InitialFade") + + target_time = $Rival.replay.length() # Called every frame. 'delta' is the elapsed time since the previous frame. func _process(delta): @@ -107,6 +108,10 @@ func _process(delta): if not race_over and player.pos.x >= finish_x_pos: race_over = true + + if is_instance_valid(player.recorder): + player.recorder.save() + if time_elapsed_in_race > target_time: # lost race get_tree().change_scene("res://Scenes/" + defeat_cutscene + ".tscn") diff --git a/Scripts/InGameUI.gd b/Scripts/InGameUI.gd index c3ede8f..e4458b0 100644 --- a/Scripts/InGameUI.gd +++ b/Scripts/InGameUI.gd @@ -21,18 +21,16 @@ var timer : RichTextLabel func _ready(): scene = get_node("/root/Scene") player = get_node("/root/Scene/Player") - speedometer = get_node("Speedometer") - timer = get_node("Timer") - boost_label = get_node("BoostLabel") + speedometer = $Speedometer + timer = $Timer + boost_label = $BoostLabel # Called every frame. 'delta' is the elapsed time since the previous frame. func _process(delta): - speedometer.text = str(floor(scene.player_speed_mph)) + " MPH" + speedometer.text = " %d MPH" % scene.player_speed_mph - var dec_value : int = floor((scene.time_elapsed_in_race - floor(scene.time_elapsed_in_race)) - * 100) - timer.text = str(floor(scene.time_elapsed_in_race)) + ":" + str(dec_value) + timer.text = (" %05.2f" % scene.time_elapsed_in_race).replace(".", ":") if player.get_current_action() == Constants.UnitCurrentAction.SPINNING: flash_boost = false diff --git a/Scripts/PlayerRecorder.gd b/Scripts/PlayerRecorder.gd index 9e84843..b80d57b 100644 --- a/Scripts/PlayerRecorder.gd +++ b/Scripts/PlayerRecorder.gd @@ -4,17 +4,23 @@ class_name PlayerRecorder var replay: ReplayRecording var this_frame: bool = true var sprite: int = 0 -var player: DownhillAutoscrollerPlayer +var player: Node +var scene: Node export var save_to: String +export var enabled: bool func _ready(): + if not enabled: + queue_free() + replay = ReplayRecording.new() replay.time_per_frame = 1.0 / 30.0 player = get_parent() player.recorder = self + scene = player.get_parent() -func _process(delta): +func _process(_delta): if this_frame: this_frame = false replay.positions.append(player.pos) @@ -23,3 +29,7 @@ func _process(delta): else: this_frame = true + +func save(): + replay.save_to_uri(save_to) + queue_free() diff --git a/Scripts/ReplayRecording.gd b/Scripts/ReplayRecording.gd index ab942ae..5187e15 100644 --- a/Scripts/ReplayRecording.gd +++ b/Scripts/ReplayRecording.gd @@ -1,6 +1,8 @@ extends Object class_name ReplayRecording +const TAPER: float = 7.0 + var time_per_frame: float var frames: int = 0 @@ -13,7 +15,7 @@ func load_from(file: File): positions = [] sprites = [] - for i in range(frames): + for _i in range(frames): var x: float = file.get_real() var y: float = file.get_real() positions.append(Vector2(x, y)) @@ -44,10 +46,13 @@ func position(frame: int) -> Vector2: if frame < frames: return positions[frame] else: - return positions[-1] + return lerp(positions[-2], positions[-1], 2 + TAPER * atan((frame - frames) / TAPER)) func sprite(frame: int) -> int: if frame < frames: return sprites[frame] else: return sprites[-1] + +func length() -> float: + return time_per_frame * frames diff --git a/Scripts/Unit.gd b/Scripts/Unit.gd index 1c054d2..a5549df 100644 --- a/Scripts/Unit.gd +++ b/Scripts/Unit.gd @@ -238,15 +238,20 @@ func handle_idle(): else: set_sprite(Constants.SpriteClass.JUMP, 1) -func set_sprite(sprite_class : int, index : int = 0): +func set_sprite(sprite_class: int, index: int = 0, ignore_bad_values: bool = false): + if ignore_bad_values: + if not(unit_type in Constants.UNIT_SPRITES) or not(sprite_class in Constants.UNIT_SPRITES[unit_type]): + return + assert(unit_type in Constants.UNIT_SPRITES) assert(sprite_class in Constants.UNIT_SPRITES[unit_type]) + var node_list = sprite_class_nodes[sprite_class] var true_index : int = index if true_index > len(node_list) - 1: true_index = 0 - if recorder != null: + if is_instance_valid(recorder): recorder.sprite = (index << 3) | sprite_class var new_sprite : Node2D = node_list[true_index] diff --git a/Scripts/Units/FollowReplay.gd b/Scripts/Units/FollowReplay.gd index 3462e1c..1029cd1 100644 --- a/Scripts/Units/FollowReplay.gd +++ b/Scripts/Units/FollowReplay.gd @@ -2,10 +2,18 @@ extends Unit var replay : ReplayRecording = null +export var replay_file: String + +func _ready(): + ._ready() + replay = ReplayRecording.new() + replay.load_from_uri(replay_file) + + func process_unit(delta : float, time_elapsed : float): self.time_elapsed = time_elapsed - if replay != null: + if replay != null and replay.time_per_frame > 0: handle_replay(time_elapsed) func handle_replay(at_time: float): @@ -18,4 +26,4 @@ func handle_replay(at_time: float): var index: int = sprite >> 3 sprite &= 7 - set_sprite(sprite, index) + set_sprite(sprite, index, true)