-use crate::faux_quicksilver::Color;
+use std::path::Path;
+
+use crate::faux_quicksilver::{Circle, Color, Rectangle, Transform, Vector};
pub trait ImageInterface {
- fn draw(&self, x: f32, y: f32) -> Result<(), String>;
+ fn draw(&mut self, x: f32, y: f32) -> Result<(), String>;
+ fn get_w(&self) -> usize;
+ fn get_h(&self) -> usize;
+ fn get_wh_rect(&self) -> Rectangle;
}
pub trait FontInterface {
- fn draw(&self, s: &str) -> Result<(), String>;
+ fn draw(&mut self, s: &str, size: u32) -> Result<(), String>;
}
pub trait SoundInterface {
- fn play(&self, vol: f32) -> Result<(), String>;
+ fn play(&mut self, vol: f32) -> Result<(), String>;
+}
+
+pub trait MusicInterface {
+ fn play(&mut self, vol: f32) -> Result<(), String>;
+ fn pause(&mut self) -> Result<(), String>;
+ fn stop(&mut self) -> Result<(), String>;
}
-pub trait WindowInterface {
+pub trait GameInterface {
fn get_dimensions(&self) -> Result<(f32, f32), String>;
- fn get_key_pressed(&self, key: char) -> Result<bool, String>;
- fn get_mouse_pressed(&self) -> Result<Option<(f32, f32)>, String>;
- fn clear_window(&self, color: Color) -> Result<(), String>;
- fn begin_drawing(&self) -> Result<(), String>;
- fn end_drawing(&self) -> Result<(), String>;
+ fn get_key_pressed(&mut self, key: char) -> Result<bool, String>;
+ fn get_mouse_pressed(&mut self) -> Result<Option<(f32, f32)>, String>;
+ fn clear_window(&mut self, color: Color) -> Result<(), String>;
+ fn begin_drawing(&mut self) -> Result<(), String>;
+ fn end_drawing(&mut self) -> Result<(), String>;
+
+ fn draw_circle(&mut self, circle: Circle, color: Color) -> Result<(), String>;
+ fn draw_circle_ex(
+ &mut self,
+ circle: Circle,
+ color: Color,
+ origin: Vector,
+ rot: f32,
+ ) -> Result<(), String>;
+ fn draw_circle_transform(
+ &mut self,
+ circle: Circle,
+ color: Color,
+ transform: Transform,
+ ) -> Result<(), String>;
+ fn draw_rect(&mut self, rect: Rectangle, color: Color) -> Result<(), String>;
+ fn draw_rect_ex(
+ &mut self,
+ rect: Rectangle,
+ color: Color,
+ origin: Vector,
+ rot: f32,
+ ) -> Result<(), String>;
+ fn draw_rect_transform(
+ &mut self,
+ rect: Rectangle,
+ color: Color,
+ transform: Transform,
+ ) -> Result<(), String>;
+
+ fn load_image(&mut self, path: &Path) -> Result<Box<dyn ImageInterface>, String>;
+ fn load_font(&mut self, path: &Path) -> Result<Box<dyn FontInterface>, String>;
+ fn load_sound(&mut self, path: &Path) -> Result<Box<dyn SoundInterface>, String>;
+ fn load_music(&mut self, path: &Path) -> Result<Box<dyn MusicInterface>, String>;
}
-use std::ops::{Mul, Add, AddAssign, Sub};
+use std::collections::HashMap;
+use std::ops::{Add, AddAssign, Mul, Sub};
+use std::path::Path;
use serde::{Deserialize, Serialize};
-use crate::agnostic_interface::WindowInterface;
+use crate::agnostic_interface::{
+ FontInterface, GameInterface, ImageInterface, MusicInterface, SoundInterface,
+};
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Color {
};
pub fn from_rgba(r: u8, g: u8, b: u8, a: u8) -> Self {
- Self {
- r,
- g,
- b,
- a,
- }
+ Self { r, g, b, a }
}
}
impl Rectangle {
pub fn new(x: f32, y: f32, w: f32, h: f32) -> Self {
- Self {
- x,
- y,
- w,
- h,
- }
+ Self { x, y, w, h }
}
pub fn pos_add_vec(&mut self, v: Vector) {
impl Circle {
pub fn new(x: f32, y: f32, r: f32) -> Self {
- Self {
- x,
- y,
- r,
- }
+ Self { x, y, r }
}
pub fn pos_add_vec(&mut self, v: Vector) {
impl Vector {
pub fn new(x: f32, y: f32) -> Self {
- Self {
- x,
- y,
- }
+ Self { x, y }
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Transform {
pub mat: [f32; 9],
+ translate: Vector,
+ rotate: f32,
}
impl Default for Transform {
fn default() -> Self {
Self {
- mat: [
- 1.0, 0.0, 0.0,
- 0.0, 1.0, 0.0,
- 0.0, 0.0, 1.0,
- ],
+ mat: [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0],
+ translate: Vector { x: 0.0, y: 0.0 },
+ rotate: 0.0,
}
}
}
self.mat[6] * rhs.mat[0] + self.mat[7] * rhs.mat[3] + self.mat[8] * rhs.mat[6],
self.mat[6] * rhs.mat[1] + self.mat[7] * rhs.mat[4] + self.mat[8] * rhs.mat[7],
self.mat[6] * rhs.mat[2] + self.mat[7] * rhs.mat[5] + self.mat[8] * rhs.mat[8],
- ]
+ ],
+ translate: self.translate + rhs.translate,
+ rotate: self.rotate + rhs.rotate,
}
}
}
pub fn rotate(rot: f32) -> Self {
Self {
mat: [
- rot.cos(), rot.sin(), 0.0,
- -rot.sin(), rot.cos(), 0.0,
- 0.0, 0.0, 1.0,
- ]
+ rot.cos(),
+ rot.sin(),
+ 0.0,
+ -rot.sin(),
+ rot.cos(),
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0,
+ ],
+ rotate: rot,
+ ..Default::default()
}
}
pub fn translate(x: f32, y: f32) -> Self {
Self {
- mat: [
- 1.0, 0.0, x,
- 0.0, 1.0, y,
- 0.0, 0.0, 1.0,
- ]
+ mat: [1.0, 0.0, x, 0.0, 1.0, y, 0.0, 0.0, 1.0],
+ translate: Vector { x, y },
+ ..Default::default()
}
}
-}
-pub struct View {
+ pub fn get_translate(&self) -> Vector {
+ self.translate
+ }
+
+ pub fn get_rotation(&self) -> f32 {
+ self.rotate
+ }
}
+pub struct View {}
+
pub struct Window {
- interface: Box<dyn WindowInterface>,
+ gi: Box<dyn GameInterface>,
+ images: HashMap<String, Box<dyn ImageInterface>>,
+ fonts: HashMap<String, Box<dyn FontInterface>>,
+ sounds: HashMap<String, Box<dyn SoundInterface>>,
+ music: HashMap<String, Box<dyn MusicInterface>>,
}
impl Window {
- pub fn new() -> Self {
+ pub fn new(gi: Box<dyn GameInterface>) -> Self {
Self {
- interface: todo!(),
+ gi,
+ images: HashMap::new(),
+ fonts: HashMap::new(),
+ sounds: HashMap::new(),
+ music: HashMap::new(),
}
}
-}
-pub struct Key {
-}
+ pub fn get_gi(&self) -> &Box<dyn GameInterface> {
+ &self.gi
+ }
-pub struct Event {
-}
+ pub fn get_gi_mut(&mut self) -> &mut Box<dyn GameInterface> {
+ &mut self.gi
+ }
-pub struct Sound {
-}
+ pub fn load_image(&mut self, path: &Path, name: String) -> Result<(), String> {
+ self.images.insert(name, self.gi.load_image(path)?);
-pub struct Font {
-}
+ Ok(())
+ }
-pub struct FontStyle {
-}
+ pub fn load_font(&mut self, path: &Path, name: String) -> Result<(), String> {
+ self.fonts.insert(name, self.gi.load_font(path)?);
-pub struct Image {
- image_w: usize,
- image_h: usize,
-}
+ Ok(())
+ }
-impl Image {
- pub fn area_rect(&self) -> Rectangle {
- Rectangle {
- x: 0.0,
- y: 0.0,
- w: self.image_w as f32,
- h: self.image_h as f32,
- }
+ pub fn load_sound(&mut self, path: &Path, name: String) -> Result<(), String> {
+ self.sounds.insert(name, self.gi.load_sound(path)?);
+
+ Ok(())
+ }
+
+ pub fn load_music(&mut self, path: &Path, name: String) -> Result<(), String> {
+ self.music.insert(name, self.gi.load_music(path)?);
+
+ Ok(())
+ }
+
+ pub fn get_image(&self, name: &str) -> Result<&Box<dyn ImageInterface>, String> {
+ Ok(self
+ .images
+ .get(name)
+ .ok_or_else(|| format!("Image \"{name}\" not found"))?)
+ }
+
+ pub fn get_image_mut(&self, name: &str) -> Result<&mut Box<dyn ImageInterface>, String> {
+ Ok(self
+ .images
+ .get_mut(name)
+ .ok_or_else(|| format!("Image \"{name}\" not found"))?)
+ }
+
+ pub fn get_font(&self, name: &str) -> Result<&Box<dyn FontInterface>, String> {
+ Ok(self
+ .fonts
+ .get(name)
+ .ok_or_else(|| format!("Font \"{name}\" not found"))?)
+ }
+
+ pub fn get_font_mut(&self, name: &str) -> Result<&mut Box<dyn FontInterface>, String> {
+ Ok(self
+ .fonts
+ .get_mut(name)
+ .ok_or_else(|| format!("Font \"{name}\" not found"))?)
+ }
+
+ pub fn get_sound(&self, name: &str) -> Result<&Box<dyn SoundInterface>, String> {
+ Ok(self
+ .sounds
+ .get(name)
+ .ok_or_else(|| format!("Sound \"{name}\" not found"))?)
+ }
+
+ pub fn get_sound_mut(&self, name: &str) -> Result<&mut Box<dyn SoundInterface>, String> {
+ Ok(self
+ .sounds
+ .get_mut(name)
+ .ok_or_else(|| format!("Sound \"{name}\" not found"))?)
+ }
+
+ pub fn get_music(&self, name: &str) -> Result<&Box<dyn MusicInterface>, String> {
+ Ok(self
+ .music
+ .get(name)
+ .ok_or_else(|| format!("Music \"{name}\" not found"))?)
+ }
+
+ pub fn get_music_mut(&self, name: &str) -> Result<&mut Box<dyn MusicInterface>, String> {
+ Ok(self
+ .music
+ .get_mut(name)
+ .ok_or_else(|| format!("Music \"{name}\" not found"))?)
}
}
+
+pub struct Key {}
+
+pub struct Event {}
mod agnostic_interface;
mod faux_quicksilver;
-use faux_quicksilver::{Color, Image, Rectangle, Circle, Vector, Transform, Window, Sound, Font, FontStyle, Event, Key, View};
+use faux_quicksilver::{Circle, Color, Event, Key, Rectangle, Transform, Vector, View, Window};
const WIDTH_F: f32 = 800.0;
const HEIGHT_F: f32 = 600.0;
enum MenuItemType {
Button {
text: &'static str,
- text_image: Option<Image>,
+ text_image: Option<String>,
text_c: Color,
h_c: Color,
c: Color,
},
AppearingText {
text: &'static str,
- text_image: Option<Image>,
+ text_image: Option<String>,
current_text: String,
text_size: f32,
text_c: Color,
},
InstantText {
text: &'static str,
- text_image: Option<Image>,
+ text_image: Option<String>,
text_size: f32,
text_color: Color,
},
return;
}
for particle in &mut self.particles {
- self.color.a = ((1.0 - (particle.life_timer / particle.lifetime) as f32) * self.opacity * 255.0) as u8;
+ self.color.a = ((1.0 - (particle.life_timer / particle.lifetime) as f32)
+ * self.opacity
+ * 255.0) as u8;
if particle.is_rect {
- let pre_transform = Transform::translate(
- -particle.rect.x / 2.0,
- -particle.rect.y / 2.0,
- ) * Transform::rotate(particle.r);
- window.draw_ex(
- &particle.rect,
- Col(self.color),
- transform * pre_transform,
- 1,
- );
+ let pre_transform =
+ Transform::translate(-particle.rect.x / 2.0, -particle.rect.y / 2.0)
+ * Transform::rotate(particle.r);
+ window
+ .get_gi_mut()
+ .draw_rect_transform(particle.rect, self.color, transform * pre_transform)
+ .ok();
} else {
- window.draw_ex(&particle.circle, Col(self.color), transform, 1);
+ window
+ .get_gi_mut()
+ .draw_circle_transform(particle.circle, self.color, transform)
+ .ok();
}
}
}
fn update(&mut self, dt: f64) {
if self.particle_system.is_rect {
let saved_rect = self.particle_system.host_rect;
- self.particle_system.host_rect.pos_add_vec(
- Transform::rotate(self.r) * Vector::new(self.offset, 0.0));
+ self.particle_system
+ .host_rect
+ .pos_add_vec(Transform::rotate(self.r) * Vector::new(self.offset, 0.0));
self.particle_system.update(dt);
self.particle_system.host_rect = saved_rect;
} else {
let saved_cir = self.particle_system.host_circle;
- self.particle_system.host_circle.pos_add_vec(
- Transform::rotate(self.r) * Vector::new(self.offset, 0.0));
+ self.particle_system
+ .host_circle
+ .pos_add_vec(Transform::rotate(self.r) * Vector::new(self.offset, 0.0));
self.particle_system.update(dt);
self.particle_system.host_circle = saved_cir;
}
moved_rect.pos_add_vec(Transform::rotate(self.r) * Vector::new(self.offset, 0.0));
let mut solid_color = self.particle_system.color;
solid_color.a = (self.particle_system.opacity * 255.0) as u8;
- window.draw_ex(
- &moved_rect,
- Col(solid_color),
- transform
- * Transform::translate(-moved_rect.x / 2.0, -moved_rect.y / 2.0)
- * Transform::rotate(self.r * 1.3),
- 1,
- );
+ window
+ .get_gi_mut()
+ .draw_rect_transform(
+ moved_rect,
+ solid_color,
+ transform
+ * Transform::translate(-moved_rect.x / 2.0, -moved_rect.y / 2.0)
+ * Transform::rotate(self.r * 1.3),
+ )
+ .ok();
} else {
let mut moved_cir = self.particle_system.host_circle;
moved_cir.pos_add_vec(Transform::rotate(self.r) * Vector::new(self.offset, 0.0));
let mut solid_color = self.particle_system.color;
solid_color.a = (self.particle_system.opacity * 255.0) as u8;
- window.draw_ex(&moved_cir, Col(solid_color), transform, 1);
+ window
+ .get_gi_mut()
+ .draw_circle_transform(moved_cir, solid_color, transform)
+ .ok();
}
}
}
return;
}
for particle in &mut self.particles {
- self.color.a = (((self.life_timer / self.lifetime) as f32 / 2.0 + 0.5) * self.opacity * 255.0) as u8;
+ self.color.a = (((self.life_timer / self.lifetime) as f32 / 2.0 + 0.5)
+ * self.opacity
+ * 255.0) as u8;
window.draw_ex(&particle.circle, Col(self.color), transform, 1);
}
}
particle_system: ParticleSystem::new(
rand::thread_rng().gen_range(2000.0, 3800.0),
900.0,
- Rectangle::new(0.0, 0.0,1.0, 1.0),
+ Rectangle::new(0.0, 0.0, 1.0, 1.0),
circle,
false,
Vector::new(0.0, 0.0),
self.r += self.velr * dt as f32;
}
- fn draw(&mut self, image: &mut Image, window: &mut Window, transform: Transform) {
+ fn draw(&mut self, image: &mut String, window: &mut Window, transform: Transform) {
self.particle_system.draw(window, transform);
let mut image_rect = image.area_rect();
image_rect.x = self.particle_system.host_circle.x - image_rect.w / 2.0;
fn draw(
&mut self,
- fish_body: &Image,
- fish_tail: &Image,
+ fish_body: &String,
+ fish_tail: &String,
window: &mut Window,
transform: Transform,
) {
}
enum SaveLoadNotification {
- Save { text: Option<Image>, timer: f64 },
- Load { text: Option<Image>, timer: f64 },
+ Save { text: Option<String>, timer: f64 },
+ Load { text: Option<String>, timer: f64 },
}
struct GameState {
s_speak_f: Sound,
font: Font,
music2: Sound,
- i_star: Option<Image>,
- i_star_actual: Option<Image>,
- i_fish: Image,
- i_fish_body: Option<Image>,
- i_fish_tail: Option<Image>,
+ i_star: Option<String>,
+ i_star_actual: Option<String>,
+ i_fish: String,
+ i_fish_body: Option<String>,
+ i_fish_tail: Option<String>,
music_on: bool,
music_timer: f64,
menu: Menu,
// spawn planet
let mut expl_conv_system = ExplConvParticleSystem::new(
rng.gen_range(1200.0, 1600.0),
- Circle::new(self.mouse_pos.x,self.mouse_pos.y, rng.gen_range(15.0, 25.0)),
+ Circle::new(
+ self.mouse_pos.x,
+ self.mouse_pos.y,
+ rng.gen_range(15.0, 25.0),
+ ),
Color::from_rgba(
rng.gen_range(0x44, 0xFF),
rng.gen_range(0x44, 0xFF),
// spawn star
let rot_clockwise = rng.gen_bool(0.5);
self.stars.push(Star::new(
- Circle::new(self.mouse_pos.x, self.mouse_pos.y, rng.gen_range(3.0, 7.0)),
+ Circle::new(
+ self.mouse_pos.x,
+ self.mouse_pos.y,
+ rng.gen_range(3.0, 7.0),
+ ),
Color::from_rgba(
rng.gen_range(0x58, 0xFF),
rng.gen_range(0x58, 0xFF),
self.player = save_data.player;
self.joining_particles = save_data.joining_particles;
self.expl_conv_p_systems.clear();
- self.move_to = Vector{ x: self.player.x, y: self.player.y};
+ self.move_to = Vector {
+ x: self.player.x,
+ y: self.player.y,
+ };
self.camera.x = self.player.x - WIDTH_F / 2.0;
self.camera.y = self.player.y - HEIGHT_F / 2.0;
self.dbl_click_timeout = None;
self.player.y += (self.move_to.y - self.player.y) / 20.0;
self.player_particles.host_rect.x = self.player.x;
self.player_particles.host_rect.y = self.player.y;
- self.joining_particles.particle_system.host_rect.x += (self.player.x - self.joining_particles.particle_system.host_rect.x) / 30.0;
- self.joining_particles.particle_system.host_rect.y += (self.player.y - self.joining_particles.particle_system.host_rect.y) / 30.0;
+ self.joining_particles.particle_system.host_rect.x +=
+ (self.player.x - self.joining_particles.particle_system.host_rect.x) / 30.0;
+ self.joining_particles.particle_system.host_rect.y +=
+ (self.player.y - self.joining_particles.particle_system.host_rect.y) / 30.0;
self.camera.x += (self.player.x - WIDTH_F / 2.0 - self.camera.x) / 40.0;
self.camera.y += (self.player.y - HEIGHT_F / 2.0 - self.camera.y) / 40.0;
window.set_view(View::new(self.camera));
}
fn draw(&mut self, window: &mut Window) -> Result<(), String> {
- window.clear(Color::BLACK)?;
+ window.get_gi_mut().clear_window(Color::BLACK)?;
let mut rect = Rectangle::default();
for mi in &mut self.menu.items {
rect.x = mi.x;
c,
} => {
if mi.is_hover {
- window.draw(&rect, Col(*h_c));
+ window.get_gi_mut().draw_rect(rect, *h_c)?;
} else {
- window.draw(&rect, Col(*c));
+ window.get_gi_mut().draw_rect(rect, *c)?;
}
if let Some(i) = text_image {
- let mut image_rect = i.area_rect();
+ let image = window.get_image_mut(&i)?;
+ let mut image_rect = image.get_wh_rect();
image_rect.x = mi.x + (mi.w - image_rect.w) / 2.0;
image_rect.y = mi.y + (mi.h - image_rect.h) / 2.0;
- window.draw(&image_rect, Img(i));
+ image.draw(image_rect.x, image_rect.y)?;
}
}
MenuItemType::AppearingText {
timer,
} => {
if let Some(i) = text_image {
- let mut image_rect = i.area();
- image_rect.pos.x = mi.x;
- image_rect.pos.y = mi.y;
- window.draw(&image_rect, Img(i));
+ let image = window.get_image_mut(&i)?;
+ image.draw(mi.x, mi.y)?;
}
}
MenuItemType::InstantText {
text_color,
} => {
if let Some(i) = text_image {
- let mut image_rect = i.area();
- image_rect.pos.x = mi.x;
- image_rect.pos.y = mi.y;
- window.draw(&image_rect, Img(i));
+ let image = window.get_image_mut(&i)?;
+ let mut image_rect = image.get_wh_rect();
+ image.draw(mi.x, mi.y)?;
}
}
MenuItemType::Pause { timer, length } => (),
}
}
self.player_particles.draw(window, Transform::IDENTITY);
- window.draw_ex(
- &self.player,
- Col(Color::from_rgba(
- 0xFF,
- 0xFF,
- 0xFF,
- (self.player_particles.opacity * 255.0) as u8,
- )),
+ window.get_gi_mut().draw_rect_transform(
+ self.player,
+ Color::from_rgba(255, 255, 255, (self.player_particles.opacity * 255.0) as u8),
Transform::translate(-self.player.x / 2.0, -self.player.y / 2.0)
* Transform::rotate(self.player_r as f32),
- 1,
- );
+ )?;
self.joining_particles.draw(window, Transform::IDENTITY);
for expl_conv_ps in &mut self.expl_conv_p_systems {
expl_conv_ps.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 * 255.0) as u8;
- let mut image_rect = i.area_rect();
- image_rect.x = self.camera.x + 20.0;
- image_rect.y = self.camera.y + 20.0;
- window.draw(&image_rect, Blended(i, c));
- }
- }
- }
- }
+ // TODO
+ //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 * 255.0) as u8;
+ // let mut image_rect = i.area_rect();
+ // image_rect.x = self.camera.x + 20.0;
+ // image_rect.y = self.camera.y + 20.0;
+ // window.draw(&image_rect, Blended(i, c));
+ // }
+ // }
+ // }
+ //}
Ok(())
}
}
fn main() {
- run::<GameState>(
- "One And All - a Ludum Dare 45 compo entry",
- Vector::new(800, 600),
- Settings::default(),
- );
+ // TODO
+ //run::<GameState>(
+ // "One And All - a Ludum Dare 45 compo entry",
+ // Vector::new(800, 600),
+ // Settings::default(),
+ //);
}