Add cutscene support to the game
This commit is contained in:
parent
5e29a94b60
commit
21e4dc7daa
264
game/game_logic/src/scenes/cutscenes.rs
Normal file
264
game/game_logic/src/scenes/cutscenes.rs
Normal file
@ -0,0 +1,264 @@
|
||||
//! This scene encompasses the main menu system
|
||||
|
||||
use chrono::Duration;
|
||||
use na::Vector1;
|
||||
use nalgebra as na;
|
||||
use raylib::{
|
||||
ffi::{GetMouseX, GetMouseY, IsMouseButtonDown, Texture},
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
discord::{DiscordChannel, DiscordRpcSignal},
|
||||
global_resource_package::GlobalResources,
|
||||
persistent::settings::PersistentGameSettings,
|
||||
project_constants::ProjectConstants,
|
||||
};
|
||||
|
||||
use super::main_menu::MenuStateSignal;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CutScenes {
|
||||
show_debug_info: bool,
|
||||
}
|
||||
|
||||
impl CutScenes {
|
||||
/// Construct a new `CutScenes`
|
||||
pub fn new(
|
||||
raylib_handle: &mut RaylibHandle,
|
||||
thread: &RaylibThread,
|
||||
constants: &ProjectConstants,
|
||||
game_settings: &mut PersistentGameSettings,
|
||||
) -> Self {
|
||||
Self {
|
||||
show_debug_info: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn render_bartender_cutscene_frame(
|
||||
&mut self,
|
||||
raylib: &mut RaylibHandle,
|
||||
rl_thread: &RaylibThread,
|
||||
discord: &DiscordChannel,
|
||||
global_resources: &GlobalResources,
|
||||
constants: &ProjectConstants,
|
||||
audio_subsystem: &mut RaylibAudio,
|
||||
) -> MenuStateSignal {
|
||||
// Get a drawing handle
|
||||
let mut draw = raylib.begin_drawing(rl_thread);
|
||||
|
||||
// Clear the screen
|
||||
draw.clear_background(Color::WHITE);
|
||||
|
||||
//Obtain mouse position
|
||||
let mouse_x = draw.get_mouse_x();
|
||||
let mouse_y = draw.get_mouse_y();
|
||||
|
||||
// Optionally display debug info
|
||||
if draw.is_key_pressed(KeyboardKey::KEY_F3) {
|
||||
self.show_debug_info = !self.show_debug_info;
|
||||
}
|
||||
if self.show_debug_info {
|
||||
// Draw FPS and mouse location
|
||||
draw.draw_fps(10, 10);
|
||||
draw.draw_text(
|
||||
format!("Mouse position: ({}, {})", mouse_x, mouse_y).as_str(),
|
||||
10,
|
||||
30,
|
||||
20,
|
||||
Color::GREEN,
|
||||
);
|
||||
}
|
||||
|
||||
// Title
|
||||
draw.draw_text("INTRO CUTSCENE GOES HERE", 100, 90, 60, Color::BLACK);
|
||||
draw.draw_text("Press SPACE to skip", 100, 600, 20, Color::BLACK);
|
||||
|
||||
// Let the user leave this cutscene by pressing space
|
||||
if draw.is_key_pressed(KeyboardKey::KEY_SPACE) {
|
||||
return MenuStateSignal::StartGame;
|
||||
}
|
||||
|
||||
// Return MenuStateSignal::DoMainMenu if you want to return to the main menu
|
||||
// Return MenuStateSignal::StartGame if you want the game to start.
|
||||
// Otherwise, keep returning MenuStateSignal::DoIntroCutscene
|
||||
return MenuStateSignal::DoIntroCutscene;
|
||||
}
|
||||
|
||||
pub async fn render_melted_cutscene_frame(
|
||||
&mut self,
|
||||
raylib: &mut RaylibHandle,
|
||||
rl_thread: &RaylibThread,
|
||||
discord: &DiscordChannel,
|
||||
global_resources: &GlobalResources,
|
||||
constants: &ProjectConstants,
|
||||
audio_subsystem: &mut RaylibAudio,
|
||||
playtime: &Duration,
|
||||
) -> MenuStateSignal {
|
||||
// Get a drawing handle
|
||||
let mut draw = raylib.begin_drawing(rl_thread);
|
||||
|
||||
// Clear the screen
|
||||
draw.clear_background(Color::WHITE);
|
||||
|
||||
//Obtain mouse position
|
||||
let mouse_x = draw.get_mouse_x();
|
||||
let mouse_y = draw.get_mouse_y();
|
||||
|
||||
// Optionally display debug info
|
||||
if draw.is_key_pressed(KeyboardKey::KEY_F3) {
|
||||
self.show_debug_info = !self.show_debug_info;
|
||||
}
|
||||
if self.show_debug_info {
|
||||
// Draw FPS and mouse location
|
||||
draw.draw_fps(10, 10);
|
||||
draw.draw_text(
|
||||
format!("Mouse position: ({}, {})", mouse_x, mouse_y).as_str(),
|
||||
10,
|
||||
30,
|
||||
20,
|
||||
Color::GREEN,
|
||||
);
|
||||
}
|
||||
|
||||
// Title
|
||||
draw.draw_text("MELTY CUTSCENE GOES HERE", 100, 90, 60, Color::BLACK);
|
||||
draw.draw_text(
|
||||
&format!("This took you {} seconds", playtime.num_seconds()),
|
||||
100,
|
||||
600,
|
||||
20,
|
||||
Color::BLACK,
|
||||
);
|
||||
draw.draw_text("Press SPACE to skip", 100, 680, 20, Color::BLACK);
|
||||
|
||||
// Let the user leave this cutscene by pressing space
|
||||
if draw.is_key_pressed(KeyboardKey::KEY_SPACE) {
|
||||
return MenuStateSignal::DoMainMenu;
|
||||
}
|
||||
|
||||
// Return MenuStateSignal::DoMainMenu if you want to return to the main menu
|
||||
// Otherwise, keep returning MenuStateSignal::DoMeltedDeathCutscene
|
||||
return MenuStateSignal::DoMeltedDeathCutscene {
|
||||
playtime: playtime.clone(),
|
||||
};
|
||||
}
|
||||
|
||||
pub async fn render_finished_cutscene_frame(
|
||||
&mut self,
|
||||
raylib: &mut RaylibHandle,
|
||||
rl_thread: &RaylibThread,
|
||||
discord: &DiscordChannel,
|
||||
global_resources: &GlobalResources,
|
||||
constants: &ProjectConstants,
|
||||
audio_subsystem: &mut RaylibAudio,
|
||||
playtime: &Duration,
|
||||
) -> MenuStateSignal {
|
||||
// Get a drawing handle
|
||||
let mut draw = raylib.begin_drawing(rl_thread);
|
||||
|
||||
// Clear the screen
|
||||
draw.clear_background(Color::WHITE);
|
||||
|
||||
//Obtain mouse position
|
||||
let mouse_x = draw.get_mouse_x();
|
||||
let mouse_y = draw.get_mouse_y();
|
||||
|
||||
// Optionally display debug info
|
||||
if draw.is_key_pressed(KeyboardKey::KEY_F3) {
|
||||
self.show_debug_info = !self.show_debug_info;
|
||||
}
|
||||
if self.show_debug_info {
|
||||
// Draw FPS and mouse location
|
||||
draw.draw_fps(10, 10);
|
||||
draw.draw_text(
|
||||
format!("Mouse position: ({}, {})", mouse_x, mouse_y).as_str(),
|
||||
10,
|
||||
30,
|
||||
20,
|
||||
Color::GREEN,
|
||||
);
|
||||
}
|
||||
|
||||
// Title
|
||||
draw.draw_text("END CUTSCENE GOES HERE", 100, 90, 60, Color::BLACK);
|
||||
draw.draw_text(
|
||||
&format!("This took you {} seconds", playtime.num_seconds()),
|
||||
100,
|
||||
600,
|
||||
20,
|
||||
Color::BLACK,
|
||||
);
|
||||
draw.draw_text("Press SPACE to skip", 100, 680, 20, Color::BLACK);
|
||||
|
||||
// Let the user leave this cutscene by pressing space
|
||||
if draw.is_key_pressed(KeyboardKey::KEY_SPACE) {
|
||||
return MenuStateSignal::DoMainMenu;
|
||||
}
|
||||
|
||||
// Return MenuStateSignal::DoMainMenu if you want to return to the main menu
|
||||
// Otherwise, keep returning MenuStateSignal::DoFinishedCutscene
|
||||
return MenuStateSignal::DoFinishedCutscene {
|
||||
playtime: playtime.clone(),
|
||||
};
|
||||
}
|
||||
|
||||
pub async fn render_ocean_cutscene_frame(
|
||||
&mut self,
|
||||
raylib: &mut RaylibHandle,
|
||||
rl_thread: &RaylibThread,
|
||||
discord: &DiscordChannel,
|
||||
global_resources: &GlobalResources,
|
||||
constants: &ProjectConstants,
|
||||
audio_subsystem: &mut RaylibAudio,
|
||||
playtime: &Duration,
|
||||
) -> MenuStateSignal {
|
||||
// Get a drawing handle
|
||||
let mut draw = raylib.begin_drawing(rl_thread);
|
||||
|
||||
// Clear the screen
|
||||
draw.clear_background(Color::WHITE);
|
||||
|
||||
//Obtain mouse position
|
||||
let mouse_x = draw.get_mouse_x();
|
||||
let mouse_y = draw.get_mouse_y();
|
||||
|
||||
// Optionally display debug info
|
||||
if draw.is_key_pressed(KeyboardKey::KEY_F3) {
|
||||
self.show_debug_info = !self.show_debug_info;
|
||||
}
|
||||
if self.show_debug_info {
|
||||
// Draw FPS and mouse location
|
||||
draw.draw_fps(10, 10);
|
||||
draw.draw_text(
|
||||
format!("Mouse position: ({}, {})", mouse_x, mouse_y).as_str(),
|
||||
10,
|
||||
30,
|
||||
20,
|
||||
Color::GREEN,
|
||||
);
|
||||
}
|
||||
|
||||
// Title
|
||||
draw.draw_text("OCEAN CUTSCENE GOES HERE", 100, 90, 60, Color::BLACK);
|
||||
draw.draw_text(
|
||||
&format!("This took you {} seconds", playtime.num_seconds()),
|
||||
100,
|
||||
600,
|
||||
20,
|
||||
Color::BLACK,
|
||||
);
|
||||
draw.draw_text("Press SPACE to skip", 100, 680, 20, Color::BLACK);
|
||||
|
||||
// Let the user leave this cutscene by pressing space
|
||||
if draw.is_key_pressed(KeyboardKey::KEY_SPACE) {
|
||||
return MenuStateSignal::DoMainMenu;
|
||||
}
|
||||
|
||||
// Return MenuStateSignal::DoMainMenu if you want to return to the main menu
|
||||
// Otherwise, keep returning MenuStateSignal::DoOceanCutscene
|
||||
return MenuStateSignal::DoOceanCutscene {
|
||||
playtime: playtime.clone(),
|
||||
};
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
//! This scene encompasses the main menu system
|
||||
|
||||
use chrono::Duration;
|
||||
use na::Vector1;
|
||||
use nalgebra as na;
|
||||
use raylib::{
|
||||
@ -23,6 +24,10 @@ pub enum MenuStateSignal {
|
||||
DoCredits,
|
||||
DoLeaderboard,
|
||||
DoPauseMenu,
|
||||
DoIntroCutscene,
|
||||
DoMeltedDeathCutscene { playtime: Duration },
|
||||
DoFinishedCutscene { playtime: Duration },
|
||||
DoOceanCutscene { playtime: Duration },
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -119,7 +124,7 @@ impl MainMenu {
|
||||
draw.draw_text("Start Game", 100, 190, 34, label_colors);
|
||||
if draw.is_mouse_button_pressed(MouseButton::MOUSE_LEFT_BUTTON) {
|
||||
audio_subsystem.play_sound(&global_resources.button_click_sound);
|
||||
return MenuStateSignal::StartGame;
|
||||
return MenuStateSignal::DoIntroCutscene;
|
||||
}
|
||||
}
|
||||
|
||||
@ -364,7 +369,7 @@ impl MainMenu {
|
||||
return MenuStateSignal::QuitGame;
|
||||
}
|
||||
}
|
||||
// Return MenuStateSignal::StartGame if you want the game to start.
|
||||
// Return MenuStateSignal::DoIntroCutscene if you want the game to start.
|
||||
// Otherwise, keep returning MenuStateSignal::DoMainMenu until the player clicks the start button
|
||||
return MenuStateSignal::DoMainMenu;
|
||||
}
|
||||
|
@ -13,11 +13,13 @@ use crate::{
|
||||
};
|
||||
|
||||
use self::{
|
||||
cutscenes::CutScenes,
|
||||
main_menu::{MainMenu, MenuStateSignal},
|
||||
pause_menu::PauseMenu,
|
||||
player_interaction::PlayableScene,
|
||||
test_fox::TestFoxScene,
|
||||
};
|
||||
mod cutscenes;
|
||||
mod main_menu;
|
||||
mod pause_menu;
|
||||
mod player_interaction;
|
||||
@ -34,6 +36,7 @@ pub struct SceneRenderDelegate {
|
||||
scene_playable: PlayableScene,
|
||||
scene_main_menu: MainMenu,
|
||||
scene_pause_menu: PauseMenu,
|
||||
scene_cutscenes: CutScenes,
|
||||
}
|
||||
|
||||
impl SceneRenderDelegate {
|
||||
@ -51,6 +54,7 @@ impl SceneRenderDelegate {
|
||||
let scene_playable = PlayableScene::new(raylib, rl_thread, constants);
|
||||
let scene_main_menu = MainMenu::new(raylib, rl_thread, constants, game_settings);
|
||||
let scene_pause_menu = PauseMenu::new(raylib, rl_thread, constants, game_settings);
|
||||
let scene_cutscenes = CutScenes::new(raylib, rl_thread, constants, game_settings);
|
||||
|
||||
Self {
|
||||
menu_control_signal: MenuStateSignal::DoMainMenu,
|
||||
@ -60,6 +64,7 @@ impl SceneRenderDelegate {
|
||||
scene_playable,
|
||||
scene_main_menu,
|
||||
scene_pause_menu,
|
||||
scene_cutscenes,
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,9 +82,10 @@ impl SceneRenderDelegate {
|
||||
save_state: &mut GameSaveState,
|
||||
) {
|
||||
// Render the main menu if in it, otherwise, render the game
|
||||
match self.menu_control_signal {
|
||||
match &self.menu_control_signal {
|
||||
MenuStateSignal::StartGame => {
|
||||
self.menu_control_signal = self.scene_playable
|
||||
self.menu_control_signal = self
|
||||
.scene_playable
|
||||
.render_frame(
|
||||
raylib,
|
||||
rl_thread,
|
||||
@ -159,6 +165,61 @@ impl SceneRenderDelegate {
|
||||
)
|
||||
.await;
|
||||
}
|
||||
MenuStateSignal::DoIntroCutscene => {
|
||||
self.menu_control_signal = self
|
||||
.scene_cutscenes
|
||||
.render_bartender_cutscene_frame(
|
||||
raylib,
|
||||
rl_thread,
|
||||
discord,
|
||||
global_resources,
|
||||
constants,
|
||||
&mut self.audio_subsystem,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
MenuStateSignal::DoMeltedDeathCutscene { playtime } => {
|
||||
self.menu_control_signal = self
|
||||
.scene_cutscenes
|
||||
.render_melted_cutscene_frame(
|
||||
raylib,
|
||||
rl_thread,
|
||||
discord,
|
||||
global_resources,
|
||||
constants,
|
||||
&mut self.audio_subsystem,
|
||||
playtime,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
MenuStateSignal::DoFinishedCutscene { playtime } => {
|
||||
self.menu_control_signal = self
|
||||
.scene_cutscenes
|
||||
.render_finished_cutscene_frame(
|
||||
raylib,
|
||||
rl_thread,
|
||||
discord,
|
||||
global_resources,
|
||||
constants,
|
||||
&mut self.audio_subsystem,
|
||||
playtime,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
MenuStateSignal::DoOceanCutscene { playtime } => {
|
||||
self.menu_control_signal = self
|
||||
.scene_cutscenes
|
||||
.render_ocean_cutscene_frame(
|
||||
raylib,
|
||||
rl_thread,
|
||||
discord,
|
||||
global_resources,
|
||||
constants,
|
||||
&mut self.audio_subsystem,
|
||||
playtime,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
//! This scene encompasses all of the game where the player can walk around.
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use nalgebra as na;
|
||||
use raylib::prelude::*;
|
||||
use std::time::SystemTime;
|
||||
@ -25,6 +26,7 @@ pub struct PlayableScene {
|
||||
game_soundtrack: Music,
|
||||
world_colliders: Vec<WorldSpaceObjectCollider>,
|
||||
show_debug_info: bool,
|
||||
play_start_time: DateTime<Utc>,
|
||||
}
|
||||
|
||||
impl PlayableScene {
|
||||
@ -64,6 +66,7 @@ impl PlayableScene {
|
||||
game_soundtrack,
|
||||
world_colliders,
|
||||
show_debug_info: false,
|
||||
play_start_time: Utc::now(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,6 +94,7 @@ impl PlayableScene {
|
||||
.await
|
||||
.unwrap();
|
||||
self.has_updated_discord_rpc = true;
|
||||
self.play_start_time = Utc::now();
|
||||
}
|
||||
|
||||
// Ensure the game soundtrack is playing
|
||||
@ -111,6 +115,17 @@ impl PlayableScene {
|
||||
|
||||
self.draw_ui(&mut draw, constants);
|
||||
|
||||
// NOTE: If you want to trigger a cutscene, do it here by using one of:
|
||||
// return MenuStateSignal::DoFinishedCutscene {
|
||||
// playtime: Utc::now().signed_duration_since(self.play_start_time),
|
||||
// };
|
||||
// return MenuStateSignal::DoMeltedDeathCutscene {
|
||||
// playtime: Utc::now().signed_duration_since(self.play_start_time),
|
||||
// };
|
||||
// return MenuStateSignal::DoOceanCutscene {
|
||||
// playtime: Utc::now().signed_duration_since(self.play_start_time),
|
||||
// };
|
||||
|
||||
// A little hack to make pausing work
|
||||
if draw.is_key_pressed(KeyboardKey::KEY_ESCAPE) {
|
||||
return MenuStateSignal::DoPauseMenu;
|
||||
@ -124,8 +139,12 @@ impl PlayableScene {
|
||||
let mut ctx2d = draw.begin_mode2D(self.camera);
|
||||
|
||||
// Render the map
|
||||
self.world_map
|
||||
.render_map(&mut ctx2d, &self.camera, self.show_debug_info, self.player.position);
|
||||
self.world_map.render_map(
|
||||
&mut ctx2d,
|
||||
&self.camera,
|
||||
self.show_debug_info,
|
||||
self.player.position,
|
||||
);
|
||||
|
||||
let player_size =
|
||||
(constants.tile_size as f32 * constants.player.start_size * self.player.size) as i32;
|
||||
|
Reference in New Issue
Block a user