Skip to content

Commit

Permalink
Render ground as tiling textures
Browse files Browse the repository at this point in the history
Kind of a hack based on bevyengine/bevy#399,
but good enough for now.
  • Loading branch information
mystal committed Jun 12, 2022
1 parent ece88d1 commit 996fac4
Show file tree
Hide file tree
Showing 8 changed files with 118 additions and 14 deletions.
4 changes: 3 additions & 1 deletion TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
* [ ] Save out window state when closing app.

## Graphics
* [ ] Set up animating bird
* [x] Set up animating bird
* Try [benimator](https://github.com/jcornaz/benimator) or [bevy_sprite_animation](https://github.com/PhaestusFox/bevy_sprite_animation)
* [ ] Draw tiling textures for art and pipes
* https://github.com/bevyengine/bevy/issues/399#issuecomment-1015353924

# Done
## Gameplay
Expand Down
Binary file added assets/sprites/Tileset/Style 1/OldS2-Ground.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/sprites/Tileset/Style 1/OldS2-GroundTop.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/sprites/Tileset/Style 1/OldS2-PipeCenter.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
68 changes: 68 additions & 0 deletions src/assets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ use std::time::Duration;

use benimator::SpriteSheetAnimation;
use bevy::prelude::*;
use bevy::{
sprite::Rect,
render::render_resource::AddressMode,
};
use bevy_asset_loader::{AssetCollection, AssetLoader};
use iyes_loopless::prelude::*;

Expand Down Expand Up @@ -31,15 +35,79 @@ pub struct GameAssets {

#[asset(path = "sprites/Background/Background5.png")]
pub background: Handle<Image>,

#[asset(path = "sprites/Tileset/Style 1/OldS2.png")]
pub terrain_image: Handle<Image>,
pub terrain_atlas: Handle<TextureAtlas>,
pub terrain_indices: TerrainAtlasIndices,

#[asset(path = "sprites/Tileset/Style 1/OldS2-PipeCenter.png")]
pub pipe_center: Handle<Image>,
#[asset(path = "sprites/Tileset/Style 1/OldS2-GroundTop.png")]
pub ground_top: Handle<Image>,
#[asset(path = "sprites/Tileset/Style 1/OldS2-Ground.png")]
pub ground: Handle<Image>,
}

#[derive(Default)]
pub struct TerrainAtlasIndices {
pub pipe_top: usize,
pub pipe_bottom: usize,
pub pipe_center: usize,

pub ground_top: usize,
pub ground: usize,
}

fn assets_loaded(
mut assets: ResMut<GameAssets>,
mut animations: ResMut<Assets<SpriteSheetAnimation>>,
mut atlases: ResMut<Assets<TextureAtlas>>,
mut images: ResMut<Assets<Image>>,
) {
eprintln!("Loaded assets!");

// Bird anim info asset.
let bird_anim = SpriteSheetAnimation::from_range(0..=3, Duration::from_millis(150));
assets.bird_anim = animations.add(bird_anim);

// Populate terrain texture atlas.
if let Some(image) = images.get_mut(&assets.terrain_image) {
image.sampler_descriptor.address_mode_u = AddressMode::Repeat;
image.sampler_descriptor.address_mode_v = AddressMode::Repeat;

let mut atlas = TextureAtlas::new_empty(assets.terrain_image.clone(), image.size());
assets.terrain_indices.pipe_top = atlas.add_texture(Rect {
min: Vec2::new(0.0, 0.0),
max: Vec2::new(32.0, 16.0),
});
assets.terrain_indices.pipe_bottom = atlas.add_texture(Rect {
min: Vec2::new(0.0, 64.0),
max: Vec2::new(32.0, 80.0),
});
assets.terrain_indices.pipe_center = atlas.add_texture(Rect {
min: Vec2::new(2.0, 32.0),
max: Vec2::new(30.0, 48.0),
});
assets.terrain_indices.ground_top = atlas.add_texture(Rect {
min: Vec2::new(0.0, 80.0),
max: Vec2::new(16.0, 96.0),
});
assets.terrain_indices.ground = atlas.add_texture(Rect {
min: Vec2::new(0.0, 96.0),
max: Vec2::new(16.0, 112.0),
});

assets.terrain_atlas = atlases.add(atlas);
}

// Set repeat address mode on tiling textures.
if let Some(image) = images.get_mut(&assets.ground) {
image.sampler_descriptor.address_mode_u = AddressMode::Repeat;
image.sampler_descriptor.address_mode_v = AddressMode::Repeat;
}
if let Some(image) = images.get_mut(&assets.ground_top) {
image.sampler_descriptor.address_mode_u = AddressMode::Repeat;
image.sampler_descriptor.address_mode_v = AddressMode::Repeat;
}
}
55 changes: 45 additions & 10 deletions src/game.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use bevy::prelude::*;
use bevy::{
render::camera::WindowOrigin,
render::{camera::WindowOrigin, mesh::VertexAttributeValues},
sprite::Anchor,
};
use bevy_egui::EguiContext;
Expand Down Expand Up @@ -200,6 +200,9 @@ fn setup_game(
assets: Res<GameAssets>,
mut game_data: ResMut<GameData>,
window_scale: Res<WindowScale>,
images: Res<Assets<Image>>,
mut materials: ResMut<Assets<ColorMaterial>>,
mut meshes: ResMut<Assets<Mesh>>,
) {
eprintln!("Setting up game");

Expand Down Expand Up @@ -229,17 +232,49 @@ fn setup_game(
commands.spawn_bundle(background_sprite)
.insert(Name::new("Background"));

// Spawn ground sprite
let ground_sprite = SpriteBundle {
transform: Transform::from_translation(Vec3::new(GAME_SIZE.0 / 2.0, GROUND_OFFSET, 10.0)),
sprite: Sprite {
color: Color::DARK_GREEN,
custom_size: Some(Vec2::new(GAME_SIZE.0, GROUND_OFFSET * 2.0)),
..default()
},
// Spawn tiling ground texture.
let ground_image_size = images.get(&assets.ground).unwrap().size();
let mut ground_mesh = Mesh::from(shape::Quad::default());
if let Some(VertexAttributeValues::Float32x2(uvs)) = ground_mesh.attribute_mut(Mesh::ATTRIBUTE_UV_0) {
for uv in uvs {
uv[0] *= GAME_SIZE.0 / ground_image_size.x;
uv[1] *= (GROUND_OFFSET * 2.0) / ground_image_size.y;
}
}
let ground_transform = Transform {
translation: Vec3::new(GAME_SIZE.0 / 2.0, GROUND_OFFSET, 10.0),
scale: Vec3::new(GAME_SIZE.0, GROUND_OFFSET * 2.0, 1.0),
..default()
};
let ground_bundle = ColorMesh2dBundle {
transform: ground_transform,
material: materials.add(assets.ground.clone().into()),
mesh: meshes.add(ground_mesh.into()).into(),
..default()
};
commands.spawn_bundle(ground_bundle)
.insert(Name::new("Ground"));

// Spawn tiling ground top texture.
let ground_image_size = images.get(&assets.ground_top).unwrap().size();
let mut ground_mesh = Mesh::from(shape::Quad::default());
if let Some(VertexAttributeValues::Float32x2(uvs)) = ground_mesh.attribute_mut(Mesh::ATTRIBUTE_UV_0) {
for uv in uvs {
uv[0] *= GAME_SIZE.0 / ground_image_size.x;
}
}
let ground_transform = Transform {
translation: Vec3::new(GAME_SIZE.0 / 2.0, (GROUND_OFFSET * 2.0) - (ground_image_size.y / 2.0), 10.0),
scale: Vec3::new(GAME_SIZE.0, ground_image_size.y, 1.0),
..default()
};
let ground_bundle = ColorMesh2dBundle {
transform: ground_transform,
material: materials.add(assets.ground_top.clone().into()),
mesh: meshes.add(ground_mesh.into()).into(),
..default()
};
commands.spawn_bundle(ground_sprite)
commands.spawn_bundle(ground_bundle)
.insert(Name::new("Ground"));

// Spawn pipes offscreen.
Expand Down
3 changes: 1 addition & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,7 @@ fn main() {
mode: WindowMode::Windowed,
..default()
})
// .insert_resource(ClearColor(Color::hex("018893").unwrap()))
.insert_resource(ClearColor(Color::rgb_u8(230, 230, 230)))
.insert_resource(ClearColor(Color::rgb_u8(0, 57, 109)))

// External plugins
.add_plugins(DefaultPlugins)
Expand Down
2 changes: 1 addition & 1 deletion src/menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ fn setup_main_menu(
let style = TextStyle {
font: assets.font.clone(),
font_size: 80.0,
color: Color::BLACK,
color: Color::WHITE,
};
let alignment = TextAlignment {
horizontal: HorizontalAlign::Center,
Expand Down

0 comments on commit 996fac4

Please sign in to comment.