我正在尝试在 Bevy 中渲染一个棋盘(或制作一个基于网格的系统)。
我有这个组件:
#[derive(Debug, Component)]
/// Defines a single grid.
/// As `Cell` is a term used in Rust terminology, Grid is a better way to refer to this.
pub(crate) struct Grid(u8, u8);
impl Grid {
pub(crate) fn new(x: u8, y: u8) -> Self {
Self(x, y)
}
pub(crate) fn x(&self) -> u8 {
self.0
}
pub(crate) fn y(&self) -> u8 {
self.1
}
pub(crate) fn indices(&self) -> (u8, u8) {
(self.x(), self.y())
}
}
还有这些启动系统:
pub(crate) fn init_grids(mut commands: Commands) {
debug!("Initializing grids...");
//| initializing grids up to u8::MAX
for x in 0..u8::MAX {
for y in 0..u8::MAX {
commands.spawn(Grid::new(x, y));
}
}
}
pub(crate) fn paint_grids(
grid_query: Query<&Grid>,
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<ColorMaterial>>,
) {
debug!("Painting grids...");
//| iterating over each grid
for grid in grid_query.iter() {
//| unpack x and y val of the grid
let (grid_x, grid_y) = grid.indices();
//| choose color black or white based on grid x and y value
let color = if (grid_x + grid_y) % 2 == 0 {
Color::BLACK
} else {
Color::WHITE
};
//| define grid's pixel position
let pos_x = grid_x * GRID_SIZE;
let pos_y = grid_y * GRID_SIZE;
//| create a rectangle
let mesh_handler =
Mesh2dHandle(meshes.add(Rectangle::new(GRID_SIZE as f32, GRID_SIZE as f32)));
//| draw the rectangle
commands.spawn(MaterialMesh2dBundle {
mesh: mesh_handler,
material: materials.add(color), //| define its color
transform: Transform::from_xyz(pos_x as f32, pos_y as f32, 0.0), //| define its pos in the screen
..Default::default()
});
}
}
...其中
GRID_SIZE
是 u8
常数,其值为 16
。
DefaultPlugins
和 Camera2dBundle
已初始化,但我看到的是纯灰色屏幕。
尽管初始化了相机和默认插件并添加了系统,但它仍呈现空白屏幕。
我对 Bevy 有点陌生(不是 Rust),所以我想知道我是否在这里遗漏了一些东西。
提前致谢。
项目有一个
CorePlugin
,用于设置所有其他插件。目前,它只有另一个名为 GridPlugin
的插件。
一些可能相关的文件:
// main.rs
use bevy::app::App;
use oxidized_pixel_dungeon::core::CorePlugin;
fn main() {
App::new().add_plugins(CorePlugin).run();
}
// core/mod.rs
use bevy::{
app::{Plugin, PluginGroup, Startup},
core_pipeline::core_2d::Camera2dBundle,
ecs::system::Commands,
log::LogPlugin,
utils::tracing::field::debug,
DefaultPlugins,
};
use crate::grid::GridPlugin;
pub struct CorePlugin;
impl Plugin for CorePlugin {
fn build(&self, app: &mut bevy::prelude::App) {
let default_plugins = DefaultPlugins.set(if cfg!(debug_assertions) {
LogPlugin {
level: bevy::log::Level::TRACE,
filter: "info,wgpu_core=warn,wgpu_hal=warn,oxidized_pixel_dungeon=trace".into(),
..Default::default()
}
} else {
LogPlugin {
level: bevy::log::Level::INFO,
filter: "info,wgpu_core=warn,wgpu_hal=warn".into(),
..Default::default()
}
});
app.add_plugins(default_plugins)
.add_systems(Startup, init_system)
.add_plugins(GridPlugin);
}
}
fn init_system(mut commands: Commands) {
debug("Running CorePlugin::init_system");
commands.spawn(Camera2dBundle::default());
}
// grid/mod.rs
pub mod components;
pub(crate) mod constants;
mod systems;
use bevy::{
app::{Plugin, Startup},
asset::Assets,
ecs::system::{Commands, ResMut},
log::debug,
math::primitives::Rectangle,
render::{color::Color, mesh::Mesh},
sprite::{ColorMaterial, MaterialMesh2dBundle, Mesh2dHandle},
transform::components::Transform,
};
use crate::grid::systems::{init_grids, paint_grids};
pub(super) struct GridPlugin;
impl Plugin for GridPlugin {
fn build(&self, app: &mut bevy::prelude::App) {
debug!("Initializing GridPlugin...");
app.add_systems(Startup, (init_grids, paint_grids));
}
}
您的问题是两个系统
paint_grid
和init_grid
的组合。
它们都在启动计划中只运行一次,这意味着游戏的第一帧。
// init_grids
//...
commands.spawn(Grid::new(x,y))
// ...
向世界发出命令,在帧末尾插入带有
Grid
组件的实体。但是,这意味着该实体仅从第 2 帧开始可见。
因此 grid_query: Query<&Grid>
在第 1 帧处为空。
最简单的解决方案是将
init_grids
和 pain_grids
合并到单个系统。就目前情况而言,无论如何都不需要两个单独的系统。
另一种方法是在
paint_grids
计划中运行 Update
并查询新添加的 Grid
组件。
// GridPlugin
app.add_systems(Startup, init_grids)
.add_systems(Update, paint_grids)
// paint_grids
fn pain_grids(
grid_query: Query<&Grid, Added<Grid>>,
//...
) {
//...
}
每当将新的网格组件插入到世界中时,都会添加网格实体。您可能会担心这可能会很昂贵,因为我们查询每一帧,但实际上它非常便宜。
我也不会将视觉/网格和
Grid
组件分成两个不同的实体。这样做没有什么理由,并且可能会使同步有点乏味