sprite sheet

This commit is contained in:
Crizomb 2025-12-28 21:07:03 +01:00
parent ad6eaa7d79
commit b3e1359c63
10 changed files with 112 additions and 35 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
assets/sprites/bubble.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 B

BIN
assets/sprites/shield.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 B

BIN
assets/sprites/speed.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B

60
src/animation.rs Normal file
View file

@ -0,0 +1,60 @@
use bevy::prelude::*;
// Source : https://bevy.org/examples/2d-rendering/sprite-sheet/
fn main() {
App::new()
.add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest())) // prevents blurry sprites
.add_systems(Startup, setup)
.add_systems(Update, animate_sprite)
.run();
}
#[derive(Component)]
pub struct AnimationIndices {
pub first: usize,
pub last: usize,
}
#[derive(Component, Deref, DerefMut)]
pub struct AnimationTimer(pub Timer);
pub fn animate_sprite(time: Res<Time>, mut query: Query<(&AnimationIndices, &mut AnimationTimer, &mut Sprite)>) {
for (indices, mut timer, mut sprite) in &mut query {
timer.tick(time.delta());
if timer.just_finished()
&& let Some(atlas) = &mut sprite.texture_atlas
{
atlas.index = if atlas.index >= indices.last || atlas.index < indices.first {
indices.first
} else {
atlas.index + 1
};
}
}
}
#[allow(dead_code)]
fn setup(
mut commands: Commands,
asset_server: Res<AssetServer>,
mut texture_atlas_layouts: ResMut<Assets<TextureAtlasLayout>>,
) {
let texture = asset_server.load("textures/rpg/chars/gabe/gabe-idle-run.png");
let layout = TextureAtlasLayout::from_grid(UVec2::splat(24), 7, 1, None, None);
let texture_atlas_layout = texture_atlas_layouts.add(layout);
// Use only the subset of sprites in the sheet that make up the run animation
let animation_indices = AnimationIndices { first: 1, last: 6 };
commands.spawn(Camera2d);
commands.spawn((
Sprite::from_atlas_image(
texture,
TextureAtlas { layout: texture_atlas_layout, index: animation_indices.first },
),
Transform::from_scale(Vec3::splat(6.0)),
animation_indices,
AnimationTimer(Timer::from_seconds(0.1, TimerMode::Repeating)),
));
}

View file

@ -1,7 +0,0 @@
use bevy::{prelude::*, render::renderer};
#[derive(Component, Default)]
#[require(Transform)]
pub struct BoxCollider {
pub dimensions: Vec2,
}

View file

@ -1,20 +1,19 @@
use crate::density_grid::DensityObject; use crate::density_grid::DensityObject;
use crate::kirby::Kirby; use crate::kirby::Kirby;
use crate::physics_body::PhysicsBody; use crate::physics_body::PhysicsBody;
use crate::sphere_collider::SphereCollider;
use bevy::prelude::*; use bevy::prelude::*;
use rand::Rng; use rand::Rng;
use std::f32::consts::TAU; use std::f32::consts::TAU;
use std::fmt::Debug; use std::fmt::Debug;
#[derive(Component)] #[derive(Component)]
#[require(Sprite, PhysicsBody, SphereCollider, DensityObject)] #[require(Sprite, PhysicsBody, DensityObject)]
pub struct Lana { pub struct Bubble {
move_force: f32, move_force: f32,
} }
pub fn lana_spawn(mut commands: Commands, asset_server: Res<AssetServer>) { pub fn bubble_spawn(mut commands: Commands, asset_server: Res<AssetServer>) {
let texture: Handle<Image> = asset_server.load("sprites/lana.png"); let texture: Handle<Image> = asset_server.load("sprites/bubble.png");
let mut rng = rand::rng(); let mut rng = rand::rng();
for _ in 0..1000 { for _ in 0..1000 {
@ -22,16 +21,16 @@ pub fn lana_spawn(mut commands: Commands, asset_server: Res<AssetServer>) {
let pos = Vec2::from_angle(angle) * 500.0; let pos = Vec2::from_angle(angle) * 500.0;
commands.spawn(( commands.spawn((
Lana { move_force: 3000.0 }, Bubble { move_force: 3000.0 },
Sprite { image: texture.clone(), ..default() }, Sprite { image: texture.clone(), ..default() },
Transform::from_translation(pos.extend(0.0)).with_scale(Vec3::splat(0.01)), 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 }, PhysicsBody { mass: 10.0, force: Vec2::ZERO, velocity: Vec2::ZERO, drag: 0.05 },
)); ));
} }
} }
pub fn lana_move( pub fn bubble_move(
mut lana_query: Query<(&mut PhysicsBody, &Transform, &Lana), With<Lana>>, mut lana_query: Query<(&mut PhysicsBody, &Transform, &Bubble), With<Bubble>>,
kirby_query: Query<(&Transform, &Kirby), With<Kirby>>, kirby_query: Query<(&Transform, &Kirby), With<Kirby>>,
) { ) {
for (mut lana_body, lana_transform, lana) in &mut lana_query { for (mut lana_body, lana_transform, lana) in &mut lana_query {
@ -50,9 +49,3 @@ pub fn lana_move(
lana_body.force += dir * lana.move_force; lana_body.force += dir * lana.move_force;
} }
} }
#[derive(Component)]
#[require(Sprite, Transform)]
pub struct KirbySuction {
box_size: Vec2,
}

View file

@ -1,3 +1,4 @@
use crate::animation::{AnimationIndices, AnimationTimer};
use crate::physics_body::PhysicsBody; use crate::physics_body::PhysicsBody;
use crate::sphere_collider::SphereCollider; use crate::sphere_collider::SphereCollider;
use bevy::prelude::*; use bevy::prelude::*;
@ -8,15 +9,32 @@ pub struct Kirby {
speed_force: f32, speed_force: f32,
} }
pub fn kirby_spawn(mut commands: Commands, asset_server: Res<AssetServer>) { pub fn kirby_spawn(
let sprite = Sprite::from_image(asset_server.load("sprites/kirby.png")); mut commands: Commands,
asset_server: Res<AssetServer>,
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 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); let layout = TextureAtlasLayout::from_grid(UVec2::splat(32), 3, 3, None, None);
commands.spawn((Kirby { speed_force: 10000.0 }, transform, sprite, body)); let texture_atlas_layout = texture_atlas_layouts.add(layout);
let animation_indices = AnimationIndices { first: 3, last: 5 }; // idle
commands.spawn((
Kirby { speed_force: 10000.0 },
Sprite::from_atlas_image(
texture,
TextureAtlas { layout: texture_atlas_layout, index: animation_indices.first },
),
Transform::from_scale(Vec3::splat(3.0)),
animation_indices,
AnimationTimer(Timer::from_seconds(0.1, TimerMode::Repeating)),
body,
));
} }
pub fn get_dir(keys: Res<ButtonInput<KeyCode>>) -> Vec2 { pub fn get_dir(keys: Res<ButtonInput<KeyCode>>) -> Vec2 {
if keys.pressed(KeyCode::Space) { if keys.just_pressed(KeyCode::Space) {
println!("SUCKING"); println!("SUCKING");
} }
@ -38,13 +56,23 @@ pub fn get_dir(keys: Res<ButtonInput<KeyCode>>) -> Vec2 {
dir.normalize_or_zero() 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, &mut AnimationIndices), With<Kirby>>,
) {
if keys.pressed(KeyCode::Space) { if keys.pressed(KeyCode::Space) {
println!("SUCKING"); println!("SUCKING");
} }
let dir = get_dir(keys); let dir = get_dir(keys);
for (mut body, kirby) in &mut query { for (mut body, kirby, mut anim_indices) in &mut query {
body.force += dir * kirby.speed_force; body.force += dir * kirby.speed_force;
if (dir == Vec2::ZERO) {
anim_indices.first = 3;
anim_indices.last = 5;
} else {
anim_indices.first = 6;
anim_indices.last = 8;
}
} }
} }

View file

@ -1,4 +1,7 @@
use animation::animate_sprite;
use bevy::prelude::*; use bevy::prelude::*;
use bubble::bubble_move;
use bubble::bubble_spawn;
use camera::spawn_camera; use camera::spawn_camera;
use density_grid::DensityGrid; use density_grid::DensityGrid;
use density_grid::density_grid_force; use density_grid::density_grid_force;
@ -6,32 +9,32 @@ use density_grid::density_grid_update;
use density_grid::init_density_object; use density_grid::init_density_object;
use kirby::kirby_player_move; use kirby::kirby_player_move;
use kirby::kirby_spawn; use kirby::kirby_spawn;
use lana::lana_move;
use lana::lana_spawn;
use map::MapBounds; use map::MapBounds;
use physics_body::integrate; use physics_body::integrate;
mod animation;
mod bubble;
mod camera; mod camera;
mod density_grid; mod density_grid;
mod globals; mod globals;
mod kirby; mod kirby;
mod lana;
mod map; mod map;
mod physics_body; mod physics_body;
mod sphere_collider; mod sphere_collider;
fn main() { fn main() {
App::new() App::new()
.add_plugins(DefaultPlugins) .add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest()))
.insert_resource(MapBounds { min: Vec2::ONE * -600.0, max: Vec2::ONE * 600.0 }) .insert_resource(MapBounds { min: Vec2::ONE * -600.0, max: Vec2::ONE * 600.0 })
.insert_resource(DensityGrid::new()) .insert_resource(DensityGrid::new())
.add_systems(Startup, spawn_camera) .add_systems(Startup, spawn_camera)
.add_systems(Startup, kirby_spawn) .add_systems(Startup, kirby_spawn)
.add_systems(Startup, lana_spawn) .add_systems(Startup, bubble_spawn)
.add_systems(PostStartup, init_density_object) .add_systems(PostStartup, init_density_object)
.add_systems(Update, animate_sprite)
.add_systems(FixedUpdate, (density_grid_update, density_grid_force).chain()) .add_systems(FixedUpdate, (density_grid_update, density_grid_force).chain())
.add_systems(FixedUpdate, kirby_player_move) .add_systems(FixedUpdate, kirby_player_move)
.add_systems(FixedUpdate, lana_move) .add_systems(FixedUpdate, bubble_move)
.add_systems(FixedPostUpdate, integrate) .add_systems(FixedPostUpdate, integrate)
.run(); .run();
} }