diff --git a/.gitignore b/.gitignore index ea8c4bf..bf0a94c 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ +/build/* +!/build/index.html + /target diff --git a/Cargo.lock b/Cargo.lock index e204520..77d4fa1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1968,6 +1968,17 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" +[[package]] +name = "chacha20" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" +dependencies = [ + "cfg-if", + "cpufeatures", + "rand_core", +] + [[package]] name = "codespan-reporting" version = "0.12.0" @@ -2627,8 +2638,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" dependencies = [ "cfg-if", + "js-sys", "libc", "r-efi 6.0.0", + "rand_core", + "wasm-bindgen", ] [[package]] @@ -4098,6 +4112,9 @@ name = "pong" version = "0.1.0" dependencies = [ "bevy", + "chacha20", + "getrandom 0.4.3", + "rand", ] [[package]] @@ -4213,6 +4230,7 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" dependencies = [ + "chacha20", "getrandom 0.4.3", "rand_core", ] diff --git a/Cargo.toml b/Cargo.toml index 7c66e6c..cc270b2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,14 @@ edition = "2024" [dependencies] bevy = "0.19.0" +chacha20 = { version = "0.10.1", default-features = false, features = ["rng"] } +getrandom = "0.4.3" +rand = "0.10.2" + +[features] +default = ["debug"] +debug = ["bevy/debug"] +wasm = ["getrandom/wasm_js"] # Enable some optimization in development so the game runs well. # Enable more optimization for dependencies because they change less often. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..99a3eaa --- /dev/null +++ b/Makefile @@ -0,0 +1,16 @@ +.DEFAULT_GOAL := help + +.PHONY: help +help: ## List targets in this Makefile + @awk 'BEGIN { FS = ":|:.*?## "; OFS="\t" }; /^[0-9a-zA-Z_-]+?:/ { print $$1, $$2 }' $(MAKEFILE_LIST) \ + | column --separator $$'\t' --table --table-wrap 2 --output-separator ' ' \ + | sort --dictionary-order + +.PHONY: build +build: + cargo build --release --target wasm32-unknown-unknown --no-default-features --features wasm + wasm-bindgen --target web --out-dir build target/wasm32-unknown-unknown/release/pong.wasm + +.PHONY: publish +publish: + rsync --verbose --checksum --recursive --safe-links --delete --progress build/ root@lab:/www/games/pong diff --git a/build/index.html b/build/index.html new file mode 100644 index 0000000..325f6d0 --- /dev/null +++ b/build/index.html @@ -0,0 +1,23 @@ + + + + + Pong + + + diff --git a/clippy.toml b/clippy.toml new file mode 100644 index 0000000..05bfba2 --- /dev/null +++ b/clippy.toml @@ -0,0 +1,5 @@ +# Bevy query types can get a bit more complicated than usual Rust code. +type-complexity-threshold = 1000 + +# Bevy systems sometimes rely on a lot of different entities. +too-many-arguments-threshold = 10 diff --git a/src/ball.rs b/src/ball.rs new file mode 100644 index 0000000..24da111 --- /dev/null +++ b/src/ball.rs @@ -0,0 +1,131 @@ +use bevy::math::bounding::{Aabb2d, Bounded2d, BoundingVolume, IntersectsVolume}; +use bevy::prelude::*; + +use crate::hud::Hud; +use crate::{GameState, Player}; + +pub struct BallPlugin; + +impl Plugin for BallPlugin { + fn build(&self, app: &mut App) { + app.init_resource::() + .add_systems(Startup, spawn_ball) + .add_systems( + FixedUpdate, + (collision, movement) + .chain() + .run_if(in_state(GameState::Game)), + ); + } +} + +#[derive(Component, Debug, Clone, Copy)] +pub struct Ball; + +#[derive(Component, Debug, Clone, Copy, PartialEq, Default, Deref, DerefMut)] +pub struct Velocity(pub Vec2); + +#[derive(Resource, Debug, Default, Deref, DerefMut)] +pub struct ServeAngle(pub f32); + +#[derive(Event, Debug)] +pub struct Serve; + +#[derive(Component)] +pub enum Collision { + Wall(CollisionWall), + Paddle(CollisionPaddle), +} + +#[derive(Debug)] +pub struct CollisionWall { + pub plane: Plane2d, +} + +#[derive(Debug)] +pub struct CollisionPaddle { + pub normal: Vec2, + pub rect: Aabb2d, +} + +pub const BALL_SIZE: f32 = 10.; + +const V_MULTIPLIER: f32 = 1.5; +pub const V_MIN: f32 = 80.; +pub const V_MAX: f32 = 500.; + +fn spawn_ball( + mut commands: Commands, + mut meshes: ResMut>, + mut materials: ResMut>, +) { + commands.spawn(( + Mesh2d(meshes.add(Rectangle::from_length(BALL_SIZE))), + MeshMaterial2d(materials.add(ColorMaterial::from_color(Color::WHITE))), + Transform::from_translation(Vec3::ZERO), + Ball, + Velocity(Vec2::ZERO), + )); + + commands.add_observer(on_serve); +} + +fn movement(time: Res