feat: debug terrain painting
parent
2bdc5182a5
commit
4968e5a802
|
|
@ -13,6 +13,7 @@ pub struct GameCameraPlugin;
|
|||
impl Plugin for GameCameraPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.register_inspectable::<CameraFollow>()
|
||||
.register_type::<GameCamera>()
|
||||
.add_startup_system(camera_setup)
|
||||
.add_system_to_stage(CoreStage::PostUpdate, camera_system);
|
||||
}
|
||||
|
|
@ -31,6 +32,10 @@ impl Default for FollowMovement {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Component, Reflect, Inspectable)]
|
||||
#[reflect(Component)]
|
||||
pub struct GameCamera;
|
||||
|
||||
#[derive(Default, Component, Reflect, Inspectable)]
|
||||
#[reflect(Component)]
|
||||
pub struct CameraFollow {
|
||||
|
|
@ -55,6 +60,7 @@ fn camera_setup(mut commands: Commands) {
|
|||
},
|
||||
..default()
|
||||
},
|
||||
GameCamera,
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,10 @@ use std::collections::{
|
|||
HashMap,
|
||||
};
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy::{
|
||||
prelude::*,
|
||||
render::{camera::RenderTarget, view::window},
|
||||
};
|
||||
use bevy_prototype_debug_lines::DebugLines;
|
||||
|
||||
mod chunk2d;
|
||||
|
|
@ -14,7 +17,10 @@ pub use chunk2d::*;
|
|||
pub use terrain_gen2d::*;
|
||||
pub use texel2d::*;
|
||||
|
||||
use crate::util::{math::*, Vector2I};
|
||||
use crate::{
|
||||
game::camera::GameCamera,
|
||||
util::{math::*, Vector2I},
|
||||
};
|
||||
|
||||
pub struct Terrain2DPlugin;
|
||||
|
||||
|
|
@ -23,6 +29,7 @@ impl Plugin for Terrain2DPlugin {
|
|||
app.register_type::<TerrainChunk2D>()
|
||||
.insert_resource(Terrain2D::new())
|
||||
.add_event::<TerrainEvent2D>()
|
||||
.add_system(debug_painter)
|
||||
.add_system_to_stage(
|
||||
CoreStage::PostUpdate,
|
||||
dirty_rect_visualizer.before(emit_terrain_events),
|
||||
|
|
@ -34,6 +41,70 @@ impl Plugin for Terrain2DPlugin {
|
|||
}
|
||||
}
|
||||
|
||||
fn debug_painter(
|
||||
mut terrain: ResMut<Terrain2D>,
|
||||
windows: Res<Windows>,
|
||||
input: Res<Input<MouseButton>>,
|
||||
camera_query: Query<(&Camera, &GlobalTransform), With<GameCamera>>,
|
||||
) {
|
||||
if !input.pressed(MouseButton::Left) && !input.pressed(MouseButton::Right) {
|
||||
return;
|
||||
}
|
||||
|
||||
// REM: Dirty and hopefully temporary
|
||||
// https://bevy-cheatbook.github.io/cookbook/cursor2world.html#2d-games
|
||||
// get the camera info and transform
|
||||
// assuming there is exactly one main camera entity, so query::single() is OK
|
||||
let (camera, camera_transform) = camera_query.single();
|
||||
|
||||
// get the window that the camera is displaying to (or the primary window)
|
||||
let window = if let RenderTarget::Window(id) = camera.target {
|
||||
windows.get(id).unwrap()
|
||||
} else {
|
||||
windows.get_primary().unwrap()
|
||||
};
|
||||
|
||||
// check if the cursor is inside the window and get its position
|
||||
let world_pos = if let Some(screen_pos) = window.cursor_position() {
|
||||
// get the size of the window
|
||||
let window_size = Vec2::new(window.width() as f32, window.height() as f32);
|
||||
|
||||
// convert screen position [0..resolution] to ndc [-1..1] (gpu coordinates)
|
||||
let ndc = (screen_pos / window_size) * 2.0 - Vec2::ONE;
|
||||
|
||||
// matrix for undoing the projection and camera transform
|
||||
let ndc_to_world = camera_transform.compute_matrix() * camera.projection_matrix().inverse();
|
||||
|
||||
// use it to convert ndc to world-space coordinates
|
||||
let world_pos = ndc_to_world.project_point3(ndc.extend(-1.0));
|
||||
|
||||
// reduce it to a 2D value
|
||||
world_pos.truncate()
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
||||
let origin = Vector2I::from(world_pos);
|
||||
let radius: i32 = 12;
|
||||
let id = match (
|
||||
input.pressed(MouseButton::Left),
|
||||
input.pressed(MouseButton::Right),
|
||||
) {
|
||||
(true, false) => 1,
|
||||
(_, _) => 0,
|
||||
};
|
||||
|
||||
for y in origin.y - (radius - 1)..origin.y + radius {
|
||||
for x in origin.x - (radius - 1)..origin.x + radius {
|
||||
let dx = (x - origin.x).abs();
|
||||
let dy = (y - origin.y).abs();
|
||||
if dx * dx + dy * dy <= (radius - 1) * (radius - 1) {
|
||||
terrain.set_texel(&Vector2I { x, y }, id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Visualize dirty rects
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -553,7 +553,8 @@ pub fn chunk_collision_sync(
|
|||
(With<TerrainChunkCollisionSync2D>, Changed<TerrainChunk2D>),
|
||||
>,
|
||||
chunk_query: Query<(Entity, &TerrainChunk2D), With<TerrainChunkCollisionSync2D>>,
|
||||
child_collider_query: Query<&Children, With<Collider>>,
|
||||
child_query: Query<&Children>,
|
||||
collider_query: Query<&Collider>,
|
||||
) {
|
||||
let mut updated_chunks = vec![];
|
||||
|
||||
|
|
@ -585,9 +586,11 @@ pub fn chunk_collision_sync(
|
|||
|
||||
for (entity, chunk) in updated_chunks.iter() {
|
||||
// Remove old colliders
|
||||
for children in child_collider_query.get(*entity) {
|
||||
for children in child_query.get(*entity) {
|
||||
for child in children {
|
||||
commands.entity(*child).despawn_recursive()
|
||||
if let Ok(_) = collider_query.get(*child) {
|
||||
commands.entity(*child).despawn_recursive()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,15 @@ impl Vector2I {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Vec2> for Vector2I {
|
||||
fn from(vec: Vec2) -> Self {
|
||||
Self {
|
||||
x: vec.x as i32,
|
||||
y: vec.y as i32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vector2I> for Vec2 {
|
||||
fn from(vec: Vector2I) -> Self {
|
||||
Vec2 {
|
||||
|
|
|
|||
Loading…
Reference in New Issue