Compare commits
14 Commits
b1fd2e5f73
...
v0.6.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 76426094d3 | |||
| 4b101633e7 | |||
| a5a6f32037 | |||
| 4d899d3c97 | |||
| 6d5afc2445 | |||
| d34d0a31f2 | |||
| 72f062ea10 | |||
| eecfbf5d7c | |||
| 1e09e3ce3a | |||
| 19ac032792 | |||
| de75e25ca6 | |||
| d7802bdbed | |||
| ae093d2c9c | |||
| 3963b548b9 |
26
Cargo.lock
generated
26
Cargo.lock
generated
@@ -242,7 +242,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "asteroids"
|
name = "asteroids"
|
||||||
version = "0.6.0-dev2"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy",
|
"bevy",
|
||||||
"bevy-inspector-egui",
|
"bevy-inspector-egui",
|
||||||
@@ -1848,9 +1848,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.49"
|
version = "1.2.50"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "90583009037521a116abf44494efecd645ba48b6622457080f080b85544e2215"
|
checksum = "9f50d563227a1c37cc0a263f64eca3334388c01c5e4c4861a9def205c614383c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"find-msvc-tools",
|
"find-msvc-tools",
|
||||||
"jobserver",
|
"jobserver",
|
||||||
@@ -4470,9 +4470,9 @@ checksum = "c3d6831663a5098ea164f89cff59c6284e95f4e3c76ce9848d4529f5ccca9bde"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rangemap"
|
name = "rangemap"
|
||||||
version = "1.7.0"
|
version = "1.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "acbbbbea733ec66275512d0b9694f34102e7d5406fdbe2ad8d21b28dce92887c"
|
checksum = "973443cf09a9c8656b574a866ab68dfa19f0867d0340648c7d2f6a71b8a8ea68"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rapier2d"
|
name = "rapier2d"
|
||||||
@@ -5167,9 +5167,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_datetime"
|
name = "toml_datetime"
|
||||||
version = "0.7.4+spec-1.0.0"
|
version = "0.7.5+spec-1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fe3cea6b2aa3b910092f6abd4053ea464fab5f9c170ba5e9a6aead16ec4af2b6"
|
checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_core",
|
"serde_core",
|
||||||
]
|
]
|
||||||
@@ -5188,18 +5188,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_parser"
|
name = "toml_parser"
|
||||||
version = "1.0.5+spec-1.0.0"
|
version = "1.0.6+spec-1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4c03bee5ce3696f31250db0bbaff18bc43301ce0e8db2ed1f07cbb2acf89984c"
|
checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winnow",
|
"winnow",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing"
|
name = "tracing"
|
||||||
version = "0.1.43"
|
version = "0.1.44"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2d15d90a0b5c19378952d479dc858407149d7bb45a14de0142f6c534b16fc647"
|
checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"tracing-attributes",
|
"tracing-attributes",
|
||||||
@@ -5219,9 +5219,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing-core"
|
name = "tracing-core"
|
||||||
version = "0.1.35"
|
version = "0.1.36"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c"
|
checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"valuable",
|
"valuable",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "asteroids"
|
name = "asteroids"
|
||||||
version = "0.6.0-dev2"
|
version = "0.6.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
license = "AGPL-3.0-only"
|
license = "AGPL-3.0-only"
|
||||||
|
|
||||||
|
|||||||
17
Makefile
17
Makefile
@@ -12,23 +12,26 @@ CARGO_PROFILE := tiny
|
|||||||
SRC_DIR = ./src
|
SRC_DIR = ./src
|
||||||
SRCS := $(wildcard $(SRC_DIR)/**)
|
SRCS := $(wildcard $(SRC_DIR)/**)
|
||||||
|
|
||||||
|
ASSET_SOURCE := $(wildcard assets/**)
|
||||||
|
ASSETS := $(patsubst assets/%.ogg, out/assets/%.ogg, $(ASSET_SOURCE))
|
||||||
|
|
||||||
.PHONY: clean full-clean tarball tarball-standalone web web-standalone
|
.PHONY: clean full-clean tarball tarball-standalone web web-standalone
|
||||||
|
|
||||||
# "Standalone" version. It includes an index.html to serve as-is
|
# "Standalone" version. It includes an index.html to serve as-is
|
||||||
web-standalone: out/asteroids.js out/asteroids_bg.wasm.gz out/index.html
|
web-standalone: out/asteroids.js out/asteroids_bg.wasm.gz out/index.html $(ASSETS)
|
||||||
|
|
||||||
# "Bundle-able" version. It has a page, but no index.html. Consumers are
|
# "Bundle-able" version. It has a page, but no index.html. Consumers are
|
||||||
# expected to provide their own index.html and link to this page.
|
# expected to provide their own index.html and link to this page.
|
||||||
web: out/asteroids.js out/asteroids_bg.wasm.gz out/asteroids.html
|
web: out/asteroids.js out/asteroids_bg.wasm.gz out/asteroids.html $(ASSETS)
|
||||||
|
|
||||||
tarball: asteroids_web_root.tar
|
tarball: asteroids_web_root.tar
|
||||||
|
|
||||||
tarball_standalone: asteroids_web_root_standalone.tar
|
tarball_standalone: asteroids_web_root_standalone.tar
|
||||||
|
|
||||||
asteroids_web_root.tar: out/asteroids.js out/asteroids_bg.wasm.gz out/asteroids.html
|
asteroids_web_root.tar: out/asteroids.js out/asteroids_bg.wasm.gz out/asteroids.html $(ASSETS)
|
||||||
tar -caf $@ $^
|
tar -caf $@ $^
|
||||||
|
|
||||||
asteroids_web_root_standalone.tar: out/asteroids.js out/asteroids_bg.wasm.gz out/index.html
|
asteroids_web_root_standalone.tar: out/asteroids.js out/asteroids_bg.wasm.gz out/index.html $(ASSETS)
|
||||||
tar -caf $@ $^
|
tar -caf $@ $^
|
||||||
|
|
||||||
target/$(CARGO_TARGET)/$(CARGO_PROFILE)/asteroids.wasm: $(SRCS) Cargo.lock Cargo.toml
|
target/$(CARGO_TARGET)/$(CARGO_PROFILE)/asteroids.wasm: $(SRCS) Cargo.lock Cargo.toml
|
||||||
@@ -37,6 +40,12 @@ target/$(CARGO_TARGET)/$(CARGO_PROFILE)/asteroids.wasm: $(SRCS) Cargo.lock Cargo
|
|||||||
out:
|
out:
|
||||||
mkdir $@
|
mkdir $@
|
||||||
|
|
||||||
|
out/assets: | out
|
||||||
|
mkdir $@
|
||||||
|
|
||||||
|
out/assets/%.ogg: assets/%.ogg | out/assets
|
||||||
|
cp -ar assets/$*.ogg $@
|
||||||
|
|
||||||
# Both the JS and WASM files are generated by the wasm-bindgen call, so both
|
# Both the JS and WASM files are generated by the wasm-bindgen call, so both
|
||||||
# get to be on the target half of this recipe.
|
# get to be on the target half of this recipe.
|
||||||
out/asteroids.js out/asteroids_bg.wasm.gz &: target/$(CARGO_TARGET)/$(CARGO_PROFILE)/asteroids.wasm | out
|
out/asteroids.js out/asteroids_bg.wasm.gz &: target/$(CARGO_TARGET)/$(CARGO_PROFILE)/asteroids.wasm | out
|
||||||
|
|||||||
BIN
assets/explosionCrunch_000.ogg
Normal file
BIN
assets/explosionCrunch_000.ogg
Normal file
Binary file not shown.
BIN
assets/laserSmall_001.ogg
Normal file
BIN
assets/laserSmall_001.ogg
Normal file
Binary file not shown.
BIN
assets/thrusterFire_004.ogg
Normal file
BIN
assets/thrusterFire_004.ogg
Normal file
Binary file not shown.
@@ -9,19 +9,21 @@ pub const UI_BUTTON_NORMAL: Color = Color::srgb(0.15, 0.15, 0.15); // Button col
|
|||||||
pub const UI_BUTTON_HOVERED: Color = Color::srgb(0.25, 0.25, 0.25); // ... when it's hovered
|
pub const UI_BUTTON_HOVERED: Color = Color::srgb(0.25, 0.25, 0.25); // ... when it's hovered
|
||||||
pub const UI_BUTTON_PRESSED: Color = Color::srgb(0.55, 0.55, 0.55); // ... when it's pressed
|
pub const UI_BUTTON_PRESSED: Color = Color::srgb(0.55, 0.55, 0.55); // ... when it's pressed
|
||||||
|
|
||||||
pub(crate) const BACKGROUND_COLOR: Color = Color::srgb(0.3, 0.3, 0.3);
|
pub(crate) const BACKGROUND_COLOR: Color = Color::srgb(0.1, 0.1, 0.1);
|
||||||
pub(crate) const PLAYER_SHIP_COLOR: Color = Color::srgb(1.0, 1.0, 1.0);
|
pub(crate) const PLAYER_SHIP_COLOR: Color = Color::srgb(1.0, 1.0, 1.0);
|
||||||
pub(crate) const SHIP_THRUSTER_COLOR_ACTIVE: Color = Color::srgb(1.0, 0.2, 0.2);
|
pub(crate) const SHIP_THRUSTER_COLOR_ACTIVE: Color = Color::srgb(1.0, 0.2, 0.2);
|
||||||
pub(crate) const SHIP_THRUSTER_COLOR_INACTIVE: Color = Color::srgb(0.5, 0.5, 0.5);
|
pub(crate) const SHIP_THRUSTER_COLOR_INACTIVE: Color = Color::srgb(0.5, 0.5, 0.5);
|
||||||
pub(crate) const SHIP_FIRE_RATE: f32 = 3.0; // in bullets-per-second
|
pub(crate) const SHIP_FIRE_RATE: f32 = 3.0; // in bullets-per-second
|
||||||
pub(crate) const ASTEROID_SMALL_COLOR: Color = Color::srgb(1.0, 0., 0.);
|
pub(crate) const ASTEROID_SMALL_COLOR: Color = Color::srgb(0.9, 0.9, 0.9);
|
||||||
pub(crate) const BULLET_COLOR: Color = Color::srgb(0.0, 0.1, 0.9);
|
pub(crate) const ASTEROID_MEDIUM_COLOR: Color = Color::srgb(0.8, 0.8, 0.8);
|
||||||
|
pub(crate) const ASTEROID_LARGE_COLOR: Color = Color::srgb(0.6, 0.6, 0.6);
|
||||||
|
pub(crate) const BULLET_COLOR: Color = Color::srgb(0.9, 0.9, 0.9);
|
||||||
// TODO: asteroid medium & large
|
// TODO: asteroid medium & large
|
||||||
|
|
||||||
pub(crate) const SHIP_THRUST: f32 = 1.0;
|
pub(crate) const SHIP_THRUST: f32 = 4.0;
|
||||||
pub(crate) const SHIP_ROTATION: f32 = 4.0; // +/- rotation speed in... radians per frame
|
pub(crate) const SHIP_ROTATION: f32 = 4.0; // +/- rotation speed in... radians per frame
|
||||||
|
|
||||||
pub(crate) const BULLET_SPEED: f32 = 150.0;
|
pub(crate) const BULLET_SPEED: f32 = 500.0;
|
||||||
pub(crate) const BULLET_LIFETIME: f32 = 2.0;
|
pub(crate) const BULLET_LIFETIME: f32 = 2.0;
|
||||||
|
|
||||||
pub(crate) const ASTEROID_LIFETIME: f32 = 40.0;
|
pub(crate) const ASTEROID_LIFETIME: f32 = 40.0;
|
||||||
|
|||||||
32
src/lib.rs
32
src/lib.rs
@@ -11,9 +11,9 @@ mod resources;
|
|||||||
mod widgets;
|
mod widgets;
|
||||||
|
|
||||||
use crate::config::{
|
use crate::config::{
|
||||||
ASTEROID_SMALL_COLOR, BACKGROUND_COLOR, BULLET_COLOR, BULLET_LIFETIME, BULLET_SPEED,
|
ASTEROID_LARGE_COLOR, ASTEROID_MEDIUM_COLOR, ASTEROID_SMALL_COLOR, BACKGROUND_COLOR,
|
||||||
PLAYER_SHIP_COLOR, SHIP_ROTATION, SHIP_THRUST, SHIP_THRUSTER_COLOR_ACTIVE,
|
BULLET_COLOR, BULLET_LIFETIME, BULLET_SPEED, PLAYER_SHIP_COLOR, SHIP_ROTATION, SHIP_THRUST,
|
||||||
SHIP_THRUSTER_COLOR_INACTIVE,
|
SHIP_THRUSTER_COLOR_ACTIVE, SHIP_THRUSTER_COLOR_INACTIVE,
|
||||||
};
|
};
|
||||||
use crate::machinery::AsteroidSpawner;
|
use crate::machinery::AsteroidSpawner;
|
||||||
use crate::objects::{Bullet, Ship, Weapon};
|
use crate::objects::{Bullet, Ship, Weapon};
|
||||||
@@ -111,14 +111,28 @@ fn spawn_camera(mut commands: Commands) {
|
|||||||
/// Checks if "W" is pressed and increases velocity accordingly.
|
/// Checks if "W" is pressed and increases velocity accordingly.
|
||||||
fn input_ship_thruster(
|
fn input_ship_thruster(
|
||||||
keyboard_input: Res<ButtonInput<KeyCode>>,
|
keyboard_input: Res<ButtonInput<KeyCode>>,
|
||||||
mut query: Query<(&mut physics::Velocity, &Transform, &mut Children), With<Ship>>,
|
mut query: Query<
|
||||||
|
(
|
||||||
|
&mut physics::Velocity,
|
||||||
|
&Transform,
|
||||||
|
Option<&mut AudioSink>,
|
||||||
|
&mut Children,
|
||||||
|
),
|
||||||
|
With<Ship>,
|
||||||
|
>,
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
game_assets: Res<GameAssets>,
|
game_assets: Res<GameAssets>,
|
||||||
) {
|
) {
|
||||||
// TODO: Maybe change for a Single<Ship>> so this only runs for the one ship
|
// TODO: Maybe change for a Single<Ship>> so this only runs for the one ship
|
||||||
// buuut... that would silently do nothing if there are 0 or >1 ships, and
|
// buuut... that would silently do nothing if there are 0 or >1 ships, and
|
||||||
// I might want to crash on purpose in that case.
|
// I might want to crash on purpose in that case.
|
||||||
let Ok((mut velocity, transform, children)) = query.single_mut() else {
|
//
|
||||||
|
// The AudioSink component doesn't exist for just one frame, forcing it to
|
||||||
|
// be an optional system parameter. I'm not sure if I want to guard it with
|
||||||
|
// a check like it does now, or finally switch to using a Single<...> query
|
||||||
|
// parameter. I would lose ship control if the sound sink didn't spawn, but
|
||||||
|
// that should be fine -- any time that fails, more has likely also failed.
|
||||||
|
let Ok((mut velocity, transform, audio, children)) = query.single_mut() else {
|
||||||
let count = query.iter().count();
|
let count = query.iter().count();
|
||||||
panic!("There should be exactly one player ship! Instead, there seems to be {count}.");
|
panic!("There should be exactly one player ship! Instead, there seems to be {count}.");
|
||||||
};
|
};
|
||||||
@@ -132,10 +146,16 @@ fn input_ship_thruster(
|
|||||||
commands
|
commands
|
||||||
.entity(*thrusters)
|
.entity(*thrusters)
|
||||||
.insert(MeshMaterial2d(game_assets.thruster_mat_active()));
|
.insert(MeshMaterial2d(game_assets.thruster_mat_active()));
|
||||||
|
if let Some(audio) = audio {
|
||||||
|
audio.play();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
commands
|
commands
|
||||||
.entity(*thrusters)
|
.entity(*thrusters)
|
||||||
.insert(MeshMaterial2d(game_assets.thruster_mat_inactive()));
|
.insert(MeshMaterial2d(game_assets.thruster_mat_inactive()));
|
||||||
|
if let Some(audio) = audio {
|
||||||
|
audio.pause();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,6 +219,8 @@ fn input_ship_shoot(
|
|||||||
MeshMaterial2d(game_assets.bullet().1),
|
MeshMaterial2d(game_assets.bullet().1),
|
||||||
ship_pos.clone(), // clone ship transform
|
ship_pos.clone(), // clone ship transform
|
||||||
Lifetime(Timer::from_seconds(BULLET_LIFETIME, TimerMode::Once)),
|
Lifetime(Timer::from_seconds(BULLET_LIFETIME, TimerMode::Once)),
|
||||||
|
AudioPlayer::new(game_assets.laser_sound()),
|
||||||
|
PlaybackSettings::ONCE, // `Lifetime` already despawns the entity, so this doesn't need to
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,9 +83,9 @@ pub fn spawn_asteroid(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let collider_radius = match spawn.size {
|
let collider_radius = match spawn.size {
|
||||||
AsteroidSize::Small => 10.0,
|
AsteroidSize::Small => 5.0,
|
||||||
AsteroidSize::Medium => 20.0,
|
AsteroidSize::Medium => 10.0,
|
||||||
AsteroidSize::Large => 40.0,
|
AsteroidSize::Large => 20.0,
|
||||||
};
|
};
|
||||||
|
|
||||||
commands.spawn((
|
commands.spawn((
|
||||||
@@ -115,6 +115,7 @@ pub fn split_asteroids(
|
|||||||
mut respawn_events: MessageWriter<SpawnAsteroid>,
|
mut respawn_events: MessageWriter<SpawnAsteroid>,
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
query: Query<(&Transform, &Asteroid, &Velocity)>,
|
query: Query<(&Transform, &Asteroid, &Velocity)>,
|
||||||
|
game_assets: Res<GameAssets>,
|
||||||
) {
|
) {
|
||||||
for event in destroy_events.read() {
|
for event in destroy_events.read() {
|
||||||
if let Ok((transform, rock, velocity)) = query.get(event.0) {
|
if let Ok((transform, rock, velocity)) = query.get(event.0) {
|
||||||
@@ -137,6 +138,12 @@ pub fn split_asteroids(
|
|||||||
// Always despawn the asteroid. New ones (may) be spawned in it's
|
// Always despawn the asteroid. New ones (may) be spawned in it's
|
||||||
// place, but this one is gone.
|
// place, but this one is gone.
|
||||||
commands.entity(event.0).despawn();
|
commands.entity(event.0).despawn();
|
||||||
|
|
||||||
|
// Play a sound for the asteroid exploding
|
||||||
|
commands.spawn((
|
||||||
|
AudioPlayer::new(game_assets.asteroid_crack_sound()),
|
||||||
|
PlaybackSettings::DESPAWN,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -161,6 +168,12 @@ pub fn spawn_player(mut commands: Commands, game_assets: Res<GameAssets>) {
|
|||||||
Mesh2d(game_assets.ship().0),
|
Mesh2d(game_assets.ship().0),
|
||||||
MeshMaterial2d(game_assets.ship().1),
|
MeshMaterial2d(game_assets.ship().1),
|
||||||
Transform::default().with_scale(Vec3::new(20.0, 20.0, 20.0)),
|
Transform::default().with_scale(Vec3::new(20.0, 20.0, 20.0)),
|
||||||
|
AudioPlayer::new(game_assets.ship_thruster_sound()),
|
||||||
|
PlaybackSettings {
|
||||||
|
mode: bevy::audio::PlaybackMode::Loop,
|
||||||
|
paused: true,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
))
|
))
|
||||||
.with_child((
|
.with_child((
|
||||||
Mesh2d(game_assets.thruster_mesh()),
|
Mesh2d(game_assets.thruster_mesh()),
|
||||||
@@ -237,7 +250,7 @@ pub fn ship_impact_listener(
|
|||||||
// STEP 5: Play crash sound
|
// STEP 5: Play crash sound
|
||||||
commands.spawn((
|
commands.spawn((
|
||||||
AudioPlayer::new(game_assets.wreck_sound()),
|
AudioPlayer::new(game_assets.wreck_sound()),
|
||||||
PlaybackSettings::ONCE,
|
PlaybackSettings::DESPAWN, // despawn this entity when playback ends.
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use bevy::{
|
|||||||
},
|
},
|
||||||
math::{
|
math::{
|
||||||
Vec2,
|
Vec2,
|
||||||
primitives::{Circle, Triangle2d},
|
primitives::{Polyline2d, Segment2d, Triangle2d},
|
||||||
},
|
},
|
||||||
mesh::Mesh,
|
mesh::Mesh,
|
||||||
prelude::{Deref, DerefMut, Reflect, ReflectResource},
|
prelude::{Deref, DerefMut, Reflect, ReflectResource},
|
||||||
@@ -19,8 +19,9 @@ use bevy_inspector_egui::InspectorOptions;
|
|||||||
use bevy_inspector_egui::inspector_options::ReflectInspectorOptions;
|
use bevy_inspector_egui::inspector_options::ReflectInspectorOptions;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ASTEROID_SMALL_COLOR, BULLET_COLOR, PLAYER_SHIP_COLOR, SHIP_THRUSTER_COLOR_ACTIVE,
|
ASTEROID_LARGE_COLOR, ASTEROID_MEDIUM_COLOR, ASTEROID_SMALL_COLOR, BULLET_COLOR,
|
||||||
SHIP_THRUSTER_COLOR_INACTIVE, config::WINDOW_SIZE,
|
PLAYER_SHIP_COLOR, SHIP_THRUSTER_COLOR_ACTIVE, SHIP_THRUSTER_COLOR_INACTIVE,
|
||||||
|
config::WINDOW_SIZE,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(InspectorOptions, Reflect, Resource, Debug, Deref, Clone, Copy)]
|
#[derive(InspectorOptions, Reflect, Resource, Debug, Deref, Clone, Copy)]
|
||||||
@@ -58,7 +59,7 @@ impl Default for WorldSize {
|
|||||||
pub struct GameAssets {
|
pub struct GameAssets {
|
||||||
meshes: [Handle<Mesh>; 5],
|
meshes: [Handle<Mesh>; 5],
|
||||||
materials: [Handle<ColorMaterial>; 7],
|
materials: [Handle<ColorMaterial>; 7],
|
||||||
sounds: [Handle<AudioSource>; 1],
|
sounds: [Handle<AudioSource>; 4],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GameAssets {
|
impl GameAssets {
|
||||||
@@ -83,15 +84,15 @@ impl GameAssets {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn asteroid_small(&self) -> (Handle<Mesh>, Handle<ColorMaterial>) {
|
pub fn asteroid_small(&self) -> (Handle<Mesh>, Handle<ColorMaterial>) {
|
||||||
(self.meshes[1].clone(), self.materials[1].clone())
|
(self.meshes[1].clone(), self.materials[3].clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn asteroid_medium(&self) -> (Handle<Mesh>, Handle<ColorMaterial>) {
|
pub fn asteroid_medium(&self) -> (Handle<Mesh>, Handle<ColorMaterial>) {
|
||||||
(self.meshes[2].clone(), self.materials[2].clone())
|
(self.meshes[2].clone(), self.materials[4].clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn asteroid_large(&self) -> (Handle<Mesh>, Handle<ColorMaterial>) {
|
pub fn asteroid_large(&self) -> (Handle<Mesh>, Handle<ColorMaterial>) {
|
||||||
(self.meshes[3].clone(), self.materials[3].clone())
|
(self.meshes[3].clone(), self.materials[5].clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bullet(&self) -> (Handle<Mesh>, Handle<ColorMaterial>) {
|
pub fn bullet(&self) -> (Handle<Mesh>, Handle<ColorMaterial>) {
|
||||||
@@ -101,6 +102,18 @@ impl GameAssets {
|
|||||||
pub fn wreck_sound(&self) -> Handle<AudioSource> {
|
pub fn wreck_sound(&self) -> Handle<AudioSource> {
|
||||||
self.sounds[0].clone()
|
self.sounds[0].clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn laser_sound(&self) -> Handle<AudioSource> {
|
||||||
|
self.sounds[1].clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn asteroid_crack_sound(&self) -> Handle<AudioSource> {
|
||||||
|
self.sounds[2].clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ship_thruster_sound(&self) -> Handle<AudioSource> {
|
||||||
|
self.sounds[3].clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromWorld for GameAssets {
|
impl FromWorld for GameAssets {
|
||||||
@@ -112,10 +125,63 @@ impl FromWorld for GameAssets {
|
|||||||
Vec2::new(-0.5, 0.45),
|
Vec2::new(-0.5, 0.45),
|
||||||
Vec2::new(-0.5, -0.45),
|
Vec2::new(-0.5, -0.45),
|
||||||
)),
|
)),
|
||||||
world_meshes.add(Circle::new(10.0)),
|
world_meshes.add(Polyline2d::new(
|
||||||
world_meshes.add(Circle::new(20.0)),
|
[
|
||||||
world_meshes.add(Circle::new(40.0)),
|
Vec2::new(0.1, 0.0),
|
||||||
world_meshes.add(Circle::new(0.2)),
|
Vec2::new(0.8, 0.2),
|
||||||
|
Vec2::new(0.8, 0.3),
|
||||||
|
Vec2::new(0.1, 1.0),
|
||||||
|
Vec2::new(-0.5, 1.0),
|
||||||
|
Vec2::new(-0.3, 0.3),
|
||||||
|
Vec2::new(-1.0, 0.3),
|
||||||
|
Vec2::new(-1.0, -0.2),
|
||||||
|
Vec2::new(-0.5, -1.0),
|
||||||
|
Vec2::new(0.1, -0.8),
|
||||||
|
Vec2::new(0.5, -0.9),
|
||||||
|
Vec2::new(1.0, -0.4),
|
||||||
|
Vec2::new(0.1, 0.0),
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.map(|vert| vert * 5.0),
|
||||||
|
)),
|
||||||
|
world_meshes.add(Polyline2d::new(
|
||||||
|
[
|
||||||
|
Vec2::new(0.6, 0.3),
|
||||||
|
Vec2::new(1.0, 0.6),
|
||||||
|
Vec2::new(0.6, 1.0),
|
||||||
|
Vec2::new(0.1, 0.8),
|
||||||
|
Vec2::new(-0.4, 1.0),
|
||||||
|
Vec2::new(-1.0, 0.6),
|
||||||
|
Vec2::new(-0.8, -0.1),
|
||||||
|
Vec2::new(-1.0, -0.5),
|
||||||
|
Vec2::new(-0.4, -1.0),
|
||||||
|
Vec2::new(-0.3, -0.7),
|
||||||
|
Vec2::new(0.6, -1.0),
|
||||||
|
Vec2::new(1.0, -0.3),
|
||||||
|
Vec2::new(0.6, 0.3),
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.map(|vert| vert * 10.0),
|
||||||
|
)),
|
||||||
|
world_meshes.add(Polyline2d::new(
|
||||||
|
[
|
||||||
|
Vec2::new(1.0, -0.1),
|
||||||
|
Vec2::new(1.0, 0.3),
|
||||||
|
Vec2::new(0.4, 1.0),
|
||||||
|
Vec2::new(-0.2, 1.0),
|
||||||
|
Vec2::new(-0.9, 0.3),
|
||||||
|
Vec2::new(-0.5, 0.1),
|
||||||
|
Vec2::new(-0.9, -0.1),
|
||||||
|
Vec2::new(-0.5, -1.0),
|
||||||
|
Vec2::new(0.0, 0.0),
|
||||||
|
Vec2::new(0.0, -1.0),
|
||||||
|
Vec2::new(0.5, -1.0),
|
||||||
|
Vec2::new(1.0, -0.1),
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.map(|vert| vert * 20.0),
|
||||||
|
)),
|
||||||
|
world_meshes.add(Segment2d::new(Vec2::new(-0.1, 0.0), Vec2::new(0.1, 0.0))),
|
||||||
];
|
];
|
||||||
let mut world_materials = world.resource_mut::<Assets<ColorMaterial>>();
|
let mut world_materials = world.resource_mut::<Assets<ColorMaterial>>();
|
||||||
let materials = [
|
let materials = [
|
||||||
@@ -124,12 +190,17 @@ impl FromWorld for GameAssets {
|
|||||||
world_materials.add(SHIP_THRUSTER_COLOR_ACTIVE),
|
world_materials.add(SHIP_THRUSTER_COLOR_ACTIVE),
|
||||||
world_materials.add(ASTEROID_SMALL_COLOR),
|
world_materials.add(ASTEROID_SMALL_COLOR),
|
||||||
// TODO: asteroid medium and large colors
|
// TODO: asteroid medium and large colors
|
||||||
world_materials.add(ASTEROID_SMALL_COLOR),
|
world_materials.add(ASTEROID_MEDIUM_COLOR),
|
||||||
world_materials.add(ASTEROID_SMALL_COLOR),
|
world_materials.add(ASTEROID_LARGE_COLOR),
|
||||||
world_materials.add(BULLET_COLOR),
|
world_materials.add(BULLET_COLOR),
|
||||||
];
|
];
|
||||||
let loader = world.resource_mut::<AssetServer>();
|
let loader = world.resource_mut::<AssetServer>();
|
||||||
let sounds = [loader.load("explosionCrunch_004.ogg")];
|
let sounds = [
|
||||||
|
loader.load("explosionCrunch_004.ogg"),
|
||||||
|
loader.load("laserSmall_001.ogg"),
|
||||||
|
loader.load("explosionCrunch_000.ogg"),
|
||||||
|
loader.load("thrusterFire_004.ogg"),
|
||||||
|
];
|
||||||
GameAssets {
|
GameAssets {
|
||||||
meshes,
|
meshes,
|
||||||
materials,
|
materials,
|
||||||
|
|||||||
@@ -180,9 +180,9 @@ fn spawn_get_ready(mut commands: Commands, mut timer: ResMut<ReadySetGoTimer>) {
|
|||||||
height: Val::Percent(30.),
|
height: Val::Percent(30.),
|
||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
BackgroundColor(LIGHT_BLUE.into()),
|
BackgroundColor(Color::NONE),
|
||||||
children![
|
children![
|
||||||
(Text::new("Get Ready!"), TextColor(BLACK.into())),
|
(Text::new("Get Ready!"), TextColor(WHITE.into())),
|
||||||
(
|
(
|
||||||
CountdownBar,
|
CountdownBar,
|
||||||
Node {
|
Node {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
margin: auto;
|
margin: auto;
|
||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
}
|
}
|
||||||
|
#prestart-controls,
|
||||||
canvas {
|
canvas {
|
||||||
margin-top: 1em;
|
margin-top: 1em;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
@@ -22,6 +23,26 @@
|
|||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
background-color: rgb(40%, 40%, 40%);
|
background-color: rgb(40%, 40%, 40%);
|
||||||
}
|
}
|
||||||
|
#prestart-controls {
|
||||||
|
width: 800px;
|
||||||
|
height: 600px;
|
||||||
|
text-align: center;
|
||||||
|
align-content: center;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
font-size: 20px;
|
||||||
|
text-shadow: 0.2em 0.2em 0px rgba(0, 0, 0, 75%);
|
||||||
|
padding: 1em;
|
||||||
|
border-radius: 2em;
|
||||||
|
border-style: solid;
|
||||||
|
border-color: black;
|
||||||
|
color: rgb(90%, 90%, 90%);
|
||||||
|
background-color: rgb(15%, 15%, 15%);
|
||||||
|
}
|
||||||
|
button:hover {
|
||||||
|
background-color: rgb(25%, 25%, 25%);
|
||||||
|
border-color: rgb(90%, 90%, 90%);
|
||||||
|
}
|
||||||
main {
|
main {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
@@ -41,13 +62,21 @@
|
|||||||
<h1>
|
<h1>
|
||||||
Robert's Bad Asteroids Game
|
Robert's Bad Asteroids Game
|
||||||
</h1>
|
</h1>
|
||||||
<canvas id="game-canvas" width="1280" height="720"></canvas>
|
<!-- <canvas id="game-canvas" width="800" height="600"></canvas> -->
|
||||||
|
<div id="prestart-controls">
|
||||||
|
<button id="gameload-button">Load Game</button>
|
||||||
|
</div>
|
||||||
<main>
|
<main>
|
||||||
<article>
|
<article>
|
||||||
<h2>Description</h2>
|
<h2>Description</h2>
|
||||||
<p>
|
<p>
|
||||||
A (work in progress) version of the Asteroids arcade game.
|
A (work in progress) version of the Asteroids arcade game.
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
<em>Sound Warning!</em> The game now has sound effects, but there are no controls on the page for changing the
|
||||||
|
volume (including to mute them). You can mute the browser tab by pressing <code>ctrl</code> + <code>m</code>.
|
||||||
|
Proper volume controls are coming soon.
|
||||||
|
</p>
|
||||||
</article>
|
</article>
|
||||||
<article>
|
<article>
|
||||||
<h3>Controls</h3>
|
<h3>Controls</h3>
|
||||||
@@ -90,23 +119,34 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td>Program Version</td>
|
<td>Program Version</td>
|
||||||
<!-- This version text is completely unchecked. I'll need to do something about that. -->
|
<!-- This version text is completely unchecked. I'll need to do something about that. -->
|
||||||
<td><code>v0.5.0</code></td>
|
<td><code>v0.6.0</code></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</article>
|
</article>
|
||||||
</main>
|
</main>
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import init from './asteroids.js'
|
import init from './asteroids.js'
|
||||||
|
|
||||||
|
let button = document.getElementById("gameload-button");
|
||||||
|
button.onclick = async function loadGame() {
|
||||||
|
console.log("Game Load button was pressed!");
|
||||||
|
let canvas = document.createElement("canvas");
|
||||||
|
// <canvas id="game-canvas" width="800" height="600"></canvas>
|
||||||
|
canvas.setAttribute("id", "game-canvas");
|
||||||
|
canvas.setAttribute("width", "800");
|
||||||
|
canvas.setAttribute("height", "600");
|
||||||
|
button.parentElement.replaceWith(canvas);
|
||||||
|
|
||||||
let compressed = await fetch("./asteroids_bg.wasm.gz")
|
let compressed = await fetch("./asteroids_bg.wasm.gz")
|
||||||
let wasm_stream = compressed.body.pipeThrough(new DecompressionStream("gzip"))
|
let wasm_stream = compressed.body.pipeThrough(new DecompressionStream("gzip"))
|
||||||
let blob = await new Response(wasm_stream).blob();
|
let blob = await new Response(wasm_stream).blob();
|
||||||
|
|
||||||
init(await blob.arrayBuffer()).catch((error) => {
|
init(await blob.arrayBuffer()).catch((error) => {
|
||||||
if (!error.message.startsWith("Using exceptions for control flow, don't mind me. This isn't actually an error!")) {
|
if (!error.message.startsWith("Using exceptions for control flow, don't mind me. This isn't actually an error!")) {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user