Add saving and loading

This commit is contained in:
Stephen Seo 2019-10-06 15:01:18 +09:00
parent 2fae2e6b0c
commit 66fca34202
3 changed files with 145 additions and 10 deletions

1
Cargo.lock generated
View file

@ -999,6 +999,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"quicksilver 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "quicksilver 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]

View file

@ -9,3 +9,4 @@ edition = "2018"
[dependencies] [dependencies]
quicksilver = "0.3.19" quicksilver = "0.3.19"
rand = "0.7.2" rand = "0.7.2"
serde = { version = "1.0.101", features = ["derive"] }

View file

@ -1,15 +1,17 @@
use quicksilver::{ use quicksilver::{
geom::{Circle, Rectangle, Transform, Vector}, geom::{Circle, Rectangle, Transform, Vector},
graphics::{ graphics::{
Background::{Col, Img}, Background::{Blended, Col, Img},
Color, Font, FontStyle, Image, View, Color, Font, FontStyle, Image, View,
}, },
input::{ButtonState, Key}, input::{ButtonState, Key},
lifecycle::{run, Asset, Event, Settings, State, Window}, lifecycle::{run, Asset, Event, Settings, State, Window},
saving::{load, save},
sound::Sound, sound::Sound,
Result, Result,
}; };
use rand::prelude::*; use rand::prelude::*;
use serde::{Deserialize, Serialize};
const WIDTH_F: f32 = 800.0; const WIDTH_F: f32 = 800.0;
const HEIGHT_F: f32 = 600.0; const HEIGHT_F: f32 = 600.0;
@ -23,6 +25,7 @@ const JOINING_OPACITY_RATE: f32 = 0.00013;
const JOINING_FAR_DIST: f32 = 700.0; const JOINING_FAR_DIST: f32 = 700.0;
const JOINING_NEAR_DIST: f32 = 150.0; const JOINING_NEAR_DIST: f32 = 150.0;
const DOUBLE_CLICK_TIME: f64 = 350.0; const DOUBLE_CLICK_TIME: f64 = 350.0;
const SL_NOTIF_TIME: f64 = 5000.0;
fn interp_sq_inv(x: f32) -> f32 { fn interp_sq_inv(x: f32) -> f32 {
if x < 0.0 { if x < 0.0 {
@ -515,17 +518,27 @@ impl Menu {
fn s_10() -> Menu { fn s_10() -> Menu {
Menu { Menu {
items: vec![Menu::instant_text( items: vec![
20.0, Menu::instant_text(
HEIGHT_F - 20.0, 20.0,
20.0, HEIGHT_F - 40.0,
true, 20.0,
"Single click to move, Double-click to create something", true,
)], "Single click to move, Double-click to create something",
),
Menu::instant_text(
20.0,
HEIGHT_F - 20.0,
20.0,
true,
"S - save; L - load (can load from the start)",
),
],
} }
} }
} }
#[derive(Serialize, Deserialize, Clone)]
struct Particle { struct Particle {
rect: Rectangle, rect: Rectangle,
circle: Circle, circle: Circle,
@ -538,6 +551,7 @@ struct Particle {
life_timer: f64, life_timer: f64,
} }
#[derive(Serialize, Deserialize, Clone)]
struct ParticleSystem { struct ParticleSystem {
particles: Vec<Particle>, particles: Vec<Particle>,
spawn_timer: f64, spawn_timer: f64,
@ -647,6 +661,7 @@ impl ParticleSystem {
} }
} }
#[derive(Serialize, Deserialize, Clone)]
struct RotatingParticleSystem { struct RotatingParticleSystem {
particle_system: ParticleSystem, particle_system: ParticleSystem,
r: f32, r: f32,
@ -813,6 +828,7 @@ impl ExplConvParticleSystem {
} }
} }
#[derive(Serialize, Deserialize, Clone)]
struct Planet { struct Planet {
circle: Circle, circle: Circle,
color: Color, color: Color,
@ -841,7 +857,7 @@ impl Planet {
moons: Vec::new(), moons: Vec::new(),
}; };
let mut r: f32 = rand::thread_rng().gen_range(0.0, 360.0); let r: f32 = rand::thread_rng().gen_range(0.0, 360.0);
for i in 0..rand::thread_rng().gen_range(0, 5) { for i in 0..rand::thread_rng().gen_range(0, 5) {
planet.moons.push(RotatingParticleSystem::new( planet.moons.push(RotatingParticleSystem::new(
rand::thread_rng().gen_range(1000.0, 2600.0), rand::thread_rng().gen_range(1000.0, 2600.0),
@ -880,6 +896,18 @@ impl Planet {
} }
} }
#[derive(Serialize, Deserialize, Clone)]
struct SaveData {
planets: Vec<Planet>,
player: Rectangle,
joining_particles: RotatingParticleSystem,
}
enum SaveLoadNotification {
Save { text: Option<Image>, timer: f64 },
Load { text: Option<Image>, timer: f64 },
}
struct GameState { struct GameState {
s_boom: Asset<Sound>, s_boom: Asset<Sound>,
s_get: Asset<Sound>, s_get: Asset<Sound>,
@ -911,6 +939,7 @@ struct GameState {
planets: Vec<Planet>, planets: Vec<Planet>,
camera: Rectangle, camera: Rectangle,
move_to: Vector, move_to: Vector,
save_load_notification: Option<SaveLoadNotification>,
} }
impl State for GameState { impl State for GameState {
@ -969,6 +998,7 @@ impl State for GameState {
planets: Vec::new(), planets: Vec::new(),
camera: Rectangle::new((0.0, 0.0), (WIDTH_F, HEIGHT_F)), camera: Rectangle::new((0.0, 0.0), (WIDTH_F, HEIGHT_F)),
move_to: Vector::new(400.0, 300.0), move_to: Vector::new(400.0, 300.0),
save_load_notification: None,
}) })
} }
@ -1141,6 +1171,48 @@ impl State for GameState {
} }
} }
} }
Event::Key(key, state) => {
if let ButtonState::Pressed = state {
match key {
Key::S => {
if self.state == 10 {
let save_data = SaveData {
planets: self.planets.clone(),
player: self.player.clone(),
joining_particles: self.joining_particles.clone(),
};
save("OneAndAll_LD45", "slot0", &save_data)?;
self.save_load_notification = Some(SaveLoadNotification::Save {
text: None,
timer: SL_NOTIF_TIME,
});
}
}
Key::L => {
let load_result = load::<SaveData>("OneAndAll_LD45", "slot0");
if let Ok(save_data) = load_result {
self.planets = save_data.planets.clone();
self.player = save_data.player.clone();
self.joining_particles = save_data.joining_particles.clone();
self.move_to = self.player.pos;
self.camera.pos =
self.player.pos - Vector::new(WIDTH_F / 2.0, HEIGHT_F / 2.0);
self.dbl_click_timeout = None;
self.click_time = None;
self.click_release_time = DOUBLE_CLICK_TIME;
self.state = 10;
self.state_dirty = true;
self.save_load_notification = Some(SaveLoadNotification::Load {
text: None,
timer: SL_NOTIF_TIME,
});
}
}
_ => (),
}
}
}
_ => (), _ => (),
} }
Ok(()) Ok(())
@ -1165,7 +1237,9 @@ impl State for GameState {
} }
self.player.pos += (self.move_to - self.player.pos) / 20.0; self.player.pos += (self.move_to - self.player.pos) / 20.0;
self.player_particles.host_rect = self.player; self.player_particles.host_rect.pos = self.player.pos;
self.joining_particles.particle_system.host_rect.pos +=
(self.player.pos - self.joining_particles.particle_system.host_rect.pos) / 30.0;
self.camera.pos += self.camera.pos +=
(self.player.pos - Vector::new(WIDTH_F / 2.0, HEIGHT_F / 2.0) - self.camera.pos) / 40.0; (self.player.pos - Vector::new(WIDTH_F / 2.0, HEIGHT_F / 2.0) - self.camera.pos) / 40.0;
window.set_view(View::new(self.camera)); window.set_view(View::new(self.camera));
@ -1277,7 +1351,19 @@ impl State for GameState {
self.music_timer = 0.0; self.music_timer = 0.0;
self.music2.execute(|m2| m2.play())?; self.music2.execute(|m2| m2.play())?;
} }
} else if self.state == 10 {
let mut music_on = false;
self.music2.execute(|m2| {
music_on = true;
m2.set_volume(0.6);
m2.play()
})?;
if music_on {
self.music_on = true;
self.music_timer = 0.0;
}
} }
for i in 0..self.menu.items.len() { for i in 0..self.menu.items.len() {
let mi: &mut MenuItem = &mut self.menu.items[i]; let mi: &mut MenuItem = &mut self.menu.items[i];
if !mi.is_loaded { if !mi.is_loaded {
@ -1387,6 +1473,37 @@ impl State for GameState {
planet.update(dt); planet.update(dt);
} }
if let Some(sl) = &mut self.save_load_notification {
match sl {
SaveLoadNotification::Save { text, timer } => {
*timer -= dt;
if *timer <= 0.0 {
self.save_load_notification = None;
} else if text.is_none() {
self.font.execute(|f| {
*text = Some(
f.render("Saved the Game", &FontStyle::new(45.0, Color::WHITE))?,
);
Ok(())
})?;
}
}
SaveLoadNotification::Load { text, timer } => {
*timer -= dt;
if *timer <= 0.0 {
self.save_load_notification = None;
} else if text.is_none() {
self.font.execute(|f| {
*text = Some(
f.render("Loaded the Game", &FontStyle::new(45.0, Color::WHITE))?,
);
Ok(())
})?;
}
}
}
}
Ok(()) Ok(())
} }
@ -1469,6 +1586,22 @@ impl State for GameState {
for planet in &mut self.planets { for planet in &mut self.planets {
planet.draw(window, Transform::IDENTITY); planet.draw(window, Transform::IDENTITY);
} }
if let Some(sl) = &mut self.save_load_notification {
match sl {
SaveLoadNotification::Save { text, timer }
| SaveLoadNotification::Load { text, timer } => {
if let Some(i) = text {
let mut c = Color::WHITE;
c.a = (*timer / SL_NOTIF_TIME) as f32;
let mut image_rect = i.area();
image_rect.pos = self.camera.pos + Vector::new(20.0, 20.0);
window.draw(&image_rect, Blended(i, c));
}
}
}
}
Ok(()) Ok(())
} }
} }