forked from karx/catbox
Compare commits
1 commit
Author | SHA1 | Date | |
---|---|---|---|
gallant | 660fe25234 |
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -1,2 +1,8 @@
|
||||||
/target
|
/target
|
||||||
Cargo.lock
|
Cargo.lock
|
||||||
|
.DS_Store
|
||||||
|
gnu-mingw
|
||||||
|
SDL2.dll
|
||||||
|
SDL2_image.dll
|
||||||
|
SDL2_ttf.dll
|
||||||
|
/.idea
|
|
@ -17,7 +17,16 @@ features = ["image", "ttf"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rodio = { version = "0.15.0", optional = true}
|
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]
|
[features]
|
||||||
default = ["audio"]
|
default = ["audio"]
|
||||||
static = ["sdl2/static-link", "sdl2/bundled"]
|
static = ["sdl2/static-link", "sdl2/bundled"]
|
||||||
audio = ["dep:rodio"]
|
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},
|
ops::{Deref, DerefMut},
|
||||||
path::Path,
|
path::Path,
|
||||||
slice::IterMut,
|
slice::IterMut,
|
||||||
|
time::Instant,
|
||||||
};
|
};
|
||||||
use vec2::Vec2Int;
|
use vec2::Vec2Int;
|
||||||
|
|
||||||
|
@ -706,6 +707,7 @@ pub struct Game {
|
||||||
pub width: u32,
|
pub width: u32,
|
||||||
/// The height of the opened window
|
/// The height of the opened window
|
||||||
pub height: u32,
|
pub height: u32,
|
||||||
|
pub time: Cell<Instant>,
|
||||||
stopped: Cell<bool>,
|
stopped: Cell<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -725,10 +727,35 @@ impl Game {
|
||||||
title: title.to_string(),
|
title: title.to_string(),
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
|
time: Instant::now().into(),
|
||||||
stopped: Cell::new(false),
|
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.
|
/// Runs the game. Note: this method blocks, as it uses an infinite loop.
|
||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```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