diff --git a/Cargo.lock b/Cargo.lock
index da3ec54d..aa197424 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -808,6 +808,17 @@ dependencies = [
"syn 2.0.77",
]
+[[package]]
+name = "bevy_ecs_tilemap"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d880047f5deaf5166ffc08238125a4ccbd2837f781ca6525fa200fcf5785ba3b"
+dependencies = [
+ "bevy",
+ "log",
+ "regex",
+]
+
[[package]]
name = "bevy_encase_derive"
version = "0.14.2"
@@ -3818,6 +3829,8 @@ name = "my_bevy_game"
version = "0.1.0"
dependencies = [
"bevy",
+ "bevy_ecs_tilemap",
+ "rand 0.8.5",
"trunk",
"wasm-bindgen",
"web-sys",
diff --git a/Cargo.toml b/Cargo.toml
index afe6fd02..3b412e4b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -5,6 +5,8 @@ edition = "2021"
[dependencies]
bevy = "0.14.2"
+bevy_ecs_tilemap = "0.14.0"
+rand = "0.8.5"
wasm-bindgen = "0.2.78"
[dependencies.web-sys]
diff --git a/assets/Pixel Art Top Down Basic/TX Plant.png b/assets/Pixel Art Top Down Basic/TX Plant.png
new file mode 100644
index 00000000..1f183454
Binary files /dev/null and b/assets/Pixel Art Top Down Basic/TX Plant.png differ
diff --git a/assets/Pixel Art Top Down Basic/TX Player.png b/assets/Pixel Art Top Down Basic/TX Player.png
new file mode 100644
index 00000000..71d6b16f
Binary files /dev/null and b/assets/Pixel Art Top Down Basic/TX Player.png differ
diff --git a/assets/Pixel Art Top Down Basic/TX Props.png b/assets/Pixel Art Top Down Basic/TX Props.png
new file mode 100644
index 00000000..2fb5bf16
Binary files /dev/null and b/assets/Pixel Art Top Down Basic/TX Props.png differ
diff --git a/assets/Pixel Art Top Down Basic/TX Shadow Plant.png b/assets/Pixel Art Top Down Basic/TX Shadow Plant.png
new file mode 100644
index 00000000..b5650547
Binary files /dev/null and b/assets/Pixel Art Top Down Basic/TX Shadow Plant.png differ
diff --git a/assets/Pixel Art Top Down Basic/TX Shadow.png b/assets/Pixel Art Top Down Basic/TX Shadow.png
new file mode 100644
index 00000000..67a2a646
Binary files /dev/null and b/assets/Pixel Art Top Down Basic/TX Shadow.png differ
diff --git a/assets/Pixel Art Top Down Basic/TX Struct.png b/assets/Pixel Art Top Down Basic/TX Struct.png
new file mode 100644
index 00000000..dd3f1b04
Binary files /dev/null and b/assets/Pixel Art Top Down Basic/TX Struct.png differ
diff --git a/assets/Pixel Art Top Down Basic/TX Tileset Grass.png b/assets/Pixel Art Top Down Basic/TX Tileset Grass.png
new file mode 100644
index 00000000..dd5d66c0
Binary files /dev/null and b/assets/Pixel Art Top Down Basic/TX Tileset Grass.png differ
diff --git a/assets/Pixel Art Top Down Basic/TX Tileset Stone Ground.png b/assets/Pixel Art Top Down Basic/TX Tileset Stone Ground.png
new file mode 100644
index 00000000..4dee6c0c
Binary files /dev/null and b/assets/Pixel Art Top Down Basic/TX Tileset Stone Ground.png differ
diff --git a/assets/Pixel Art Top Down Basic/TX Tileset Wall.png b/assets/Pixel Art Top Down Basic/TX Tileset Wall.png
new file mode 100644
index 00000000..555a2ffb
Binary files /dev/null and b/assets/Pixel Art Top Down Basic/TX Tileset Wall.png differ
diff --git a/index.html b/index.html
index e7ee0f73..27fb56e8 100644
--- a/index.html
+++ b/index.html
@@ -1,7 +1,9 @@
+
+
diff --git a/readme.md b/readme.md
index cdfc7222..0a06be6c 100644
--- a/readme.md
+++ b/readme.md
@@ -14,4 +14,10 @@ $ trunk serve
- https://trunkrs.dev/
- https://bevy-cheatbook.github.io/platforms/wasm.html
-- https://gist.github.com/nakedible/f6a0d4bcbea1df7768e9ed425f6f33db
\ No newline at end of file
+- https://gist.github.com/nakedible/f6a0d4bcbea1df7768e9ed425f6f33db
+
+
+
+### Assets
+
+- https://cainos.itch.io/pixel-art-top-down-basic
\ No newline at end of file
diff --git a/src/main.rs b/src/main.rs
index 935e1e27..f7114cb3 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,98 +1,180 @@
-//! Shows how to render simple primitive shapes with a single color.
-
use bevy::{
+ asset::{AssetMetaCheck, AssetPlugin},
prelude::*,
- sprite::{MaterialMesh2dBundle, Mesh2dHandle},
+ render::camera::CameraRenderGraph,
};
+use bevy_ecs_tilemap::prelude::*;
+use rand::prelude::*;
use wasm_bindgen::JsValue;
use web_sys::console;
+#[derive(Component)]
+struct Person;
+
+#[derive(Component)]
+struct HUD;
+
fn main() {
console::log_1(&JsValue::from("start"));
let mut app = App::new();
- app.add_plugins((DefaultPlugins,))
- .add_systems(Startup, setup);
- app.add_systems(Update, keyboard_input);
+
+ app.add_plugins(
+ DefaultPlugins
+ .set(AssetPlugin {
+ // https://github.com/bevyengine/bevy/issues/10157
+ meta_check: AssetMetaCheck::Never,
+ ..default()
+ })
+ .set(ImagePlugin::default_nearest()),
+ )
+ .add_plugins(TilemapPlugin)
+ .add_systems(Startup, setup)
+ .add_systems(Update, update);
+
app.run();
}
-const X_EXTENT: f32 = 900.;
+fn setup(mut commands: Commands, asset_server: Res) {
+ // デフォルトでは far: 1000, near: -1000でカメラが作成される
+ // この範囲を超えるとクリップされることに注意
+ let mut camera_bundle = Camera2dBundle::default();
+ camera_bundle.projection.scale = 0.5;
-fn setup(
- mut commands: Commands,
- mut meshes: ResMut>,
- mut materials: ResMut>,
-) {
- commands.spawn(Camera2dBundle::default());
-
- let shapes = [
- Mesh2dHandle(meshes.add(Circle { radius: 50.0 })),
- Mesh2dHandle(meshes.add(CircularSector::new(50.0, 1.0))),
- Mesh2dHandle(meshes.add(CircularSegment::new(50.0, 1.25))),
- Mesh2dHandle(meshes.add(Ellipse::new(25.0, 50.0))),
- Mesh2dHandle(meshes.add(Annulus::new(25.0, 50.0))),
- Mesh2dHandle(meshes.add(Capsule2d::new(25.0, 50.0))),
- Mesh2dHandle(meshes.add(Rhombus::new(75.0, 100.0))),
- Mesh2dHandle(meshes.add(Rectangle::new(50.0, 100.0))),
- Mesh2dHandle(meshes.add(RegularPolygon::new(50.0, 6))),
- Mesh2dHandle(meshes.add(Triangle2d::new(
- Vec2::Y * 50.0,
- Vec2::new(-50.0, -50.0),
- Vec2::new(50.0, -50.0),
- ))),
- ];
- let num_shapes = shapes.len();
-
- for (i, shape) in shapes.into_iter().enumerate() {
- // Distribute colors evenly across the rainbow.
- let color = Color::hsl(360. * i as f32 / num_shapes as f32, 0.95, 0.7);
-
- commands.spawn(MaterialMesh2dBundle {
- mesh: shape,
- material: materials.add(color),
- transform: Transform::from_xyz(
- // Distribute shapes from -X_EXTENT/2 to +X_EXTENT/2.
- -X_EXTENT / 2. + i as f32 / (num_shapes - 1) as f32 * X_EXTENT,
- 0.0,
- 0.0,
- ),
- ..default()
- });
- }
+ commands.spawn(camera_bundle);
- commands.spawn(
- TextBundle::from_section("Primitives Test", TextStyle::default()).with_style(Style {
+ commands.spawn((
+ TextBundle::from_section("Test", TextStyle::default()).with_style(Style {
position_type: PositionType::Absolute,
top: Val::Px(12.0),
left: Val::Px(12.0),
..default()
}),
- );
-}
+ HUD,
+ ));
-fn keyboard_input(keys: Res>) {
- if keys.just_pressed(KeyCode::Space) {
- // Space was pressed
- console::log_1(&JsValue::from("space was pressed"));
- }
- if keys.just_released(KeyCode::ControlLeft) {
- // Left Ctrl was released
- console::log_1(&JsValue::from("left ctrl was released"));
- }
- if keys.pressed(KeyCode::KeyW) {
- // W is being held down
- console::log_1(&JsValue::from("W is being held down"));
- }
- // we can check multiple at once with `.any_*`
- if keys.any_pressed([KeyCode::ShiftLeft, KeyCode::ShiftRight]) {
- // Either the left or right shift are being held down
- console::log_1(&JsValue::from(
- "Either the left or right shift are being held down",
- ));
+ for _ in 0..10 {
+ let x = 400.0 * rand::random::();
+ let y = 400.0 * rand::random::();
+ commands.spawn(SpriteBundle {
+ transform: Transform::from_xyz(x, y, -y),
+ texture: asset_server.load("Pixel Art Top Down Basic/TX Plant.png"),
+ sprite: Sprite {
+ anchor: bevy::sprite::Anchor::BottomCenter,
+ rect: Some(Rect::new(0.0, 0.0, 8.0 * 19.0, 155.0)),
+ ..default()
+ },
+ ..default()
+ });
}
- if keys.any_just_pressed([KeyCode::Delete, KeyCode::Backspace]) {
- // Either delete or backspace was just pressed
+
+ commands.spawn((
+ Person,
+ SpriteBundle {
+ transform: Transform::from_xyz(0.0, 0.0, 1.0),
+ texture: asset_server.load("Pixel Art Top Down Basic/TX Player.png"),
+ sprite: Sprite {
+ anchor: bevy::sprite::Anchor::BottomCenter,
+ rect: Some(Rect::new(0.0, 0.0, 32.0, 58.0)),
+ ..default()
+ },
+ ..default()
+ },
+ ));
+
+ let texture_handle: Handle =
+ asset_server.load("Pixel Art Top Down Basic/TX Tileset Grass.png");
+
+ let map_size = TilemapSize { x: 256, y: 256 };
+
+ let tilemap_entity = commands.spawn_empty().id();
+
+ let mut tile_storage = TileStorage::empty(map_size);
+
+ for x in 0..map_size.x {
+ for y in 0..map_size.y {
+ let tile_pos = TilePos { x, y };
+ let tile_entity = commands
+ .spawn(TileBundle {
+ // 0~120くらいが原っぱのタイル、それ以降は石畳など
+ // ひとまず原っぱをランダムに配置
+ texture_index: TileTextureIndex(rand::random::() % 120),
+ position: tile_pos,
+ tilemap_id: TilemapId(tilemap_entity),
+ ..Default::default()
+ })
+ .id();
+ tile_storage.set(&tile_pos, tile_entity);
+ }
}
+
+ let tile_size = TilemapTileSize { x: 16.0, y: 16.0 };
+ let grid_size = tile_size.into();
+ let map_type = TilemapType::default();
+
+ // fill_tilemap_rect_color(
+ // TileTextureIndex(0),
+ // TilePos { x: 0, y: 0 },
+ // TilemapSize { x: 1, y: 1 },
+ // Color::srgba(1.0, 0.0, 0.0, 1.0),
+ // TilemapId(tilemap_entity),
+ // &mut commands,
+ // &mut tile_storage,
+ // );
+
+ commands.entity(tilemap_entity).insert(TilemapBundle {
+ grid_size,
+ map_type,
+ size: map_size,
+ storage: tile_storage,
+ texture: TilemapTexture::Single(texture_handle),
+ tile_size,
+ // タイルマップは最も背後に配置したいので z: -1000にする
+ // サンプルコードでは get_tilemap_center_transform を使って画面中央に揃えているが、
+ // 座標計算が面倒になるので x:0, y:0 に配置している
+ // transform: get_tilemap_center_transform(&map_size, &grid_size, &map_type, -1000.0),
+ transform: Transform::from_xyz(0.0, 0.0, -1000.0),
+ ..Default::default()
+ });
+}
+
+fn update(
+ keys: Res>,
+ mut player_query: Query<&mut Transform, (With, Without)>,
+ mut camera_query: Query<&mut Transform, (With, Without)>,
+ mut hud_query: Query<&mut Text, With>,
+) {
+ let speed = 3.0;
+
+ let velocity = Vec2::new(
+ to_s(&keys, KeyCode::KeyD) - to_s(&keys, KeyCode::KeyA),
+ to_s(&keys, KeyCode::KeyW) - to_s(&keys, KeyCode::KeyS),
+ )
+ .normalize_or_zero()
+ * speed;
+
+ let mut player = player_query.single_mut();
+
+ player.translation.x += velocity.x;
+ player.translation.y += velocity.y;
+ player.translation.z = -player.translation.y;
+
+ let mut camera = camera_query.single_mut();
+
+ camera.translation.x += (player.translation.x - camera.translation.x) * 0.1;
+ camera.translation.y += (player.translation.y - camera.translation.y) * 0.1;
+
+ let mut hud = hud_query.single_mut();
+
+ let text = format!(
+ "Player: ({:.2}, {:.2})\nCamera: ({:.2}, {:.2})",
+ player.translation.x, player.translation.y, camera.translation.x, camera.translation.y
+ );
+
+ hud.sections = vec![TextSection::from(text)];
+}
+
+fn to_s(keys: &Res>, code: bevy::input::keyboard::KeyCode) -> f32 {
+ return if keys.pressed(code) { 1.0 } else { 0.0 };
}