Add saving and loading
This commit is contained in:
parent
2fae2e6b0c
commit
66fca34202
3 changed files with 145 additions and 10 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -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]]
|
||||||
|
|
|
@ -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"] }
|
||||||
|
|
145
src/main.rs
145
src/main.rs
|
@ -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![
|
||||||
|
Menu::instant_text(
|
||||||
|
20.0,
|
||||||
|
HEIGHT_F - 40.0,
|
||||||
|
20.0,
|
||||||
|
true,
|
||||||
|
"Single click to move, Double-click to create something",
|
||||||
|
),
|
||||||
|
Menu::instant_text(
|
||||||
20.0,
|
20.0,
|
||||||
HEIGHT_F - 20.0,
|
HEIGHT_F - 20.0,
|
||||||
20.0,
|
20.0,
|
||||||
true,
|
true,
|
||||||
"Single click to move, Double-click to create something",
|
"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(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue