This commit is contained in:
parent
57db0aff22
commit
6aeda8be14
7 changed files with 171 additions and 19 deletions
80
src/density_grid.rs
Normal file
80
src/density_grid.rs
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
use crate::globals::MAX_MAP_WIDTH;
|
||||
use crate::physics_body::PhysicsBody;
|
||||
use bevy::prelude::*;
|
||||
|
||||
const CELL_SIZE: usize = 32;
|
||||
const MAX_MAP_SIZE: usize = MAX_MAP_WIDTH * 2;
|
||||
const ARRAY_WIDTH: usize = MAX_MAP_SIZE / CELL_SIZE;
|
||||
const GRID_ARRAY_SIZE: usize = ARRAY_WIDTH * ARRAY_WIDTH;
|
||||
|
||||
const DENSITY_FORCE_SCALE: f32 = 100.0;
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct DensityGrid {
|
||||
grid: Box<[i32; GRID_ARRAY_SIZE]>,
|
||||
}
|
||||
|
||||
impl DensityGrid {
|
||||
pub fn new() -> Self {
|
||||
DensityGrid { grid: Box::new([0; GRID_ARRAY_SIZE]) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pos_to_grid_cell(pos: Vec2) -> UVec2 {
|
||||
let ix = ((pos.x + MAX_MAP_WIDTH as f32) / CELL_SIZE as f32) as u32;
|
||||
let iy = ((pos.y + MAX_MAP_WIDTH as f32) / CELL_SIZE as f32) as u32;
|
||||
UVec2::new(ix, iy)
|
||||
}
|
||||
|
||||
fn get_index_from_uvec2(grid_cell: UVec2) -> usize {
|
||||
if grid_cell.x >= ARRAY_WIDTH as u32 || grid_cell.y >= ARRAY_WIDTH as u32 {
|
||||
panic!("Index out of bounds: {:?}", grid_cell);
|
||||
}
|
||||
(grid_cell.x + grid_cell.y * ARRAY_WIDTH as u32) as usize
|
||||
}
|
||||
|
||||
#[derive(Component, Default)]
|
||||
pub struct DensityObject {}
|
||||
|
||||
pub fn init_density_object(mut density_grid: ResMut<DensityGrid>, mut query: Query<&Transform>) {
|
||||
for transform in &mut query {
|
||||
let grid_cell = pos_to_grid_cell(transform.translation.xy());
|
||||
// println!("grid cell {:?}", grid_cell);
|
||||
let index = get_index_from_uvec2(grid_cell);
|
||||
density_grid.grid[index] += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn density_grid_update(mut density_grid: ResMut<DensityGrid>, query: Query<&Transform>) {
|
||||
density_grid.grid.fill(0);
|
||||
|
||||
for transform in &query {
|
||||
let cell = pos_to_grid_cell(transform.translation.xy());
|
||||
let idx = get_index_from_uvec2(cell);
|
||||
density_grid.grid[idx] += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn density_grid_force(
|
||||
density_grid: Res<DensityGrid>,
|
||||
mut query: Query<(&mut PhysicsBody, &Transform), With<DensityObject>>,
|
||||
) {
|
||||
for (mut physics_body, transform) in &mut query {
|
||||
let grid_cell = pos_to_grid_cell(transform.translation.xy());
|
||||
let mut density_gradient = Vec2::ZERO;
|
||||
|
||||
for dx in [-1, 0, 1] {
|
||||
for dy in [-1, 0, 1] {
|
||||
let offset = IVec2 { x: dx, y: dy };
|
||||
let neighbor_cell = (offset + grid_cell.as_ivec2()).as_uvec2();
|
||||
let index = get_index_from_uvec2(neighbor_cell);
|
||||
let density = density_grid.grid[index];
|
||||
|
||||
// println!("offset : {:?} density: {:?}", offset.as_vec2(), density);
|
||||
density_gradient += offset.as_vec2() * density as f32;
|
||||
}
|
||||
}
|
||||
// println!("density : {:?}", density_gradient);
|
||||
physics_body.force -= density_gradient * DENSITY_FORCE_SCALE;
|
||||
}
|
||||
}
|
||||
1
src/globals.rs
Normal file
1
src/globals.rs
Normal file
|
|
@ -0,0 +1 @@
|
|||
pub static MAX_MAP_WIDTH: usize = 1024;
|
||||
16
src/kirby.rs
16
src/kirby.rs
|
|
@ -10,14 +10,9 @@ pub struct Kirby {
|
|||
|
||||
pub fn kirby_spawn(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||
let sprite = Sprite::from_image(asset_server.load("sprites/kirby.png"));
|
||||
let body = PhysicsBody {
|
||||
mass: 10.0,
|
||||
force: Vec2::ZERO,
|
||||
velocity: Vec2::ZERO,
|
||||
drag: 0.05,
|
||||
};
|
||||
let body = PhysicsBody { mass: 10.0, force: Vec2::ZERO, velocity: Vec2::ZERO, drag: 0.05 };
|
||||
let transform = Transform::from_xyz(0.0, 0.0, 0.0).with_scale(Vec3::ONE * 0.25);
|
||||
commands.spawn((Kirby { speed_force: 50.0 }, transform, sprite, body));
|
||||
commands.spawn((Kirby { speed_force: 10000.0 }, transform, sprite, body));
|
||||
}
|
||||
|
||||
pub fn get_dir(keys: Res<ButtonInput<KeyCode>>) -> Vec2 {
|
||||
|
|
@ -43,16 +38,13 @@ pub fn get_dir(keys: Res<ButtonInput<KeyCode>>) -> Vec2 {
|
|||
dir.normalize_or_zero()
|
||||
}
|
||||
|
||||
pub fn kirby_player_move(
|
||||
keys: Res<ButtonInput<KeyCode>>,
|
||||
mut query: Query<(&mut PhysicsBody, &Kirby), With<Kirby>>,
|
||||
) {
|
||||
pub fn kirby_player_move(keys: Res<ButtonInput<KeyCode>>, mut query: Query<(&mut PhysicsBody, &Kirby), With<Kirby>>) {
|
||||
if keys.pressed(KeyCode::Space) {
|
||||
println!("SUCKING");
|
||||
}
|
||||
let dir = get_dir(keys);
|
||||
for (mut body, kirby) in &mut query {
|
||||
body.velocity += dir * kirby.speed_force;
|
||||
body.force += dir * kirby.speed_force;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
57
src/lana.rs
Normal file
57
src/lana.rs
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
use crate::density_grid::DensityObject;
|
||||
use crate::kirby::Kirby;
|
||||
use crate::physics_body::PhysicsBody;
|
||||
use crate::sphere_collider::SphereCollider;
|
||||
use bevy::prelude::*;
|
||||
use rand::Rng;
|
||||
use std::f32::consts::TAU;
|
||||
|
||||
#[derive(Component)]
|
||||
#[require(Sprite, PhysicsBody, SphereCollider, DensityObject)]
|
||||
pub struct Lana {
|
||||
move_force: f32,
|
||||
}
|
||||
|
||||
pub fn lana_spawn(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||
let texture: Handle<Image> = asset_server.load("sprites/lana.png");
|
||||
let mut rng = rand::rng();
|
||||
|
||||
for _ in 0..1_000 {
|
||||
let angle = rng.random_range(0.0..TAU);
|
||||
let pos = Vec2::from_angle(angle) * 500.0;
|
||||
|
||||
commands.spawn((
|
||||
Lana { move_force: 3000.0 },
|
||||
Sprite { image: texture.clone(), ..default() },
|
||||
Transform::from_translation(pos.extend(0.0)).with_scale(Vec3::splat(0.02)),
|
||||
PhysicsBody { mass: 10.0, force: Vec2::ZERO, velocity: Vec2::ZERO, drag: 0.05 },
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lana_move(
|
||||
mut lana_query: Query<(&mut PhysicsBody, &Transform, &Lana), With<Lana>>,
|
||||
kirby_query: Query<(&Transform, &Kirby), With<Kirby>>,
|
||||
) {
|
||||
for (mut lana_body, lana_transform, lana) in &mut lana_query {
|
||||
let mut nearest_kirby_pos = Vec3::ZERO;
|
||||
let mut nearest_squared = f32::MAX;
|
||||
|
||||
for (kirby_transform, _kirby) in kirby_query {
|
||||
let dist_squared = kirby_transform.translation.distance_squared(lana_transform.translation);
|
||||
if (dist_squared) < nearest_squared {
|
||||
nearest_squared = dist_squared;
|
||||
nearest_kirby_pos = kirby_transform.translation;
|
||||
}
|
||||
}
|
||||
|
||||
let dir = (nearest_kirby_pos - lana_transform.translation).normalize().xy();
|
||||
lana_body.force += dir * lana.move_force;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
#[require(Sprite, Transform)]
|
||||
pub struct KirbySuction {
|
||||
box_size: Vec2,
|
||||
}
|
||||
22
src/main.rs
22
src/main.rs
|
|
@ -1,12 +1,21 @@
|
|||
use bevy::prelude::*;
|
||||
use camera::spawn_camera;
|
||||
use density_grid::DensityGrid;
|
||||
use density_grid::density_grid_force;
|
||||
use density_grid::density_grid_update;
|
||||
use density_grid::init_density_object;
|
||||
use kirby::kirby_player_move;
|
||||
use kirby::kirby_spawn;
|
||||
use lana::lana_move;
|
||||
use lana::lana_spawn;
|
||||
use map::MapBounds;
|
||||
use physics_body::integrate;
|
||||
|
||||
mod camera;
|
||||
mod density_grid;
|
||||
mod globals;
|
||||
mod kirby;
|
||||
mod lana;
|
||||
mod map;
|
||||
mod physics_body;
|
||||
mod sphere_collider;
|
||||
|
|
@ -14,12 +23,15 @@ mod sphere_collider;
|
|||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.insert_resource(MapBounds {
|
||||
min: Vec2::ONE * -400.0,
|
||||
max: Vec2::ONE * 400.0,
|
||||
})
|
||||
.insert_resource(MapBounds { min: Vec2::ONE * -600.0, max: Vec2::ONE * 600.0 })
|
||||
.insert_resource(DensityGrid::new())
|
||||
.add_systems(Startup, spawn_camera)
|
||||
.add_systems(Startup, kirby_spawn)
|
||||
.add_systems(FixedUpdate, (kirby_player_move, integrate).chain())
|
||||
.add_systems(Startup, lana_spawn)
|
||||
.add_systems(PostStartup, init_density_object)
|
||||
.add_systems(FixedUpdate, (density_grid_update, density_grid_force).chain())
|
||||
.add_systems(FixedUpdate, kirby_player_move)
|
||||
.add_systems(FixedUpdate, lana_move)
|
||||
.add_systems(FixedPostUpdate, integrate)
|
||||
.run();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ pub fn integrate(
|
|||
physicsbody.velocity += force * delta_secs / mass;
|
||||
physicsbody.velocity *= 1.0 - drag;
|
||||
|
||||
bounce(&mut physicsbody.velocity, &transform, &bounds);
|
||||
map_bounce(&mut physicsbody.velocity, &transform, &bounds);
|
||||
|
||||
transform.translation.x += physicsbody.velocity.x * delta_secs;
|
||||
transform.translation.y += physicsbody.velocity.y * delta_secs;
|
||||
|
|
@ -44,7 +44,7 @@ pub fn integrate(
|
|||
}
|
||||
}
|
||||
|
||||
fn bounce(velocity: &mut Vec2, transform: &Transform, bounds: &MapBounds) {
|
||||
fn map_bounce(velocity: &mut Vec2, transform: &Transform, bounds: &MapBounds) {
|
||||
if (transform.translation.x < bounds.min.x && velocity.x < 0.0)
|
||||
|| (transform.translation.x > bounds.max.x && velocity.x > 0.0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,3 +5,13 @@ use bevy::{prelude::*, render::renderer};
|
|||
pub struct SphereCollider {
|
||||
pub radius: f32,
|
||||
}
|
||||
|
||||
impl SphereCollider {
|
||||
fn point_inside(&self, self_pos: Vec3, point: Vec3) -> bool {
|
||||
(self_pos - point).length_squared() < self.radius * self.radius
|
||||
}
|
||||
fn collides(&self, self_pos: Vec3, other: &SphereCollider, other_pos: Vec3) -> bool {
|
||||
let radius_sum = self.radius + other.radius;
|
||||
(self_pos - other_pos).length_squared() < radius_sum * radius_sum
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue