diff --git a/.gitignore b/.gitignore
index bf0a94c..6b04bfa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
-/build/*
-!/build/index.html
+/build/*/*
+!/build/breakout/index.html
+!/build/paddle/index.html
/target
diff --git a/Cargo.toml b/Cargo.toml
index e08b822..ad35080 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -2,6 +2,7 @@
name = "breakout"
version = "0.1.0"
edition = "2024"
+default-run = "breakout"
[dependencies]
bevy = { version = "0.19.0", features = ["debug_glam_assert"] }
@@ -9,6 +10,9 @@ chacha20 = { version = "0.10.1", default-features = false, features = ["rng"] }
getrandom = "0.4.3"
rand = "0.10.2"
+[[bin]]
+name = "paddle"
+
[features]
default = ["debug"]
debug = ["bevy/debug"]
diff --git a/Makefile b/Makefile
index d93b7c6..072a803 100644
--- a/Makefile
+++ b/Makefile
@@ -8,9 +8,12 @@ help: ## List targets in this Makefile
.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/breakout.wasm
+ cargo build --bin breakout --release --target wasm32-unknown-unknown --no-default-features --features wasm
+ wasm-bindgen --target web --out-dir build/breakout target/wasm32-unknown-unknown/release/breakout.wasm
+
+ cargo build --bin paddle --release --target wasm32-unknown-unknown --no-default-features --features wasm
+ wasm-bindgen --target web --out-dir build/paddle target/wasm32-unknown-unknown/release/paddle.wasm
.PHONY: publish
publish:
- rsync --verbose --checksum --recursive --safe-links --delete --progress build/ root@lab:/www/games/breakout
+ rsync --verbose --checksum --recursive --safe-links --delete --progress build/breakout/ root@lab:/www/games/breakout
diff --git a/build/index.html b/build/breakout/index.html
similarity index 100%
rename from build/index.html
rename to build/breakout/index.html
diff --git a/build/paddle/index.html b/build/paddle/index.html
new file mode 100644
index 0000000..453547e
--- /dev/null
+++ b/build/paddle/index.html
@@ -0,0 +1,40 @@
+
+
+
+
+ Breakout
+
+
+
+
+
+ Use
+ ⬅
+ ➡
+ to move the paddle and
+ WASD
+ to move the ball.
+
+
+
+
+
diff --git a/src/bin/paddle.rs b/src/bin/paddle.rs
new file mode 100644
index 0000000..f1c6795
--- /dev/null
+++ b/src/bin/paddle.rs
@@ -0,0 +1,156 @@
+use bevy::ecs::query::QueryData;
+use bevy::math::bounding::Aabb2d;
+use bevy::prelude::*;
+
+use breakout::debug::DebugPlugin;
+use breakout::*;
+
+const WORLD_SIZE: Vec2 = Vec2::new(480., 320.);
+const CAMERA_SCALE: f32 = 2.;
+
+fn main() {
+ App::new()
+ .insert_resource(ClearColor(Color::BLACK))
+ .add_plugins(DebugPlugin)
+ .add_plugins(DefaultPlugins.set(WindowPlugin {
+ // Until there's a reliable way to hint that a game window should
+ // float on tiling window managers, the most reliable way to achieve
+ // that is to define a fixed non-resizable window.
+ //
+ // https://github.com/rust-windowing/winit/issues/862#issuecomment-2047791401
+ primary_window: Some(Window {
+ focused: false,
+ canvas: Some("#paddle".into()),
+ resize_constraints: WindowResizeConstraints {
+ min_width: CAMERA_SCALE * WORLD_SIZE.x,
+ min_height: CAMERA_SCALE * WORLD_SIZE.y,
+ max_width: CAMERA_SCALE * WORLD_SIZE.x,
+ max_height: CAMERA_SCALE * WORLD_SIZE.y,
+ },
+ ..default()
+ }),
+ ..default()
+ }))
+ .add_systems(Startup, setup)
+ .add_systems(
+ FixedUpdate,
+ (move_paddle, move_ball, draw_trajectory).chain(),
+ )
+ .run();
+}
+
+const PADDLE_START: Vec3 = Vec3::new(WORLD_SIZE.x / 2., Paddle::SIZE.y / 2. + Paddle::GAP, 0.);
+
+fn setup(
+ mut commands: Commands,
+ mut meshes: ResMut>,
+ mut materials: ResMut>,
+) {
+ commands.spawn((
+ Camera2d,
+ Transform::from_translation((WORLD_SIZE / 2.).extend(0.)),
+ Projection::Orthographic(OrthographicProjection {
+ scale: 1. / CAMERA_SCALE,
+ ..OrthographicProjection::default_2d()
+ }),
+ ));
+
+ commands.spawn(Ball::build(&mut meshes, &mut materials));
+
+ commands.spawn((
+ Paddle,
+ Sprite::from_color(Paddle::COLOR, Vec2::ONE),
+ Transform {
+ translation: PADDLE_START,
+ scale: Paddle::SIZE.extend(1.),
+ ..default()
+ },
+ Collider::Aabb(Aabb2d::new(Vec2::ZERO, Paddle::SIZE / 2.)),
+ ));
+}
+
+pub fn move_paddle(
+ time: Res