Compare commits
2 commits
10a6bad336
...
0896ccf691
Author | SHA1 | Date | |
---|---|---|---|
0896ccf691 | |||
10b525e4c7 |
4 changed files with 48 additions and 28 deletions
|
@ -6,9 +6,13 @@ use bevy::prelude::*;
|
||||||
#[require(Collider, Mesh2d, MeshMaterial2d<ColorMaterial>, Restitution = Restitution::new(1.0), RigidBody, TransformInterpolation, Transform)]
|
#[require(Collider, Mesh2d, MeshMaterial2d<ColorMaterial>, Restitution = Restitution::new(1.0), RigidBody, TransformInterpolation, Transform)]
|
||||||
struct GameObject;
|
struct GameObject;
|
||||||
|
|
||||||
|
/// Radius of a ball
|
||||||
|
#[derive(Component, Default)]
|
||||||
|
pub struct Radius(pub f32);
|
||||||
|
|
||||||
/// A basic ball with which to interact
|
/// A basic ball with which to interact
|
||||||
#[derive(Component, Default)]
|
#[derive(Component, Default)]
|
||||||
#[require(GameObject, RigidBody = RigidBody::Dynamic)]
|
#[require(GameObject, RigidBody = RigidBody::Dynamic, Radius)]
|
||||||
pub struct Ball;
|
pub struct Ball;
|
||||||
|
|
||||||
/// The controllable ball
|
/// The controllable ball
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use core::f32;
|
||||||
|
|
||||||
use avian2d::prelude::*;
|
use avian2d::prelude::*;
|
||||||
use bevy::{
|
use bevy::{
|
||||||
input::mouse::{AccumulatedMouseScroll, MouseScrollUnit},
|
input::mouse::{AccumulatedMouseScroll, MouseScrollUnit},
|
||||||
|
@ -5,32 +7,46 @@ use bevy::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::objects::Player;
|
use super::objects::{Player, Radius};
|
||||||
|
|
||||||
/// Move the player character based on the keyboard input
|
/// Move the player character based on the keyboard input
|
||||||
pub fn move_player(
|
pub fn move_player(
|
||||||
time: Res<Time>,
|
time: Res<Time>,
|
||||||
keyboard_input: Res<ButtonInput<KeyCode>>,
|
keyboard_input: Res<ButtonInput<KeyCode>>,
|
||||||
mut velocity: Single<&mut LinearVelocity, With<Player>>,
|
mut query: Single<(&mut LinearVelocity, &Radius), With<Player>>,
|
||||||
) -> Result {
|
) {
|
||||||
let acceleration = 500.0;
|
let (ref mut velocity, radius) = *query;
|
||||||
|
|
||||||
let delta_v = acceleration * time.delta_secs();
|
let acceleration_energy = 150000.0;
|
||||||
|
// Although it would arguably be more accurate to divide by pi to get the actual mass (or include the density
|
||||||
|
// somehow), `acceleration_energy` is in arbitrary units so we can just pretend it's proper physics
|
||||||
|
let delta_v = acceleration_energy * time.delta_secs() / radius.0.powi(2);
|
||||||
|
|
||||||
|
let mut direction = Vec2::ZERO;
|
||||||
|
|
||||||
if keyboard_input.any_pressed([KeyCode::KeyW, KeyCode::ArrowUp]) {
|
if keyboard_input.any_pressed([KeyCode::KeyW, KeyCode::ArrowUp]) {
|
||||||
velocity.y += delta_v;
|
direction.y += 1.0;
|
||||||
}
|
}
|
||||||
if keyboard_input.any_pressed([KeyCode::KeyS, KeyCode::ArrowDown]) {
|
if keyboard_input.any_pressed([KeyCode::KeyS, KeyCode::ArrowDown]) {
|
||||||
velocity.y -= delta_v;
|
direction.y -= 1.0;
|
||||||
}
|
}
|
||||||
if keyboard_input.any_pressed([KeyCode::KeyA, KeyCode::ArrowLeft]) {
|
if keyboard_input.any_pressed([KeyCode::KeyA, KeyCode::ArrowLeft]) {
|
||||||
velocity.x -= delta_v;
|
direction.x -= 1.0;
|
||||||
}
|
}
|
||||||
if keyboard_input.any_pressed([KeyCode::KeyD, KeyCode::ArrowRight]) {
|
if keyboard_input.any_pressed([KeyCode::KeyD, KeyCode::ArrowRight]) {
|
||||||
velocity.x += delta_v;
|
direction.x += 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
// This would be easier if I could compare floats with 0 and still sleep at night
|
||||||
|
let circularize = if direction.x.abs() > 0.0 && direction.y.abs() > 0.0 {
|
||||||
|
f32::consts::FRAC_1_SQRT_2
|
||||||
|
} else {
|
||||||
|
1.0
|
||||||
|
};
|
||||||
|
|
||||||
|
// Kinda annoying I have to manually assign the fields here but I'll leave it in case I remember a better way later
|
||||||
|
velocity.x += direction.x * delta_v * circularize;
|
||||||
|
velocity.y += direction.y * delta_v * circularize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Neatly exit game
|
/// Neatly exit game
|
||||||
|
|
|
@ -12,7 +12,7 @@ use bevy_rand::prelude::{GlobalEntropy, WyRand};
|
||||||
use rand::Rng as _;
|
use rand::Rng as _;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
objects::{Ball, Player, Wall},
|
objects::{Ball, Player, Radius, Wall},
|
||||||
rng::thread_rng,
|
rng::thread_rng,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -24,19 +24,15 @@ const DIMENSION_SIZES: Range<f32> = 500.0..2000.0;
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
pub struct PlayableArea(f32, f32);
|
pub struct PlayableArea(f32, f32);
|
||||||
|
|
||||||
/// The size of the player character
|
|
||||||
#[derive(Resource)]
|
|
||||||
pub struct PlayerSize(f32);
|
|
||||||
|
|
||||||
/// Initialize deterministic values
|
/// Initialize deterministic values
|
||||||
pub fn setup_pseudo_random(mut commands: Commands, mut rng: GlobalEntropy<WyRand>) {
|
pub fn setup_from_seed(mut commands: Commands, mut rng: GlobalEntropy<WyRand>) {
|
||||||
commands.insert_resource(PlayerSize(rng.random_range(BALL_SIZES)));
|
|
||||||
commands.insert_resource(PlayableArea(
|
commands.insert_resource(PlayableArea(
|
||||||
rng.random_range(DIMENSION_SIZES),
|
rng.random_range(DIMENSION_SIZES),
|
||||||
rng.random_range(DIMENSION_SIZES),
|
rng.random_range(DIMENSION_SIZES),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// I mean, a camera is technically a user interface, I guess
|
||||||
pub fn setup_ui(mut commands: Commands) {
|
pub fn setup_ui(mut commands: Commands) {
|
||||||
commands.spawn((Name::new("Camera"), Camera2d, IsDefaultUiCamera));
|
commands.spawn((Name::new("Camera"), Camera2d, IsDefaultUiCamera));
|
||||||
}
|
}
|
||||||
|
@ -46,12 +42,15 @@ pub fn setup_player(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut materials: ResMut<Assets<ColorMaterial>>,
|
mut materials: ResMut<Assets<ColorMaterial>>,
|
||||||
mut meshes: ResMut<Assets<Mesh>>,
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
radius: Res<PlayerSize>,
|
|
||||||
) {
|
) {
|
||||||
let circle = Circle::new(radius.0);
|
let mut random = thread_rng();
|
||||||
|
|
||||||
|
let radius = random.random_range(BALL_SIZES);
|
||||||
|
let circle = Circle::new(radius);
|
||||||
commands.spawn((
|
commands.spawn((
|
||||||
Name::new("Player"),
|
Name::new("Player"),
|
||||||
Player,
|
Player,
|
||||||
|
Radius(radius),
|
||||||
Collider::from(circle),
|
Collider::from(circle),
|
||||||
Mesh2d(meshes.add(circle)),
|
Mesh2d(meshes.add(circle)),
|
||||||
MeshMaterial2d(materials.add(Color::from(LIME_400))),
|
MeshMaterial2d(materials.add(Color::from(LIME_400))),
|
||||||
|
@ -66,19 +65,20 @@ pub fn setup_balls(
|
||||||
region: Res<PlayableArea>,
|
region: Res<PlayableArea>,
|
||||||
) {
|
) {
|
||||||
let mut random = thread_rng();
|
let mut random = thread_rng();
|
||||||
|
|
||||||
for i in 0..BALL_COUNT {
|
for i in 0..BALL_COUNT {
|
||||||
let circle = Circle::new(random.random_range(BALL_SIZES));
|
let radius = random.random_range(BALL_SIZES);
|
||||||
|
let circle = Circle::new(radius);
|
||||||
commands.spawn((
|
commands.spawn((
|
||||||
Name::new(format!("Ball[{i}]")),
|
Name::new(format!("Ball[{i}]")),
|
||||||
Ball,
|
Ball,
|
||||||
|
Radius(radius),
|
||||||
Collider::from(circle),
|
Collider::from(circle),
|
||||||
Mesh2d(meshes.add(circle)),
|
Mesh2d(meshes.add(circle)),
|
||||||
MeshMaterial2d(materials.add(Color::from(RED_400))),
|
MeshMaterial2d(materials.add(Color::from(RED_400))),
|
||||||
Transform::from_xyz(
|
Transform::from_xyz(
|
||||||
random.random::<f32>() * (region.0 - 2.0 * circle.radius) + circle.radius
|
random.random::<f32>() * (region.0 - 2.0 * radius) + radius - region.0 / 2.0,
|
||||||
- region.0 / 2.0,
|
random.random::<f32>() * (region.1 - 2.0 * radius) + radius - region.1 / 2.0,
|
||||||
random.random::<f32>() * (region.1 - 2.0 * circle.radius) + circle.radius
|
|
||||||
- region.1 / 2.0,
|
|
||||||
0.0,
|
0.0,
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
|
|
|
@ -7,7 +7,7 @@ mod game;
|
||||||
use game::{
|
use game::{
|
||||||
runtime::{move_camera, move_player, quit, zoom_camera},
|
runtime::{move_camera, move_player, quit, zoom_camera},
|
||||||
seed::Seed,
|
seed::Seed,
|
||||||
setup::{setup_balls, setup_player, setup_pseudo_random, setup_ui, setup_walls},
|
setup::{setup_balls, setup_from_seed, setup_player, setup_ui, setup_walls},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The initial configuration passed to the game's setup functions.
|
/// The initial configuration passed to the game's setup functions.
|
||||||
|
@ -39,9 +39,9 @@ impl Plugin for AppSettings {
|
||||||
.add_systems(
|
.add_systems(
|
||||||
Startup,
|
Startup,
|
||||||
(
|
(
|
||||||
setup_pseudo_random,
|
setup_from_seed,
|
||||||
setup_ui,
|
setup_ui,
|
||||||
(setup_player, setup_balls, setup_walls).after(setup_pseudo_random),
|
(setup_player, setup_balls, setup_walls).after(setup_from_seed),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.add_systems(
|
.add_systems(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue