rts camera
This commit is contained in:
8
Cargo.lock
generated
8
Cargo.lock
generated
@@ -1382,13 +1382,6 @@ dependencies = [
|
|||||||
"wayland-client",
|
"wayland-client",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "camera_system"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"bevy",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.90"
|
version = "1.0.90"
|
||||||
@@ -3223,7 +3216,6 @@ dependencies = [
|
|||||||
"bevy",
|
"bevy",
|
||||||
"bevy-inspector-egui 0.23.4",
|
"bevy-inspector-egui 0.23.4",
|
||||||
"bevy_rapier3d",
|
"bevy_rapier3d",
|
||||||
"camera_system",
|
|
||||||
"iyes_perf_ui",
|
"iyes_perf_ui",
|
||||||
"noise 0.8.2",
|
"noise 0.8.2",
|
||||||
"rayon",
|
"rayon",
|
||||||
|
|||||||
@@ -3,8 +3,7 @@ resolver = "2"
|
|||||||
members = [
|
members = [
|
||||||
"game/main",
|
"game/main",
|
||||||
"engine/world_generation",
|
"engine/world_generation",
|
||||||
"game/camera_system"
|
"engine/asset_loader"]
|
||||||
, "engine/asset_loader"]
|
|
||||||
|
|
||||||
# Enable a small amount of optimization in debug mode
|
# Enable a small amount of optimization in debug mode
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
|
|||||||
@@ -86,6 +86,20 @@ impl HexCoord {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_world_pos(world_pos: Vec3) -> Self {
|
||||||
|
let offset = world_pos.z / (OUTER_RADIUS * 3.);
|
||||||
|
let mut x = world_pos.x / (INNER_RADIUS * 2.);
|
||||||
|
let mut z = -x;
|
||||||
|
z -= offset;
|
||||||
|
x -= offset;
|
||||||
|
|
||||||
|
let i_x = x.round() as i32;
|
||||||
|
let i_z = (-x - z).round() as i32;
|
||||||
|
let offset_pos = IVec2::new(i_x + i_z / 2, i_z);
|
||||||
|
|
||||||
|
return Self::from_offset(offset_pos);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_in_bounds(&self, map_height: usize, map_width: usize) -> bool {
|
pub fn is_in_bounds(&self, map_height: usize, map_width: usize) -> bool {
|
||||||
let off = self.to_offset();
|
let off = self.to_offset();
|
||||||
if off.x < 0 || off.y < 0 {
|
if off.x < 0 || off.y < 0 {
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "camera_system"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
bevy = "0.13.1"
|
|
||||||
@@ -12,6 +12,5 @@ bevy-inspector-egui = "0.23.4"
|
|||||||
iyes_perf_ui = "0.2.3"
|
iyes_perf_ui = "0.2.3"
|
||||||
noise = "0.8.2"
|
noise = "0.8.2"
|
||||||
world_generation ={path="../../engine/world_generation"}
|
world_generation ={path="../../engine/world_generation"}
|
||||||
camera_system={path = "../camera_system"}
|
|
||||||
bevy_rapier3d = { version = "0.25.0", features = [ "simd-stable", "debug-render-3d","parallel" ] }
|
bevy_rapier3d = { version = "0.25.0", features = [ "simd-stable", "debug-render-3d","parallel" ] }
|
||||||
rayon = "1.10.0"
|
rayon = "1.10.0"
|
||||||
|
|||||||
@@ -1,20 +1,23 @@
|
|||||||
use crate::prelude::PhosCamera;
|
|
||||||
use bevy::core_pipeline::experimental::taa::{TemporalAntiAliasBundle, TemporalAntiAliasPlugin};
|
use bevy::core_pipeline::experimental::taa::{TemporalAntiAliasBundle, TemporalAntiAliasPlugin};
|
||||||
use bevy::input::mouse::{MouseMotion, MouseScrollUnit, MouseWheel};
|
use bevy::input::mouse::{MouseMotion, MouseScrollUnit, MouseWheel};
|
||||||
use bevy::pbr::ScreenSpaceAmbientOcclusionBundle;
|
use bevy::pbr::ScreenSpaceAmbientOcclusionBundle;
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy::window::CursorGrabMode;
|
use bevy::window::CursorGrabMode;
|
||||||
use prelude::{CameraBounds, PhosCameraTargets};
|
use bevy_rapier3d::plugin::RapierContext;
|
||||||
|
use world_generation::hex_utils::HexCoord;
|
||||||
|
use world_generation::prelude::Map;
|
||||||
|
|
||||||
pub mod prelude;
|
use super::components::*;
|
||||||
|
|
||||||
pub struct PhosCameraPlugin;
|
pub struct PhosCameraPlugin;
|
||||||
|
|
||||||
impl Plugin for PhosCameraPlugin {
|
impl Plugin for PhosCameraPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
|
app.register_type::<PhosCamera>();
|
||||||
|
|
||||||
app.add_systems(PreStartup, setup);
|
app.add_systems(PreStartup, setup);
|
||||||
|
|
||||||
app.add_systems(Update, (rts_camera_system, apply_camera_height).chain());
|
app.add_systems(Update, rts_camera_system);
|
||||||
app.add_systems(PostUpdate, limit_camera_bounds);
|
app.add_systems(PostUpdate, limit_camera_bounds);
|
||||||
//Free Cam
|
//Free Cam
|
||||||
//app.add_systems(Update, (grab_mouse, (update_camera, update_camera_mouse).chain()));
|
//app.add_systems(Update, (grab_mouse, (update_camera, update_camera_mouse).chain()));
|
||||||
@@ -27,15 +30,10 @@ fn setup(mut commands: Commands, mut msaa: ResMut<Msaa>) {
|
|||||||
commands
|
commands
|
||||||
.spawn((
|
.spawn((
|
||||||
Camera3dBundle {
|
Camera3dBundle {
|
||||||
transform: Transform::from_xyz(0., 30., 0.)
|
transform: Transform::from_xyz(0., 30., 0.).looking_to(Vec3::Z, Vec3::Y),
|
||||||
.with_rotation(Quat::from_axis_angle(Vec3::Y, (-90 as f32).to_radians())),
|
|
||||||
..default()
|
|
||||||
},
|
|
||||||
PhosCamera {
|
|
||||||
speed: 100.,
|
|
||||||
zoom_speed: 20.,
|
|
||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
|
PhosCamera::default(),
|
||||||
PhosCameraTargets::default(),
|
PhosCameraTargets::default(),
|
||||||
))
|
))
|
||||||
.insert(ScreenSpaceAmbientOcclusionBundle::default())
|
.insert(ScreenSpaceAmbientOcclusionBundle::default())
|
||||||
@@ -128,12 +126,14 @@ fn grab_mouse(mut windows: Query<&mut Window>, mouse: Res<ButtonInput<MouseButto
|
|||||||
|
|
||||||
fn rts_camera_system(
|
fn rts_camera_system(
|
||||||
mut cam_query: Query<(&mut Transform, &PhosCamera, &mut PhosCameraTargets)>,
|
mut cam_query: Query<(&mut Transform, &PhosCamera, &mut PhosCameraTargets)>,
|
||||||
|
mut wheel: EventReader<MouseWheel>,
|
||||||
key: Res<ButtonInput<KeyCode>>,
|
key: Res<ButtonInput<KeyCode>>,
|
||||||
time: Res<Time>,
|
time: Res<Time>,
|
||||||
mut wheel: EventReader<MouseWheel>,
|
heightmap: Res<Map>,
|
||||||
) {
|
) {
|
||||||
let (mut cam, cam_cfg, mut cam_targets) = cam_query.single_mut();
|
let (mut cam, cam_cfg, mut cam_targets) = cam_query.single_mut();
|
||||||
let mut cam_move = Vec3::ZERO;
|
let mut cam_move = Vec3::ZERO;
|
||||||
|
let mut cam_pos = cam.translation;
|
||||||
|
|
||||||
if key.pressed(KeyCode::KeyA) {
|
if key.pressed(KeyCode::KeyA) {
|
||||||
cam_move.x = 1.;
|
cam_move.x = 1.;
|
||||||
@@ -147,30 +147,75 @@ fn rts_camera_system(
|
|||||||
cam_move.z = -1.;
|
cam_move.z = -1.;
|
||||||
}
|
}
|
||||||
|
|
||||||
let fwd = cam.forward();
|
if key.pressed(KeyCode::ShiftLeft) {
|
||||||
let fwd_quat = Quat::from_rotation_arc(Vec3::Z, fwd.into());
|
cam_move = cam_move.normalize_or_zero() * cam_cfg.speed * time.delta_seconds() * 2.;
|
||||||
cam_move = fwd_quat.mul_vec3(cam_move.normalize_or_zero()) * cam_cfg.speed * time.delta_seconds();
|
} else {
|
||||||
|
cam_move = cam_move.normalize_or_zero() * cam_cfg.speed * time.delta_seconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
cam_pos -= cam_move;
|
||||||
|
|
||||||
|
let mut scroll = 0.0;
|
||||||
for e in wheel.read() {
|
for e in wheel.read() {
|
||||||
match e.unit {
|
match e.unit {
|
||||||
MouseScrollUnit::Line => cam_targets.height -= e.y * 20.,
|
MouseScrollUnit::Line => scroll += e.y * 5.,
|
||||||
MouseScrollUnit::Pixel => cam_targets.height -= e.y,
|
MouseScrollUnit::Pixel => scroll += e.y,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cam_targets.height = cam_targets.height.clamp(cam_cfg.min_height, cam_cfg.max_height);
|
cam_targets.height -= scroll;
|
||||||
|
if cam_targets.height > cam_cfg.max_height {
|
||||||
|
cam_targets.height = cam_cfg.max_height;
|
||||||
|
}
|
||||||
|
|
||||||
cam.translation += cam_move;
|
let tile_under = HexCoord::from_world_pos(cam.translation);
|
||||||
|
let neighbors = heightmap.get_neighbors(&tile_under);
|
||||||
|
let mut ground_height = heightmap.sample_height(&tile_under);
|
||||||
|
for n in neighbors {
|
||||||
|
if let Some(h) = n {
|
||||||
|
if h > ground_height {
|
||||||
|
ground_height = h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let min_height = ground_height + cam_cfg.min_height;
|
||||||
|
|
||||||
|
if min_height != cam_targets.last_height {
|
||||||
|
cam_targets.last_height = min_height;
|
||||||
|
cam_targets.anim_time = 0.;
|
||||||
|
cam_targets.rotate_time = 0.;
|
||||||
|
}
|
||||||
|
|
||||||
|
if scroll != 0. {
|
||||||
|
cam_targets.anim_time = 0.;
|
||||||
|
cam_targets.rotate_time = 0.;
|
||||||
|
if cam_targets.height < min_height {
|
||||||
|
cam_targets.height = min_height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let desired_height = if cam_targets.height < min_height {
|
||||||
|
min_height
|
||||||
|
} else {
|
||||||
|
cam_targets.height
|
||||||
|
};
|
||||||
|
if cam_targets.anim_time < 1. {
|
||||||
|
cam_targets.anim_time += time.delta_seconds() * cam_cfg.zoom_speed;
|
||||||
|
cam_targets.anim_time = cam_targets.anim_time.min(1.);
|
||||||
|
}
|
||||||
|
cam_pos.y = f32::lerp(cam_pos.y, desired_height, cam_targets.anim_time);
|
||||||
|
let t = cam_pos.y.remap(cam_cfg.min_height, cam_cfg.max_height, 0., 1.);
|
||||||
|
|
||||||
|
if cam_targets.rotate_time < 1. {
|
||||||
|
cam_targets.rotate_time += time.delta_seconds();
|
||||||
|
cam_targets.rotate_time = cam_targets.rotate_time.min(1.);
|
||||||
|
}
|
||||||
|
let angle = cam_cfg.min_angle.lerp(cam_cfg.max_angle, t);
|
||||||
|
let rot = Quat::from_axis_angle(Vec3::X, -angle);
|
||||||
|
cam.rotation = rot;
|
||||||
|
|
||||||
|
cam.translation = cam_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_camera_height(mut cam_query: Query<(&mut Transform, &PhosCamera, &mut PhosCameraTargets)>, time: Res<Time>) {
|
fn limit_camera_bounds(mut cam_query: Query<(&mut Transform, &CameraBounds)>) {}
|
||||||
let (mut cam_t, cam_cfg, targets) = cam_query.single_mut();
|
|
||||||
|
|
||||||
let movement = (cam_t.translation.y - targets.height) * time.delta_seconds();
|
|
||||||
|
|
||||||
cam_t.translation.y -= movement;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn limit_camera_bounds(mut cam_query: Query<(&mut Transform, &CameraBounds)>) {
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component, Reflect)]
|
||||||
|
#[reflect(Component)]
|
||||||
pub struct PhosCamera {
|
pub struct PhosCamera {
|
||||||
pub min_height: f32,
|
pub min_height: f32,
|
||||||
pub max_height: f32,
|
pub max_height: f32,
|
||||||
@@ -16,9 +17,9 @@ impl Default for PhosCamera {
|
|||||||
min_height: 10.,
|
min_height: 10.,
|
||||||
max_height: 100.,
|
max_height: 100.,
|
||||||
speed: 20.,
|
speed: 20.,
|
||||||
zoom_speed: 20.,
|
zoom_speed: 0.3,
|
||||||
min_angle: 10.,
|
min_angle: (20. as f32).to_radians(),
|
||||||
max_angle: 80.,
|
max_angle: 1.,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -26,6 +27,9 @@ impl Default for PhosCamera {
|
|||||||
#[derive(Component, Default)]
|
#[derive(Component, Default)]
|
||||||
pub struct PhosCameraTargets {
|
pub struct PhosCameraTargets {
|
||||||
pub height: f32,
|
pub height: f32,
|
||||||
|
pub last_height: f32,
|
||||||
|
pub anim_time: f32,
|
||||||
|
pub rotate_time: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Component, Default)]
|
#[derive(Component, Default)]
|
||||||
2
game/main/src/camera_system/mod.rs
Normal file
2
game/main/src/camera_system/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
pub mod camera_plugin;
|
||||||
|
pub mod components;
|
||||||
@@ -3,13 +3,14 @@ use bevy::prelude::*;
|
|||||||
use bevy::render::texture::{ImageAddressMode, ImageFilterMode, ImageSamplerDescriptor};
|
use bevy::render::texture::{ImageAddressMode, ImageFilterMode, ImageSamplerDescriptor};
|
||||||
use bevy::window::PresentMode;
|
use bevy::window::PresentMode;
|
||||||
use bevy_inspector_egui::quick::WorldInspectorPlugin;
|
use bevy_inspector_egui::quick::WorldInspectorPlugin;
|
||||||
|
use phos::PhosGamePlugin;
|
||||||
|
|
||||||
|
mod camera_system;
|
||||||
mod map_init;
|
mod map_init;
|
||||||
mod phos;
|
mod phos;
|
||||||
mod prelude;
|
mod prelude;
|
||||||
mod shader_extensions;
|
mod shader_extensions;
|
||||||
mod utlis;
|
mod utlis;
|
||||||
use phos::PhosGamePlugin;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
use bevy::{asset::LoadState, pbr::ExtendedMaterial, prelude::*};
|
use bevy::{asset::LoadState, pbr::ExtendedMaterial, prelude::*};
|
||||||
use bevy_inspector_egui::quick::ResourceInspectorPlugin;
|
use bevy_inspector_egui::quick::ResourceInspectorPlugin;
|
||||||
use bevy_rapier3d::geometry::{Collider, TriMeshFlags};
|
use bevy_rapier3d::geometry::{Collider, TriMeshFlags};
|
||||||
use camera_system::prelude::{CameraBounds, PhosCamera};
|
|
||||||
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
|
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
|
||||||
use world_generation::{
|
use world_generation::{
|
||||||
biome_painter::*,
|
biome_painter::*,
|
||||||
@@ -15,6 +14,7 @@ use world_generation::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
camera_system::components::*,
|
||||||
prelude::{ChunkAtlas, PhosChunk, PhosMap},
|
prelude::{ChunkAtlas, PhosChunk, PhosMap},
|
||||||
shader_extensions::chunk_material::ChunkMaterial,
|
shader_extensions::chunk_material::ChunkMaterial,
|
||||||
utlis::render_distance_system::RenderDistanceVisibility,
|
utlis::render_distance_system::RenderDistanceVisibility,
|
||||||
@@ -235,7 +235,11 @@ fn spawn_map(
|
|||||||
|
|
||||||
commands.spawn((PbrBundle {
|
commands.spawn((PbrBundle {
|
||||||
transform: Transform::from_translation(heightmap.get_center()),
|
transform: Transform::from_translation(heightmap.get_center()),
|
||||||
mesh: meshes.add(Plane3d::default().mesh().size(heightmap.get_world_width(), heightmap.get_world_height())),
|
mesh: meshes.add(
|
||||||
|
Plane3d::default()
|
||||||
|
.mesh()
|
||||||
|
.size(heightmap.get_world_width(), heightmap.get_world_height()),
|
||||||
|
),
|
||||||
material: standard_materials.add(StandardMaterial {
|
material: standard_materials.add(StandardMaterial {
|
||||||
base_color: Color::AQUAMARINE.with_a(0.5),
|
base_color: Color::AQUAMARINE.with_a(0.5),
|
||||||
alpha_mode: AlphaMode::Blend,
|
alpha_mode: AlphaMode::Blend,
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use crate::camera_system::camera_plugin::PhosCameraPlugin;
|
||||||
|
use crate::camera_system::components::PhosCamera;
|
||||||
use crate::map_init::MapInitPlugin;
|
use crate::map_init::MapInitPlugin;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::shader_extensions::chunk_material::ChunkMaterial;
|
use crate::shader_extensions::chunk_material::ChunkMaterial;
|
||||||
@@ -10,8 +12,6 @@ use bevy::{
|
|||||||
use bevy_rapier3d::dynamics::{Ccd, RigidBody, Velocity};
|
use bevy_rapier3d::dynamics::{Ccd, RigidBody, Velocity};
|
||||||
use bevy_rapier3d::geometry::Collider;
|
use bevy_rapier3d::geometry::Collider;
|
||||||
use bevy_rapier3d::plugin::{NoUserData, RapierPhysicsPlugin};
|
use bevy_rapier3d::plugin::{NoUserData, RapierPhysicsPlugin};
|
||||||
use camera_system::prelude::PhosCamera;
|
|
||||||
use camera_system::PhosCameraPlugin;
|
|
||||||
use iyes_perf_ui::prelude::*;
|
use iyes_perf_ui::prelude::*;
|
||||||
use world_generation::biome_painter::BiomePainterPlugin;
|
use world_generation::biome_painter::BiomePainterPlugin;
|
||||||
use world_generation::tile_manager::TileAssetPlugin;
|
use world_generation::tile_manager::TileAssetPlugin;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use camera_system::prelude::PhosCamera;
|
|
||||||
|
use crate::camera_system::components::PhosCamera;
|
||||||
|
|
||||||
pub struct RenderDistancePlugin;
|
pub struct RenderDistancePlugin;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user