Compare commits
2 commits
d5676ab610
...
f02158833c
| Author | SHA1 | Date | |
|---|---|---|---|
| f02158833c | |||
| fba4745162 |
10 changed files with 155 additions and 5 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -4092,6 +4092,7 @@ name = "spacorium"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy",
|
"bevy",
|
||||||
|
"rand",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
||||||
|
|
@ -5,3 +5,4 @@ edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bevy = "0.17.2"
|
bevy = "0.17.2"
|
||||||
|
rand = "0.9.2"
|
||||||
|
|
|
||||||
BIN
assets/asteroid2.png
Normal file
BIN
assets/asteroid2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 187 B |
BIN
assets/enemy_projectile.png
Normal file
BIN
assets/enemy_projectile.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 143 B |
Binary file not shown.
|
Before Width: | Height: | Size: 471 B After Width: | Height: | Size: 653 B |
96
src/asteroid.rs
Normal file
96
src/asteroid.rs
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use rand::{prelude::*, rng};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
FIRST_CORNER_X, FIRST_CORNER_Y, SECOND_CORNER_X, SECOND_CORNER_Y,
|
||||||
|
collision::{Collided, Collider},
|
||||||
|
damagable::Damagable,
|
||||||
|
projectile::Projectile,
|
||||||
|
velocity::Velocity,
|
||||||
|
};
|
||||||
|
|
||||||
|
const ASTEROID_BUMP_STRENGTH: f32 = 10.0;
|
||||||
|
|
||||||
|
pub struct AsteroidPlugin;
|
||||||
|
|
||||||
|
impl Plugin for AsteroidPlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.add_systems(Startup, setup_asteroids)
|
||||||
|
.add_systems(FixedUpdate, rotate_asteroid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct Asteroid(f32);
|
||||||
|
|
||||||
|
pub fn setup_asteroids(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||||
|
let sprite1: Handle<Image> = asset_server.load("asteroid.png");
|
||||||
|
let sprite2: Handle<Image> = asset_server.load("asteroid2.png");
|
||||||
|
let mut random = rng();
|
||||||
|
|
||||||
|
for _ in 0..50 {
|
||||||
|
let position = Vec3::new(
|
||||||
|
random.random_range(FIRST_CORNER_X..SECOND_CORNER_X),
|
||||||
|
random.random_range(FIRST_CORNER_Y..SECOND_CORNER_Y),
|
||||||
|
0.,
|
||||||
|
);
|
||||||
|
let sprite = if random.random_bool(0.5) {
|
||||||
|
sprite1.clone()
|
||||||
|
} else {
|
||||||
|
sprite2.clone()
|
||||||
|
};
|
||||||
|
let tau = f64::to_radians(360.);
|
||||||
|
let rotation = random.random_range((-tau)..tau) as f32;
|
||||||
|
|
||||||
|
commands
|
||||||
|
.spawn((
|
||||||
|
Asteroid(rotation),
|
||||||
|
Sprite::from(sprite),
|
||||||
|
Transform::from_translation(position),
|
||||||
|
Collider::new(8.),
|
||||||
|
Damagable::new(20),
|
||||||
|
))
|
||||||
|
.observe(bump);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rotate_asteroid(time: Res<Time>, query: Query<(&mut Transform, &Asteroid)>) {
|
||||||
|
for (mut transform, asteroid) in query {
|
||||||
|
transform.rotate_z(asteroid.0 * time.delta_secs());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bump(
|
||||||
|
collision: On<Collided>,
|
||||||
|
asteroid_query: Query<&Transform, (With<Asteroid>, Without<Projectile>)>,
|
||||||
|
mut collision_query: Query<
|
||||||
|
(&mut Transform, Option<&Velocity>),
|
||||||
|
(Without<Asteroid>, Without<Projectile>),
|
||||||
|
>,
|
||||||
|
time: Res<Time>,
|
||||||
|
) {
|
||||||
|
let Ok(asteroid_transform) = asteroid_query.get(collision.entity) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Ok((mut collided_transform, velocity_option)) = collision_query.get_mut(collision.with)
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let identity = Velocity::identity();
|
||||||
|
let velocity = velocity_option.unwrap_or(&identity);
|
||||||
|
|
||||||
|
let dir_to_asteroid = asteroid_transform.translation - collided_transform.translation;
|
||||||
|
let collided_direction = collided_transform.rotation * Vec3::X;
|
||||||
|
let collided_side = collided_transform.rotation * Vec3::Y;
|
||||||
|
|
||||||
|
let angle_to_direction = collided_direction.angle_between(-dir_to_asteroid);
|
||||||
|
let proporiton = velocity.linear_speed / velocity.max_linear_speed;
|
||||||
|
|
||||||
|
collided_transform.rotate_z(
|
||||||
|
angle_to_direction
|
||||||
|
* time.delta_secs()
|
||||||
|
* ASTEROID_BUMP_STRENGTH
|
||||||
|
* collided_side.dot(-dir_to_asteroid).signum()
|
||||||
|
* proporiton,
|
||||||
|
);
|
||||||
|
}
|
||||||
25
src/main.rs
25
src/main.rs
|
|
@ -1,24 +1,47 @@
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
use bevy::window::WindowResolution;
|
||||||
|
|
||||||
|
use crate::asteroid::AsteroidPlugin;
|
||||||
use crate::collision::CollisionPlugin;
|
use crate::collision::CollisionPlugin;
|
||||||
use crate::damagable::DamagablePlugin;
|
use crate::damagable::DamagablePlugin;
|
||||||
use crate::projectile::ProjectilePlugin;
|
use crate::projectile::ProjectilePlugin;
|
||||||
use crate::ships::ShipsPlugin;
|
use crate::ships::ShipsPlugin;
|
||||||
use crate::velocity::VelocityPlugin;
|
use crate::velocity::VelocityPlugin;
|
||||||
|
|
||||||
|
mod asteroid;
|
||||||
mod collision;
|
mod collision;
|
||||||
mod damagable;
|
mod damagable;
|
||||||
mod projectile;
|
mod projectile;
|
||||||
mod ships;
|
mod ships;
|
||||||
mod velocity;
|
mod velocity;
|
||||||
|
|
||||||
|
const FIRST_CORNER_X: f32 = -512.;
|
||||||
|
const FIRST_CORNER_Y: f32 = -512.;
|
||||||
|
const SECOND_CORNER_X: f32 = 512.;
|
||||||
|
const SECOND_CORNER_Y: f32 = 512.;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
.add_plugins(DefaultPlugins)
|
.add_plugins(
|
||||||
|
DefaultPlugins
|
||||||
|
.set(WindowPlugin {
|
||||||
|
primary_window: Some(Window {
|
||||||
|
resolution: WindowResolution::new(
|
||||||
|
(FIRST_CORNER_X.abs() + SECOND_CORNER_X.abs()) as u32,
|
||||||
|
(FIRST_CORNER_Y.abs() + SECOND_CORNER_Y.abs()) as u32,
|
||||||
|
)
|
||||||
|
.with_scale_factor_override(1.0),
|
||||||
|
..default()
|
||||||
|
}),
|
||||||
|
..default()
|
||||||
|
})
|
||||||
|
.set(ImagePlugin::default_nearest()),
|
||||||
|
)
|
||||||
.add_plugins(VelocityPlugin)
|
.add_plugins(VelocityPlugin)
|
||||||
.add_plugins(CollisionPlugin)
|
.add_plugins(CollisionPlugin)
|
||||||
.add_plugins(ShipsPlugin)
|
.add_plugins(ShipsPlugin)
|
||||||
.add_plugins(DamagablePlugin)
|
.add_plugins(DamagablePlugin)
|
||||||
.add_plugins(ProjectilePlugin)
|
.add_plugins(ProjectilePlugin)
|
||||||
|
.add_plugins(AsteroidPlugin)
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,15 +75,17 @@ pub fn observe_collision(
|
||||||
collision: On<Collided>,
|
collision: On<Collided>,
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
projectile_query: Query<&Projectile>,
|
projectile_query: Query<&Projectile>,
|
||||||
mut collision_query: Query<(&mut Damagable, &Factions)>,
|
mut damagable_query: Query<(&mut Damagable, Option<&Factions>)>,
|
||||||
) {
|
) {
|
||||||
let Ok(projectile) = projectile_query.get(collision.entity) else {
|
let Ok(projectile) = projectile_query.get(collision.entity) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let Ok((mut collided, faction)) = collision_query.get_mut(collision.with) else {
|
let Ok((mut collided, faction)) = damagable_query.get_mut(collision.with) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if projectile.faction.can_damage(faction) == false {
|
if let Some(f) = faction
|
||||||
|
&& projectile.faction.can_damage(f) == false
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ use crate::{
|
||||||
velocity::Velocity,
|
velocity::Velocity,
|
||||||
};
|
};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
use rand::random_range;
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
#[require(Velocity)]
|
#[require(Velocity)]
|
||||||
|
|
@ -112,10 +113,14 @@ pub fn player_shooting_system(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let five_degrees = f32::to_radians(5.);
|
||||||
|
let mut bullet_transform = transform.clone();
|
||||||
|
bullet_transform.rotate_z(random_range(-five_degrees..five_degrees));
|
||||||
|
|
||||||
spawn_projectile(
|
spawn_projectile(
|
||||||
&mut commands,
|
&mut commands,
|
||||||
projectile_sprite,
|
projectile_sprite,
|
||||||
transform.clone(),
|
bullet_transform,
|
||||||
gun.damage,
|
gun.damage,
|
||||||
Factions::PlayerFaction,
|
Factions::PlayerFaction,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
|
|
||||||
|
use crate::{FIRST_CORNER_X, FIRST_CORNER_Y, SECOND_CORNER_X, SECOND_CORNER_Y};
|
||||||
|
|
||||||
pub struct VelocityPlugin;
|
pub struct VelocityPlugin;
|
||||||
|
|
||||||
impl Plugin for VelocityPlugin {
|
impl Plugin for VelocityPlugin {
|
||||||
|
|
@ -48,6 +50,14 @@ impl Velocity {
|
||||||
max_rotation_speed: max_rotation_speed,
|
max_rotation_speed: max_rotation_speed,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn identity() -> Velocity {
|
||||||
|
Velocity {
|
||||||
|
linear_speed: 1.,
|
||||||
|
rotation_speed: 1.,
|
||||||
|
max_linear_speed: 1.0,
|
||||||
|
max_rotation_speed: 1.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Velocity {
|
impl Default for Velocity {
|
||||||
|
|
@ -71,5 +81,17 @@ fn movement_system(time: Res<Time>, query: Query<(&Velocity, &mut Transform)>) {
|
||||||
transform.translation += translation_delta;
|
transform.translation += translation_delta;
|
||||||
|
|
||||||
//TODO: Loop on bounds
|
//TODO: Loop on bounds
|
||||||
|
if transform.translation.x < FIRST_CORNER_X {
|
||||||
|
transform.translation.x += SECOND_CORNER_X * 2.;
|
||||||
|
}
|
||||||
|
if transform.translation.y < FIRST_CORNER_Y {
|
||||||
|
transform.translation.y += SECOND_CORNER_Y * 2.;
|
||||||
|
}
|
||||||
|
if transform.translation.x > SECOND_CORNER_X {
|
||||||
|
transform.translation.x += FIRST_CORNER_X * 2.;
|
||||||
|
}
|
||||||
|
if transform.translation.y > SECOND_CORNER_Y {
|
||||||
|
transform.translation.y += FIRST_CORNER_X * 2.;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue