Make sprite texture atlas more generic

This commit is contained in:
SeanOMik 2024-11-24 21:52:48 -05:00 committed by SeanOMik
parent 7e9ece83a2
commit 3c3025668a
3 changed files with 63 additions and 78 deletions

View File

@ -43,7 +43,7 @@ impl SpriteAnimation {
let mut frames = vec![]; //Vec::with_capacity(sprites.len());
for i in sprites {
let r = atlas.index_rect(i);
let r = atlas.frames.get(i as usize).cloned().unwrap();
frames.push(r);
}

View File

@ -1,72 +1,43 @@
use glam::{UVec2, Vec3};
use glam::UVec2;
use lyra_ecs::Component;
use lyra_math::URect;
use lyra_reflect::Reflect;
use lyra_resource::ResHandle;
use super::Pivot;
/// A texture atlas of multiple sprites.
#[derive(Clone, Component, Reflect)]
pub struct TextureAtlas {
pub texture: ResHandle<lyra_resource::Image>,
/// The coordinates in the texture where the grid starts.
pub grid_offset: UVec2,
/// The size of the grid in cells.
pub grid_size: UVec2,
/// The size of each cell.
pub cell_size: UVec2,
pub sprite_color: Vec3,
pub pivot: Pivot,
pub frames: Vec<URect>,
}
impl TextureAtlas {
/// The cell x and y in the grid of a specific index.
pub fn index_cell(&self, i: u32) -> UVec2 {
let x = i % self.grid_size.x;
let y = i / self.grid_size.x;
UVec2 { x, y }
}
/// The coords of the cell at x and y in the grid.
/// Create a texture atlas with rectangles of a grid.
///
/// The indices are different then the image coords, this is the position in the grid.
/// So if you have a 9x7 grid, and wanted to get the 1nd cell on the 2nd row, you'd
/// use the values `x = 0, y = 1` (indices start at zero like arrays).
#[inline(always)]
pub fn cell_coords(&self, x: u32, y: u32) -> UVec2 {
UVec2 {
x: x * self.cell_size.x,
y: y * self.cell_size.y,
/// Parameters:
/// * `texture` - The asset handle of the texture to get the sprites from.
/// * `grid_size` - The number of the cells in the grid (i.e., 9x7 grid).
/// * `cell_size` - The dimensions of each cell in the grid (i.e., 100x100 sprites).
pub fn from_grid(
texture: ResHandle<lyra_resource::Image>,
grid_size: UVec2,
cell_size: UVec2,
) -> Self {
let mut frames = vec![];
for y in 0..grid_size.y {
for x in 0..grid_size.x {
let r = URect::new(
cell_size.x * x,
cell_size.y * y,
cell_size.x * (x + 1),
cell_size.y * (y + 1),
);
frames.push(r);
}
}
}
/// The coords of the cell at an index.
#[inline(always)]
pub fn index_coords(&self, i: u32) -> UVec2 {
let cell = self.index_cell(i);
self.cell_coords(cell.x, cell.y)
}
/// The rectangle of the cell at the x and y indices in the grid.
///
/// The indices are different then the image coords, this is the position in the grid.
/// So if you have a 9x7 grid, and wanted to get the 1nd cell on the 2nd row, you'd
/// use the values `x = 0, y = 1` (indices start at zero like arrays).
#[inline(always)]
pub fn cell_rect(&self, x: u32, y: u32) -> URect {
let start = self.cell_coords(x, y);
let end = start + self.cell_size;
URect { min: start, max: end }
}
/// The rectangle of the cell at an index.
#[inline(always)]
pub fn index_rect(&self, i: u32) -> URect {
let cell = self.index_cell(i);
self.cell_rect(cell.x, cell.y)
Self { texture, frames }
}
}
@ -95,11 +66,11 @@ impl AtlasSprite {
#[inline(always)]
pub fn from_atlas_index(atlas: ResHandle<TextureAtlas>, i: u32) -> Self {
let a = atlas.data_ref().unwrap();
let rect = a.index_rect(i);
let rect = a.frames.get(i as usize).cloned().unwrap(); //index_rect(i);
Self {
atlas: atlas.clone(),
sprite: rect,
sprite: rect,
}
}
}
}

View File

@ -1,10 +1,22 @@
use lyra_engine::{
assets::{Image, ResourceManager}, ecs::query::{Res, ResMut, View}, game::App, gltf::Gltf, input::{
assets::{Image, ResourceManager},
ecs::query::{Res, ResMut, View},
game::App,
gltf::Gltf,
input::{
Action, ActionHandler, ActionKind, ActionMapping, ActionMappingId, ActionSource,
InputActionPlugin, KeyCode, LayoutId,
}, math::{self, Rect, Transform, URect, UVec2, Vec2, Vec3}, render::light::directional::DirectionalLight, scene::{
system_update_world_transforms, Camera2dBundle, CameraProjection, OrthographicProjection, ScaleMode, TopDown2dCamera, TopDown2dCameraPlugin, WorldTransform, ACTLBL_LOOK_LEFT_RIGHT, ACTLBL_LOOK_ROLL, ACTLBL_LOOK_UP_DOWN, ACTLBL_MOVE_FORWARD_BACKWARD, ACTLBL_MOVE_LEFT_RIGHT, ACTLBL_MOVE_UP_DOWN
}, sprite::{self, AtlasAnimations, AtlasSprite, Pivot, Sprite, SpriteAnimation, TextureAtlas}, DeltaTime
},
math::{self, Rect, Transform, URect, UVec2, Vec2, Vec3},
render::light::directional::DirectionalLight,
scene::{
system_update_world_transforms, Camera2dBundle, CameraProjection, OrthographicProjection,
ScaleMode, TopDown2dCamera, TopDown2dCameraPlugin, WorldTransform, ACTLBL_LOOK_LEFT_RIGHT,
ACTLBL_LOOK_ROLL, ACTLBL_LOOK_UP_DOWN, ACTLBL_MOVE_FORWARD_BACKWARD,
ACTLBL_MOVE_LEFT_RIGHT, ACTLBL_MOVE_UP_DOWN,
},
sprite::{self, AtlasAnimations, AtlasSprite, Pivot, Sprite, SpriteAnimation, TextureAtlas},
DeltaTime,
};
use tracing::debug;
@ -96,7 +108,11 @@ async fn main() {
fn setup_scene_plugin(app: &mut App) {
//app.add_resource(Timer(0.0));
//app.with_system("sprite_change", sprite_change, &[]);
app.with_system("sprite_atlas_animation", sprite::system_sprite_atlas_animation, &[]);
app.with_system(
"sprite_atlas_animation",
sprite::system_sprite_atlas_animation,
&[],
);
let world = &mut app.world;
let resman = world.get_resource_mut::<ResourceManager>().unwrap();
@ -125,21 +141,19 @@ fn setup_scene_plugin(app: &mut App) {
let image = resman.request::<Image>("../assets/Egg_item.png").unwrap();
image.wait_recurse_dependencies_load().unwrap();
let soldier = resman.request::<Image>("../assets/tiny_rpg_characters/Characters(100x100)/Soldier/Soldier/Soldier.png").unwrap();
let soldier = resman
.request::<Image>(
"../assets/tiny_rpg_characters/Characters(100x100)/Soldier/Soldier/Soldier.png",
)
.unwrap();
soldier.wait_recurse_dependencies_load().unwrap();
let atlas = resman.store_new(TextureAtlas {
texture: soldier,
grid_offset: UVec2::ZERO,
grid_size: UVec2::new(9, 7),
cell_size: UVec2::new(100, 100),
sprite_color: Vec3::ONE,
pivot: Pivot::default(),
});
let animations = AtlasAnimations::new(atlas, &[
("soldier_run", 0.1, 9..=16),
]);
let atlas = resman.store_new(TextureAtlas::from_grid(
soldier,
UVec2::new(9, 7),
UVec2::new(100, 100),
));
let animations = AtlasAnimations::new(atlas, &[("soldier_run", 0.1, 9..=16)]);
let run_anim = animations.get_active("soldier_run");
let animations = resman.store_new(animations);
@ -180,6 +194,6 @@ fn setup_scene_plugin(app: &mut App) {
zoom_speed: Some(0.2),
speed: 14.0,
..Default::default()
}
},
));
}
}