master adding timer and windows support #6
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -1,2 +1,8 @@
|
|||
/target
|
||||
Cargo.lock
|
||||
.DS_Store
|
||||
gnu-mingw
|
||||
SDL2.dll
|
||||
SDL2_image.dll
|
||||
SDL2_ttf.dll
|
||||
/.idea
|
|
@ -17,7 +17,16 @@ features = ["image", "ttf"]
|
|||
[dependencies]
|
||||
rodio = { version = "0.15.0", optional = true}
|
||||
|
||||
[build-dependencies]
|
||||
ureq = {version = "2.6.2", features = ["native-tls"]}
|
||||
native-tls = "0.2.7"
|
||||
zip-extract = "0.1.2"
|
||||
tempfile = "3.5.0"
|
||||
|
||||
[features]
|
||||
default = ["audio"]
|
||||
static = ["sdl2/static-link", "sdl2/bundled"]
|
||||
audio = ["dep:rodio"]
|
||||
|
||||
[[example]]
|
||||
name = "example_1"
|
||||
|
|
132
build.rs
Normal file
132
build.rs
Normal file
|
@ -0,0 +1,132 @@
|
|||
#![warn(clippy::pedantic)]
|
||||
|
||||
use std::env;
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::{copy, BufWriter};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
use ureq::AgentBuilder;
|
||||
use zip_extract::extract;
|
||||
|
||||
use tempfile::tempdir;
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let target = env::var("TARGET")?;
|
||||
if target.contains("pc-windows-gnu") {
|
||||
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR")?);
|
||||
let temp = tempdir()?;
|
||||
let temp_dir = temp.path();
|
||||
|
||||
//GETTING LIBRARY DIRECTORIES GIVEN THE BUILD TARGET
|
||||
let mut lib_dir = manifest_dir.clone();
|
||||
let mut dll_dir = manifest_dir.clone();
|
||||
|
||||
let mut zip_extract = manifest_dir.clone();
|
||||
zip_extract.push("gnu-mingw");
|
||||
lib_dir.push("gnu-mingw");
|
||||
dll_dir.push("gnu-mingw");
|
||||
|
||||
let mut part = String::new();
|
||||
if target.contains("x86_64") {
|
||||
part += "x86_64-w64-mingw32";
|
||||
lib_dir.push("x86_64-w64-mingw32");
|
||||
dll_dir.push("x86_64-w64-mingw32");
|
||||
} else {
|
||||
part += "x86_64-w64-mingw32";
|
||||
lib_dir.push("i686-w64-mingw32");
|
||||
dll_dir.push("i686-w64-mingw32");
|
||||
}
|
||||
lib_dir.push("lib");
|
||||
dll_dir.push("bin");
|
||||
println!("DEBUG: Managed Dirs!");
|
||||
|
||||
if !zip_extract.exists() {
|
||||
std::fs::create_dir_all(&zip_extract)?;
|
||||
}
|
||||
|
||||
println!("DEBUG: Created Dirs!");
|
||||
|
||||
if !lib_dir.exists() {
|
||||
//NOW THAT WE HAVE THE OUTPUT DIRECTORIES, WE NEED TO EXTRACT THE ZIP FILES INTO THE
|
||||
//CORRECT DIRECTORIES
|
||||
//returns zip files
|
||||
let url_sdl = download_files(temp_dir,"https://github.com/libsdl-org/SDL/releases/download/release-2.26.4/SDL2-devel-2.26.4-mingw.zip")?;
|
||||
url_sdl.sync_all()?;
|
||||
let url_ttf = download_files(temp_dir,"https://github.com/libsdl-org/SDL_ttf/releases/download/release-2.20.2/SDL2_ttf-devel-2.20.2-mingw.zip")?;
|
||||
url_ttf.sync_all()?;
|
||||
let url_image = download_files(temp_dir,"https://github.com/libsdl-org/SDL_image/releases/download/release-2.6.3/SDL2_image-devel-2.6.3-mingw.zip")?;
|
||||
url_image.sync_all()?;
|
||||
|
||||
println!("DEBUG: Downloaded Files!");
|
||||
|
||||
let zip_vec = vec![&url_sdl, &url_ttf, &url_image];
|
||||
for file in zip_vec {
|
||||
extract(file, &zip_extract, true)?;
|
||||
println!("DEBUG: Extracted 'a' File");
|
||||
}
|
||||
temp.close()?;
|
||||
}
|
||||
|
||||
//SEARCHES AND LINKS LIBRARIES WITH CARGO
|
||||
println!("cargo:rustc-link-search=all={}", lib_dir.display());
|
||||
|
||||
for entry in std::fs::read_dir(dll_dir).expect("Can't read DLL dir") {
|
||||
let entry_path = entry.expect("Invalid fs entry").path();
|
||||
let file_name_result = entry_path.file_name();
|
||||
let mut new_file_path = manifest_dir.clone();
|
||||
if let Some(file_name) = file_name_result {
|
||||
let file_name = file_name.to_str().unwrap();
|
||||
if Path::new(file_name)
|
||||
.extension()
|
||||
.map_or(false, |ext| ext.eq_ignore_ascii_case("dll"))
|
||||
{
|
||||
new_file_path.push(file_name);
|
||||
std::fs::copy(&entry_path, new_file_path.as_path())
|
||||
.expect("Can't copy from DLL dir");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Downloads files and returns the file if it was able to be downloaded
|
||||
/// # Panics
|
||||
/// panics if no response or response lacks "content-disposition" header
|
||||
/// # Errors
|
||||
/// errors if
|
||||
/// A: unable to get `TlsConnector`
|
||||
/// B: A File is unable to be create
|
||||
/// C: or if the reader is unable to be copied into the writer
|
||||
pub fn download_files(path: &Path,url: &str) -> Result<File, Box<dyn std::error::Error>> {
|
||||
let agent = AgentBuilder::new()
|
||||
.tls_connector(Arc::new(native_tls::TlsConnector::new()?))
|
||||
.build();
|
||||
let resp = agent.get(url).call()?;
|
||||
|
||||
let content_disposition = resp.header("content-disposition").unwrap();
|
||||
let file_name = content_disposition
|
||||
.split("; ")
|
||||
.find(|s| s.starts_with("filename="))
|
||||
.unwrap()
|
||||
.split('=')
|
||||
.nth(1)
|
||||
.unwrap()
|
||||
.trim_matches('"');
|
||||
|
||||
// Create a new File object to store the downloaded zip file
|
||||
|
||||
let mut path = path.to_path_buf();
|
||||
path.push(file_name);
|
||||
let file = OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.create(true)
|
||||
.open(&path)?;
|
||||
|
||||
// Use a BufWriter to efficiently write the contents of the response to the file
|
||||
let mut writer = BufWriter::new(file);
|
||||
copy(&mut resp.into_reader(), &mut writer)?;
|
||||
|
||||
Ok(writer.into_inner()?)
|
||||
}
|
93
examples/example_1.rs
Normal file
93
examples/example_1.rs
Normal file
|
@ -0,0 +1,93 @@
|
|||
#![warn(clippy::pedantic)]
|
||||
|
||||
use cat_box::{draw_text, get_keyboard_state, get_mouse_state, Game, Sprite, SpriteCollection};
|
||||
use sdl2::keyboard::Scancode;
|
||||
|
||||
fn main() {
|
||||
let game = Game::new("catbox demo", 1000, 800);
|
||||
|
||||
let mut i = 0u8;
|
||||
let mut s = Sprite::new("duck.png", 500, 400).unwrap();
|
||||
let mut s2 = Sprite::new("duck.png", 400, 500).unwrap();
|
||||
|
||||
let bytes = include_bytes!("../duck.png");
|
||||
|
||||
let mut coll = SpriteCollection::new();
|
||||
for n in 0..10 {
|
||||
for o in 0..8 {
|
||||
let x = Sprite::from_bytes(bytes, n * 100, o * 100).unwrap();
|
||||
coll.push(x);
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "audio")]
|
||||
cat_box::play("output.mp3", 120);
|
||||
game.run(|ctx| {
|
||||
if game.step() >= 1 {
|
||||
i = (i + 1) % 255;
|
||||
ctx.set_background_colour(i, 64, 255);
|
||||
|
||||
draw_text(
|
||||
ctx,
|
||||
format!("i is {i}"),
|
||||
"MesloLGS NF Regular.ttf",
|
||||
72,
|
||||
(300, 300),
|
||||
cat_box::TextMode::Shaded {
|
||||
foreground: (255, 255, 255),
|
||||
background: (0, 0, 0),
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let (start_x, start_y) = s.position().into();
|
||||
let m = get_mouse_state(ctx);
|
||||
let x_diff = m.x - start_x;
|
||||
let y_diff = m.y - start_y;
|
||||
|
||||
let angle = f64::from(y_diff).atan2(f64::from(x_diff));
|
||||
s.set_angle(angle.to_degrees());
|
||||
|
||||
for spr in coll.iter() {
|
||||
let (start_x, start_y) = spr.position().into();
|
||||
let m = get_mouse_state(ctx);
|
||||
let x_diff = m.x - start_x;
|
||||
let y_diff = m.y - start_y;
|
||||
|
||||
let angle = f64::from(y_diff).atan2(f64::from(x_diff));
|
||||
spr.set_angle(angle.to_degrees());
|
||||
}
|
||||
|
||||
let keys = get_keyboard_state(ctx).keys;
|
||||
|
||||
for key in keys {
|
||||
let offset = match key {
|
||||
Scancode::Escape => {
|
||||
game.terminate();
|
||||
(0, 0)
|
||||
}
|
||||
Scancode::W | Scancode::Up => (0, 5),
|
||||
Scancode::S | Scancode::Down => (0, -5),
|
||||
Scancode::A | Scancode::Left => (-5, 0),
|
||||
Scancode::D | Scancode::Right => (5, 0),
|
||||
_ => (0, 0),
|
||||
};
|
||||
|
||||
s.translate(offset);
|
||||
|
||||
for spr in coll.iter() {
|
||||
spr.translate(offset);
|
||||
}
|
||||
}
|
||||
|
||||
if !cat_box::physics::check_for_collision_with_collection(&s2, &coll).is_empty() {
|
||||
println!("Sprites collided! {i}");
|
||||
}
|
||||
|
||||
game.t_reset();
|
||||
}
|
||||
s2.draw(ctx).unwrap();
|
||||
s.draw(ctx).unwrap();
|
||||
coll.draw(ctx).unwrap();
|
||||
})
|
||||
.unwrap();
|
||||
}
|
27
src/lib.rs
27
src/lib.rs
|
@ -113,6 +113,7 @@ use std::{
|
|||
ops::{Deref, DerefMut},
|
||||
path::Path,
|
||||
slice::IterMut,
|
||||
time::Instant,
|
||||
};
|
||||
use vec2::Vec2Int;
|
||||
|
||||
|
@ -706,6 +707,7 @@ pub struct Game {
|
|||
pub width: u32,
|
||||
/// The height of the opened window
|
||||
pub height: u32,
|
||||
pub time: Cell<Instant>,
|
||||
stopped: Cell<bool>,
|
||||
}
|
||||
|
||||
|
@ -725,10 +727,35 @@ impl Game {
|
|||
title: title.to_string(),
|
||||
width,
|
||||
height,
|
||||
time: Instant::now().into(),
|
||||
stopped: Cell::new(false),
|
||||
}
|
||||
}
|
||||
|
||||
///Gets time elapsed since last timer reset in milliseconds
|
||||
///
|
||||
///Run this within the game loop
|
||||
///```
|
||||
///# use cat_box::Game;
|
||||
///# let game = Game::new("wacky game", 1000, 1000);
|
||||
///# game.run(|ctx| {
|
||||
/// if game.step() >= 1000
|
||||
/// {
|
||||
/// println!("A second has passed approx!");
|
||||
/// game.t_reset();
|
||||
/// }
|
||||
///}).unwrap();
|
||||
///```
|
||||
pub fn step(&self) -> u128 {
|
||||
self.time.get().elapsed().as_millis()
|
||||
|
||||
}
|
||||
|
||||
///Resets in-game timer
|
||||
pub fn t_reset(&self) {
|
||||
self.time.set(Instant::now());
|
||||
}
|
||||
|
||||
/// Runs the game. Note: this method blocks, as it uses an infinite loop.
|
||||
///
|
||||
/// ```no_run
|
||||
|
|
90
src/main.rs
90
src/main.rs
|
@ -1,90 +0,0 @@
|
|||
#![warn(clippy::pedantic)]
|
||||
|
||||
use cat_box::{draw_text, get_keyboard_state, get_mouse_state, Game, Sprite, SpriteCollection};
|
||||
use sdl2::keyboard::Scancode;
|
||||
|
||||
fn main() {
|
||||
let game = Game::new("catbox demo", 1000, 800);
|
||||
|
||||
let mut i = 0u8;
|
||||
let mut s = Sprite::new("duck.png", 500, 400).unwrap();
|
||||
let mut s2 = Sprite::new("duck.png", 400, 500).unwrap();
|
||||
|
||||
let bytes = include_bytes!("../duck.png");
|
||||
|
||||
let mut coll = SpriteCollection::new();
|
||||
for n in 0..10 {
|
||||
for o in 0..8 {
|
||||
let x = Sprite::from_bytes(bytes, n * 100, o * 100).unwrap();
|
||||
coll.push(x);
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "audio")]
|
||||
cat_box::play("output.mp3", 120);
|
||||
game.run(|ctx| {
|
||||
i = (i + 1) % 255;
|
||||
ctx.set_background_colour(i as u8, 64, 255);
|
||||
|
||||
draw_text(
|
||||
ctx,
|
||||
format!("i is {}", i),
|
||||
"MesloLGS NF Regular.ttf",
|
||||
72,
|
||||
(300, 300),
|
||||
cat_box::TextMode::Shaded {
|
||||
foreground: (255, 255, 255),
|
||||
background: (0, 0, 0),
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let (start_x, start_y) = s.position().into();
|
||||
let m = get_mouse_state(ctx);
|
||||
let x_diff = m.x - start_x;
|
||||
let y_diff = m.y - start_y;
|
||||
|
||||
let angle = f64::from(y_diff).atan2(f64::from(x_diff));
|
||||
s.set_angle(angle.to_degrees());
|
||||
|
||||
for spr in coll.iter() {
|
||||
let (start_x, start_y) = spr.position().into();
|
||||
let m = get_mouse_state(ctx);
|
||||
let x_diff = m.x - start_x;
|
||||
let y_diff = m.y - start_y;
|
||||
|
||||
let angle = f64::from(y_diff).atan2(f64::from(x_diff));
|
||||
spr.set_angle(angle.to_degrees());
|
||||
}
|
||||
|
||||
let keys = get_keyboard_state(ctx).keys;
|
||||
|
||||
for key in keys {
|
||||
let offset = match key {
|
||||
Scancode::Escape => {
|
||||
game.terminate();
|
||||
(0, 0)
|
||||
}
|
||||
Scancode::W | Scancode::Up => (0, 5),
|
||||
Scancode::S | Scancode::Down => (0, -5),
|
||||
Scancode::A | Scancode::Left => (-5, 0),
|
||||
Scancode::D | Scancode::Right => (5, 0),
|
||||
_ => (0, 0),
|
||||
};
|
||||
|
||||
s.translate(offset);
|
||||
|
||||
for spr in coll.iter() {
|
||||
spr.translate(offset);
|
||||
}
|
||||
}
|
||||
|
||||
if !cat_box::physics::check_for_collision_with_collection(&s2, &coll).is_empty() {
|
||||
println!("Sprites collided! {}", i);
|
||||
}
|
||||
|
||||
s2.draw(ctx).unwrap();
|
||||
s.draw(ctx).unwrap();
|
||||
coll.draw(ctx).unwrap();
|
||||
})
|
||||
.unwrap();
|
||||
}
|
Loading…
Reference in a new issue