Skip to content

Commit

Permalink
refactor setup, player build into tilemap build, build wall, started …
Browse files Browse the repository at this point in the history
…working on player movement with impassable tiles
  • Loading branch information
peregrine-l committed Feb 21, 2024
1 parent 7ca26b4 commit 1af5201
Show file tree
Hide file tree
Showing 8 changed files with 171 additions and 92 deletions.
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"./Cargo.toml",
"./Cargo.toml",
"./Cargo.toml",
"./Cargo.toml",
"./Cargo.toml"
]
}
6 changes: 3 additions & 3 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ Legend:
- [] Basic terrain layer (0) with random ground tiles
- [] Basic characters layer (2) with Player stating at the center
- [] Player 4-direction movement (arrows)
- [+] Asset management, for tilemaps but also characters
- [+] Access through mapping functions: TileTextureIndex(1D-coordinates)
- [] Asset management, for tilemaps but also characters
- [] Access through mapping functions: TileTextureIndex(1D-coordinates)
<= Spritesheets with specific coordinates <= abstract Unicode symbols
- [+] Dungeon floors, Dungeon wall (no direction),
- [] Dungeon floors, Dungeon wall (no direction),
Adventurer Player (no animation), Monster (no animation)
- [ ] Wall component, that blocks movement
- [ ] Set up simple map with walls for testing
Expand Down
33 changes: 24 additions & 9 deletions src/components.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use bevy::prelude::*;
use bevy_ecs_tilemap::prelude::*;

// Map

Expand All @@ -15,17 +14,33 @@ pub enum TilemapMarker {
CharactersTilemap,
}

// Player

#[derive(Component)]
pub struct Player;
pub struct Impassable;

pub enum WallOrientation {
NorthwestCorner,
Horizontal,
NortheastCorner,
Vertical,
SoutheastCorner,
SouthwestCorner,
Pillar,
Undefined,
}

#[derive(Component)]
pub struct Health(pub u32);
pub struct Wall(pub WallOrientation);

#[derive(Bundle)]
pub struct PlayerBundle {
pub marker: Player,
pub health: Health,
pub position: TilePos,
pub struct WallBundle {
pub wall: Wall,
pub pass: Impassable,
}

// Player

#[derive(Component, PartialEq)]
pub struct Player;

#[derive(Component)]
pub struct Health(pub u32);
35 changes: 5 additions & 30 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,42 +1,17 @@
use bevy::{log::LogPlugin, prelude::*};
use bevy::prelude::*;
use bevy_ecs_tilemap::prelude::*;

pub mod components;
pub mod map;
pub mod mappings;
pub mod player;
pub mod resources;
pub mod setup;

use crate::components::TilemapMarker;
use crate::resources::AssetPack;
use bevy::log::LogPlugin;
use crate::setup::select_asset_pack;
use crate::setup::game_setup;

fn select_asset_pack() -> AssetPack {
// TODO: here test for the presence of the OneBitCanari asset pack
// if absent, use the Free asset pack
let free_asset_pack = AssetPack {
name: "Free asset pack",
tileset: "FreeAssetPack/RogueYun_SomethingBoxy.png",
sprites: "FreeAssetPack/RogueYun_SomethingBoxy.png",
};

return free_asset_pack;
}

fn game_setup(
mut commands: Commands,
asset_pack: Res<AssetPack>,
query: Query<(&TileStorage, &TilemapMarker)>,
asset_server: Res<AssetServer>,
) {
commands.spawn(Camera2dBundle::default());

for tilemap_metadata in crate::map::setup_tilemap_metadata(asset_pack).iter() {
crate::map::build_tilemap(&mut commands, &asset_server, tilemap_metadata);
}


crate::player::build_player(&mut commands, query);
}

fn main() {
App::new()
Expand Down
60 changes: 57 additions & 3 deletions src/map.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use bevy::prelude::*;
use bevy_ecs_tilemap::{prelude::*, tiles::TileTextureIndex};
use bevy_ecs_tilemap::prelude::*;

use crate::components::{TileMarker, TilemapMarker};
use crate::components::{TileMarker, TilemapMarker, Impassable, Wall, WallOrientation};
use crate::mappings::cp437_tile;
use crate::resources::AssetPack;

Expand Down Expand Up @@ -33,7 +33,7 @@ pub fn setup_tilemap_metadata(asset_pack: Res<AssetPack>) -> [TilemapMetadata; 2
return [terrain_tilemap, characters_tilemap];
}

pub fn build_tilemap(
pub fn build_tilemap (
commands: &mut Commands,
asset_server: &Res<AssetServer>,
tilemap_metadata: &TilemapMetadata,
Expand All @@ -42,12 +42,14 @@ pub fn build_tilemap(
let map_size = TilemapSize { x: 32, y: 32 };
let tile_size = TilemapTileSize { x: 16.0, y: 16.0 };
let grid_size = tile_size.into();
let start_position = (1, 1);

let texture_handle: Handle<Image> =
asset_server.load(format!("{}", tilemap_metadata.asset_path));
let mut tile_storage = TileStorage::empty(map_size);
let tilemap_entity = commands.spawn_empty().id();

let mut player_start_tile = None;
for x in 0..map_size.x {
for y in 0..map_size.y {
let tile_pos = TilePos { x, y };
Expand All @@ -62,10 +64,15 @@ pub fn build_tilemap(
tilemap_metadata.tile_marker.clone(),
))
.id();
if (x, y) == start_position {
player_start_tile = Some(tile_entity);
}
tile_storage.set(&tile_pos, tile_entity);
}
}

build_walls(commands, tilemap_entity, map_size, &mut tile_storage);

let map_type = TilemapType::Square;
commands.entity(tilemap_entity).insert((
TilemapBundle {
Expand All @@ -86,4 +93,51 @@ pub fn build_tilemap(
},
tilemap_metadata.tilemap_marker.clone(),
));

// Player initialization, needs starting tile entity
if tilemap_metadata.tilemap_marker == TilemapMarker::CharactersTilemap {
crate::player::build_player(commands, player_start_tile.unwrap(), start_position);
}
}

fn build_walls(
commands: &mut Commands,
tilemap_entity: Entity,
map_size: TilemapSize,
tile_storage: &mut TileStorage
) {
fn build_single_wall(
commands: &mut Commands,
tilemap_entity: Entity,
tile_storage: &mut TileStorage,
x: u32,
y: u32,
) {
let tile_pos = TilePos { x, y };
let tile_entity = commands
.spawn((
TileBundle {
position: tile_pos,
tilemap_id: TilemapId(tilemap_entity),
texture_index: cp437_tile(&'#'),
..Default::default()
},
TileMarker::TerrainTile,
Wall(WallOrientation::Undefined),
Impassable,
))
.id();
tile_storage.set(&tile_pos, tile_entity);
}

for i in 0..map_size.x {
for j in 0..map_size.y {
if j == 0 || j == map_size.y - 1 {
build_single_wall(commands, tilemap_entity, tile_storage, i, j);
} else if !(j == 0 || j == map_size.y - 1)
&& (i == 0 || i == map_size.x - 1) {
build_single_wall(commands, tilemap_entity, tile_storage, i, j);
}
}
}
}
4 changes: 4 additions & 0 deletions src/mappings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ use self::cp437::CP437;
pub mod canaripack;
pub mod cp437;

pub fn cp437_pos(c: &char) -> u32 {
return *CP437.get(&c).unwrap();
}

pub fn cp437_tile(c: &char) -> TileTextureIndex {
return TileTextureIndex(*CP437.get(&c).unwrap());
}
Expand Down
95 changes: 48 additions & 47 deletions src/player.rs
Original file line number Diff line number Diff line change
@@ -1,36 +1,33 @@
use crate::components::{Health, Player, PlayerBundle, TilemapMarker};
use crate::mappings::cp437_tile;
use bevy::prelude::*;
use bevy_ecs_tilemap::{
helpers::square_grid::neighbors::{Neighbors, SquareDirection},
prelude::*,
};

pub fn build_player(commands: &mut Commands, query: Query<(&TileStorage, &TilemapMarker)>) {
commands.spawn(PlayerBundle {
marker: Player,
health: Health(1),
position: TilePos { x: 0, y: 0 },
}); // player entity
use crate::components::{Health, Impassable, Player, TilemapMarker};
use crate::mappings::{cp437_pos, cp437_tile};

if query.is_empty() { info!("empty q"); }
for (tile_storage, tilemap_marker) in query.iter() {
match tilemap_marker {
TilemapMarker::CharactersTilemap => {
let player_start_tile = tile_storage.get(&TilePos { x: 0, y: 0 }).unwrap();
commands.entity(player_start_tile).insert(cp437_tile(&'☺')); // character sprite
info!("init player tile");
}
TilemapMarker::TerrainTilemap => {}
}
}
pub fn build_player(
commands: &mut Commands,
player_start_tile: Entity,
player_start_pos: (u32, u32),
) {
commands.spawn((
Player,
Health(1),
TilePos { x: player_start_pos.0, y: player_start_pos.1 },
Impassable
)); // player entity

commands.entity(player_start_tile).insert(cp437_tile(&'☺'));
}

pub fn player_movement(
keyboard_input: Res<Input<KeyCode>>,
mut player_q: Query<&mut TilePos, With<Player>>,
tilemap_q: Query<(&TilemapMarker, &TilemapSize, &TileStorage)>,
mut tiles_q: Query<&mut TileTextureIndex>,
tilemap_q: Query<(&TilemapSize, &TileStorage, &TilemapMarker)>,
mut player_q: Query<&mut TilePos, With<Player>>,
impassables_q: Query<&TilePos, With<Impassable>>,
) {
let input_direction = if !keyboard_input.any_pressed([KeyCode::ShiftLeft, KeyCode::ShiftRight])
{
Expand All @@ -50,39 +47,43 @@ pub fn player_movement(
};

if let Some(movement_direction) = input_direction {
let mut player_pos = player_q.get_single_mut().unwrap();
let mut tilemap_size: Option<&TilemapSize> = None;
let mut chars_tile_storage: Option<&TileStorage> = None;

for (tilemap_size, tile_storage, tilemap_marker) in tilemap_q.iter() {
match tilemap_marker {
for (q_tilemap_marker, q_tilemap_size, q_chars_tile_storage) in tilemap_q.iter() {
match q_tilemap_marker {
TilemapMarker::CharactersTilemap => {
let neighboring_tiles = Neighbors::get_square_neighboring_positions(
&player_pos,
tilemap_size,
false,
);
tilemap_size = Some(q_tilemap_size);
chars_tile_storage = Some(q_chars_tile_storage);
}
TilemapMarker::TerrainTilemap => {} // for later interactions with the terrain
}
}

if let Some(target_pos) = neighboring_tiles.get(movement_direction) {
{
let source_tile_id = tile_storage.get(&player_pos).unwrap();
let mut source_tile_texture_index =
tiles_q.get_mut(source_tile_id).unwrap();
source_tile_texture_index.0 = cp437_tile(&'\u{0000}').0;
// set to transparent sprite
}
let mut player_pos = player_q.get_single_mut().unwrap();

{
let target_tile_id = tile_storage.get(target_pos).unwrap();
let mut target_tile_texture_index =
tiles_q.get_mut(target_tile_id).unwrap();
target_tile_texture_index.0 = cp437_tile(&'☺').0; // set to character sprite
}
let neighboring_tiles = Neighbors::get_square_neighboring_positions(
&player_pos,
tilemap_size.unwrap(),
false,
);

(player_pos.x, player_pos.y) = (target_pos.x, target_pos.y);
}
}
if let Some(target_pos) = neighboring_tiles.get(movement_direction) {
{
let source_tile_id = chars_tile_storage.unwrap().get(&player_pos).unwrap();
let mut source_tile_texture_index =
tiles_q.get_mut(source_tile_id).unwrap();
source_tile_texture_index.0 = cp437_pos(&'\u{0000}'); // set to transparent sprite
}

TilemapMarker::TerrainTilemap => {} // for later interactions with the terrain
{
let target_tile_id = chars_tile_storage.unwrap().get(&target_pos).unwrap();
let mut target_tile_texture_index =
tiles_q.get_mut(target_tile_id).unwrap();
target_tile_texture_index.0 = cp437_pos(&'☺'); // set to character sprite
}

(player_pos.x, player_pos.y) = (target_pos.x, target_pos.y);
}
}
}
29 changes: 29 additions & 0 deletions src/setup.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use bevy::prelude::*;

use crate::resources::AssetPack;

pub fn select_asset_pack() -> AssetPack {
// TODO: here test for the presence of the OneBitCanari asset pack
// if absent, use the Free asset pack
let free_asset_pack = AssetPack {
name: "Free asset pack",
tileset: "FreeAssetPack/RogueYun_SomethingBoxy.png",
sprites: "FreeAssetPack/RogueYun_SomethingBoxy.png",
};

return free_asset_pack;
}

pub fn game_setup(
mut commands: Commands,
asset_pack: Res<AssetPack>,
asset_server: Res<AssetServer>,
) {
commands.spawn(Camera2dBundle::default());

for tilemap_metadata in crate::map::setup_tilemap_metadata(asset_pack).iter() {
crate::map::build_tilemap(&mut commands, &asset_server, tilemap_metadata);
}

// player creation done in build_tilemap for TilemapMarker::CharactersTilemap
}

0 comments on commit 1af5201

Please sign in to comment.