This commit is contained in:
Crizomb 2025-12-30 18:15:04 +01:00
parent 895b56c326
commit ee8799c324
8 changed files with 177 additions and 38 deletions

View file

@ -1,4 +1,4 @@
use std::{f32::consts::TAU, fmt::Debug};
use std::f32::consts::TAU;
use bevy::prelude::*;
use rand::Rng;
@ -8,10 +8,11 @@ use crate::{
kirby::Kirby,
life::{DamageDealer, Life},
physics_body::PhysicsBody,
sphere_collider::SphereCollider,
};
#[derive(Component)]
#[require(Sprite, PhysicsBody, DensityObject, Life, DamageDealer)]
#[require(Sprite, PhysicsBody, DensityObject, Life, DamageDealer, SphereCollider)]
pub struct Bubble {
move_force: f32,
}
@ -27,10 +28,11 @@ pub fn bubble_spawn(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn((
Bubble { move_force: 3000.0 },
Sprite { image: texture.clone(), ..default() },
Transform::from_translation(pos.extend(0.0)).with_scale(Vec3::splat(1.0)),
PhysicsBody { mass: 10.0, force: Vec2::ZERO, velocity: Vec2::ZERO, drag: 0.05 },
Transform::from_translation(pos.extend(0.0)).with_scale(Vec3::splat(1.0)),
Life::new(10.0),
DamageDealer::new(0.5),
SphereCollider::new(20.0),
));
}
}
@ -55,3 +57,11 @@ pub fn bubble_move(
bubble_body.force += dir * bubble.move_force;
}
}
pub struct BubblePlugin;
impl Plugin for BubblePlugin {
fn build(&self, app: &mut App) {
app.add_systems(Startup, bubble_spawn).add_systems(FixedUpdate, bubble_move);
}
}

View file

@ -1,5 +1,51 @@
use std::f32::consts::TAU;
use bevy::{prelude::*, render::renderer};
pub fn spawn_camera(mut commands: Commands) {
commands.spawn(Camera2d);
use crate::counter::KirbyHitCountThisFrame;
#[derive(Component)]
pub struct MyCamera {
shaking_intensity_factor: f32,
shaking_reset_speed: f32,
}
pub fn spawn_camera(mut commands: Commands) {
let mycam = commands
.spawn((
MyCamera { shaking_intensity_factor: 10.0, shaking_reset_speed: 0.1 },
Transform::from_translation(Vec3::ZERO),
))
.id();
commands.entity(mycam).with_child((Camera2d, Transform::from_xyz(0.0, 0.0, 0.0)));
}
pub fn camera_shake(
time: Res<Time<Fixed>>,
kirby_hit_count: Res<KirbyHitCountThisFrame>,
parent_query: Query<(&MyCamera, &Children)>,
mut children_query: Query<&mut Transform, With<Camera2d>>,
) {
let (parent, children) = parent_query.single().expect("Expect exactly one MyCamera entity");
let child = children.first().expect("MyCamera must have at least one child Camera2d");
let mut child_transform = children_query.get_mut(*child).expect("Camera child must have a Transform and Camera2d");
let rand_angle = rand::random_range(0.0..TAU);
let rand_vec = Vec2::from_angle(rand_angle);
let shaking_strength = kirby_hit_count.count as f32 * parent.shaking_intensity_factor;
let shaking_vec = rand_vec * shaking_strength;
let mut child_translation = child_transform.translation.clone();
child_translation += shaking_vec.extend(0.0);
child_translation -= child_translation * parent.shaking_reset_speed * time.delta_secs();
child_transform.translation.x = child_translation.x;
child_transform.translation.y = child_translation.y;
// println!("{:?}", child_transform.translation);
}
pub struct MyCameraPlugin;
impl Plugin for MyCameraPlugin {
fn build(&self, app: &mut App) {
app.add_systems(Startup, spawn_camera).add_systems(FixedPostUpdate, camera_shake);
}
}

51
src/counter.rs Normal file
View file

@ -0,0 +1,51 @@
use bevy::prelude::*;
use derive_more::{Deref, DerefMut};
#[derive(Resource, Default)]
pub struct Counter {
pub count: u32,
}
impl Counter {
pub fn new() -> Self {
Counter { count: 0 }
}
pub fn increase(&mut self, delta: u32) {
self.count += delta;
}
pub fn reset(&mut self) {
self.count = 0;
}
}
#[derive(Resource, Default, Deref, DerefMut)]
pub struct BubbleExplodedCountThisFrame(pub Counter);
#[derive(Resource, Default, Deref, DerefMut)]
pub struct BubbleSuckedCountThisFrame(pub Counter);
#[derive(Resource, Default, Deref, DerefMut)]
pub struct KirbyHitCountThisFrame(pub Counter);
fn reset_frame_counters(
mut bubble_sucked: ResMut<BubbleSuckedCountThisFrame>,
mut bubble_exploded: ResMut<BubbleExplodedCountThisFrame>,
mut kirby_hit: ResMut<KirbyHitCountThisFrame>,
) {
bubble_sucked.reset();
bubble_exploded.reset();
kirby_hit.reset();
}
pub struct CounterPlugin;
impl Plugin for CounterPlugin {
fn build(&self, app: &mut App) {
app.insert_resource(BubbleSuckedCountThisFrame::default())
.insert_resource(BubbleExplodedCountThisFrame::default())
.insert_resource(KirbyHitCountThisFrame::default())
.add_systems(FixedPostUpdate, reset_frame_counters);
}
}

View file

@ -52,7 +52,7 @@ pub fn init_density_object(mut density_grid: ResMut<DensityGrid>, mut query: Que
}
}
pub fn density_grid_update(mut density_grid: ResMut<DensityGrid>, query: Query<&Transform>) {
pub fn density_grid_update(mut density_grid: ResMut<DensityGrid>, query: Query<&Transform, With<DensityObject>>) {
density_grid.grid.fill(0);
for transform in &query {
@ -86,3 +86,13 @@ pub fn density_grid_force(
physics_body.force -= density_gradient * DENSITY_FORCE_SCALE;
}
}
pub struct DensityGridPlugin;
impl Plugin for DensityGridPlugin {
fn build(&self, app: &mut App) {
app.insert_resource(DensityGrid::new())
.add_systems(PostStartup, init_density_object)
.add_systems(FixedUpdate, (density_grid_update, density_grid_force).chain());
}
}

View file

@ -26,7 +26,6 @@ pub fn kirby_spawn(
mut texture_atlas_layouts: ResMut<Assets<TextureAtlasLayout>>,
) {
let texture: Handle<Image> = asset_server.load("sprites/Sprite_kirby-Sheet.png");
let body = PhysicsBody { mass: 10.0, force: Vec2::ZERO, velocity: Vec2::ZERO, drag: 0.05 };
let layout = TextureAtlasLayout::from_grid(UVec2::splat(32), 3, 3, None, None);
let texture_atlas_layout = texture_atlas_layouts.add(layout);
let animation_indices = AnimationIndices { first: 3, last: 5 }; // idle
@ -38,22 +37,21 @@ pub fn kirby_spawn(
texture,
TextureAtlas { layout: texture_atlas_layout, index: animation_indices.first },
),
Transform::from_scale(Vec3::splat(KIRBY_SCALE)),
PhysicsBody { mass: 10.0, force: Vec2::ZERO, velocity: Vec2::ZERO, drag: 0.05 },
SphereCollider::new(20.0),
animation_indices,
AnimationTimer(Timer::from_seconds(0.1, TimerMode::Repeating)),
body,
SphereCollider::new(50.0),
Life::new(1000.0),
Transform::from_scale(Vec3::splat(KIRBY_SCALE)),
))
.id();
commands.entity(kirby_entity).with_children(|parent| {
parent.spawn((
Transform::from_xyz(40.0, 0.0, 0.0),
SuckArea,
SphereCollider::new(80.0),
DamageDealer::new(10000.0),
));
});
commands.entity(kirby_entity).with_child((
Transform::from_xyz(40.0, 0.0, 0.0),
SuckArea,
SphereCollider::new(80.0),
DamageDealer::new(10000.0),
));
}
pub fn get_dir(keys: Res<ButtonInput<KeyCode>>) -> Vec2 {
@ -106,3 +104,10 @@ pub fn kirby_actions(
}
}
}
pub struct KirbyPlugin;
impl Plugin for KirbyPlugin {
fn build(&self, app: &mut App) {
app.add_systems(Startup, kirby_spawn).add_systems(FixedUpdate, kirby_actions);
}
}

View file

@ -2,6 +2,7 @@ use bevy::prelude::*;
use crate::{
bubble::Bubble,
counter::{BubbleExplodedCountThisFrame, BubbleSuckedCountThisFrame, KirbyHitCountThisFrame},
kirby::{Kirby, SuckArea},
sphere_collider::SphereCollider,
};
@ -55,7 +56,7 @@ impl DamageDealer {
// Considerating ennemies are ponctual
pub fn bubble_receive_damage(
time: Res<Time<Fixed>>,
mut bubble_sucked: ResMut<BubbleSuckedCountThisFrame>,
mut enemy_query: Query<(&GlobalTransform, &mut Life), With<Bubble>>,
kirby_query: Query<(&Kirby, &Children)>,
@ -74,6 +75,7 @@ pub fn bubble_receive_damage(
for (enemy_transform, mut enemy_life) in &mut enemy_query {
if suck_collider.point_inside(suck_transform.translation(), enemy_transform.translation()) {
enemy_life.damage(suck_damage.damage_strength * time.delta_secs());
bubble_sucked.increase(1);
}
}
}
@ -82,14 +84,22 @@ pub fn bubble_receive_damage(
// Considerating allies are ponctual
pub fn kirby_receive_damage(
mut ally_query: Query<(&GlobalTransform, &mut Life), With<Kirby>>,
mut enemy_query: Query<(&GlobalTransform, &SphereCollider, &DamageDealer, &mut Life), With<Bubble>>,
mut bubble_exploded: ResMut<BubbleExplodedCountThisFrame>,
mut kirby_hit: ResMut<KirbyHitCountThisFrame>,
mut kirby_query: Query<(&GlobalTransform, &mut Life), (With<Kirby>, Without<Bubble>)>,
mut bubble_query: Query<
(&GlobalTransform, &SphereCollider, &DamageDealer, &mut Life),
(With<Bubble>, Without<Kirby>),
>,
) {
for (ally_transform, mut ally_life) in &mut ally_query {
for (enemy_transform, enemy_sphere_collider, enemy_damage_dealer, mut bubble_life) in &mut enemy_query {
if enemy_sphere_collider.point_inside(ally_transform.translation(), enemy_transform.translation()) {
ally_life.damage(enemy_damage_dealer.damage_strength);
for (kirby_transform, mut kirby_life) in &mut kirby_query {
for (bubble_transform, bubble_sphere_collider, bubble_damage_dealer, mut bubble_life) in &mut bubble_query {
if bubble_sphere_collider.point_inside(kirby_transform.translation(), bubble_transform.translation()) {
kirby_life.damage(bubble_damage_dealer.damage_strength);
bubble_life.damage(1000000.0); // Bubble explode
// println!("{:?}", kirby_life.current_life)
bubble_exploded.increase(1);
kirby_hit.increase(1);
}
}
}

View file

@ -3,16 +3,21 @@ use bevy::prelude::*;
use bubble::{bubble_move, bubble_spawn};
use camera::spawn_camera;
use density_grid::{DensityGrid, density_grid_force, density_grid_update, init_density_object};
use kirby::{kirby_actions, kirby_spawn};
use life::despawn_if_dead;
use life::{bubble_receive_damage, kirby_receive_damage};
use map::MapBounds;
use physics_body::integrate;
use physics_body::physics_integrate;
use crate::life::bubble_receive_damage;
use crate::bubble::BubblePlugin;
use crate::camera::MyCameraPlugin;
use crate::counter::CounterPlugin;
use crate::density_grid::DensityGridPlugin;
use crate::kirby::KirbyPlugin;
mod animation;
mod bubble;
mod camera;
mod counter;
mod density_grid;
mod globals;
mod kirby;
@ -24,19 +29,17 @@ mod sphere_collider;
fn main() {
App::new()
.add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest()))
.add_plugins(CounterPlugin)
.add_plugins(KirbyPlugin)
.add_plugins(DensityGridPlugin)
.add_plugins(BubblePlugin)
.add_plugins(MyCameraPlugin)
.insert_resource(Time::<Fixed>::from_seconds(1.0 / 60.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(Startup, bubble_spawn)
.add_systems(PostStartup, init_density_object)
.add_systems(Update, animate_sprite)
.add_systems(FixedUpdate, (density_grid_update, density_grid_force).chain())
.add_systems(FixedUpdate, kirby_actions)
.add_systems(FixedUpdate, bubble_move)
.add_systems(FixedUpdate, bubble_receive_damage)
.add_systems(FixedUpdate, kirby_receive_damage)
.add_systems(FixedPostUpdate, despawn_if_dead)
.add_systems(FixedPostUpdate, integrate)
.add_systems(FixedPostUpdate, physics_integrate)
.run();
}

View file

@ -17,7 +17,11 @@ impl Default for PhysicsBody {
}
}
pub fn integrate(bounds: Res<MapBounds>, mut query: Query<(&mut Transform, &mut PhysicsBody)>, time: Res<Time<Fixed>>) {
pub fn physics_integrate(
bounds: Res<MapBounds>,
mut query: Query<(&mut Transform, &mut PhysicsBody)>,
time: Res<Time<Fixed>>,
) {
for (mut transform, mut physicsbody) in &mut query {
let force = physicsbody.force;
let mass = physicsbody.mass;