rts camera

This commit is contained in:
2024-05-05 00:39:27 -04:00
parent ed94f77323
commit 7b6cae39b7
12 changed files with 112 additions and 60 deletions

8
Cargo.lock generated
View File

@@ -1382,13 +1382,6 @@ dependencies = [
"wayland-client",
]
[[package]]
name = "camera_system"
version = "0.1.0"
dependencies = [
"bevy",
]
[[package]]
name = "cc"
version = "1.0.90"
@@ -3223,7 +3216,6 @@ dependencies = [
"bevy",
"bevy-inspector-egui 0.23.4",
"bevy_rapier3d",
"camera_system",
"iyes_perf_ui",
"noise 0.8.2",
"rayon",

View File

@@ -3,8 +3,7 @@ resolver = "2"
members = [
"game/main",
"engine/world_generation",
"game/camera_system"
, "engine/asset_loader"]
"engine/asset_loader"]
# Enable a small amount of optimization in debug mode
[profile.dev]

View File

@@ -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 {
let off = self.to_offset();
if off.x < 0 || off.y < 0 {

View File

@@ -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"

View File

@@ -12,6 +12,5 @@ bevy-inspector-egui = "0.23.4"
iyes_perf_ui = "0.2.3"
noise = "0.8.2"
world_generation ={path="../../engine/world_generation"}
camera_system={path = "../camera_system"}
bevy_rapier3d = { version = "0.25.0", features = [ "simd-stable", "debug-render-3d","parallel" ] }
rayon = "1.10.0"

View File

@@ -1,20 +1,23 @@
use crate::prelude::PhosCamera;
use bevy::core_pipeline::experimental::taa::{TemporalAntiAliasBundle, TemporalAntiAliasPlugin};
use bevy::input::mouse::{MouseMotion, MouseScrollUnit, MouseWheel};
use bevy::pbr::ScreenSpaceAmbientOcclusionBundle;
use bevy::prelude::*;
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;
impl Plugin for PhosCameraPlugin {
fn build(&self, app: &mut App) {
app.register_type::<PhosCamera>();
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);
//Free Cam
//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
.spawn((
Camera3dBundle {
transform: Transform::from_xyz(0., 30., 0.)
.with_rotation(Quat::from_axis_angle(Vec3::Y, (-90 as f32).to_radians())),
..default()
},
PhosCamera {
speed: 100.,
zoom_speed: 20.,
transform: Transform::from_xyz(0., 30., 0.).looking_to(Vec3::Z, Vec3::Y),
..default()
},
PhosCamera::default(),
PhosCameraTargets::default(),
))
.insert(ScreenSpaceAmbientOcclusionBundle::default())
@@ -128,12 +126,14 @@ fn grab_mouse(mut windows: Query<&mut Window>, mouse: Res<ButtonInput<MouseButto
fn rts_camera_system(
mut cam_query: Query<(&mut Transform, &PhosCamera, &mut PhosCameraTargets)>,
mut wheel: EventReader<MouseWheel>,
key: Res<ButtonInput<KeyCode>>,
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_move = Vec3::ZERO;
let mut cam_pos = cam.translation;
if key.pressed(KeyCode::KeyA) {
cam_move.x = 1.;
@@ -147,30 +147,75 @@ fn rts_camera_system(
cam_move.z = -1.;
}
let fwd = cam.forward();
let fwd_quat = Quat::from_rotation_arc(Vec3::Z, fwd.into());
cam_move = fwd_quat.mul_vec3(cam_move.normalize_or_zero()) * cam_cfg.speed * time.delta_seconds();
if key.pressed(KeyCode::ShiftLeft) {
cam_move = cam_move.normalize_or_zero() * cam_cfg.speed * time.delta_seconds() * 2.;
} 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() {
match e.unit {
MouseScrollUnit::Line => cam_targets.height -= e.y * 20.,
MouseScrollUnit::Pixel => cam_targets.height -= e.y,
MouseScrollUnit::Line => scroll += e.y * 5.,
MouseScrollUnit::Pixel => scroll += e.y,
}
}
cam_targets.height = cam_targets.height.clamp(cam_cfg.min_height, cam_cfg.max_height);
cam.translation += cam_move;
cam_targets.height -= scroll;
if cam_targets.height > cam_cfg.max_height {
cam_targets.height = cam_cfg.max_height;
}
fn apply_camera_height(mut cam_query: Query<(&mut Transform, &PhosCamera, &mut PhosCameraTargets)>, time: Res<Time>) {
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;
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;
}
}
}
fn limit_camera_bounds(mut cam_query: Query<(&mut Transform, &CameraBounds)>) {
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 limit_camera_bounds(mut cam_query: Query<(&mut Transform, &CameraBounds)>) {}

View File

@@ -1,6 +1,7 @@
use bevy::prelude::*;
#[derive(Component)]
#[derive(Component, Reflect)]
#[reflect(Component)]
pub struct PhosCamera {
pub min_height: f32,
pub max_height: f32,
@@ -16,9 +17,9 @@ impl Default for PhosCamera {
min_height: 10.,
max_height: 100.,
speed: 20.,
zoom_speed: 20.,
min_angle: 10.,
max_angle: 80.,
zoom_speed: 0.3,
min_angle: (20. as f32).to_radians(),
max_angle: 1.,
}
}
}
@@ -26,6 +27,9 @@ impl Default for PhosCamera {
#[derive(Component, Default)]
pub struct PhosCameraTargets {
pub height: f32,
pub last_height: f32,
pub anim_time: f32,
pub rotate_time: f32,
}
#[derive(Component, Default)]

View File

@@ -0,0 +1,2 @@
pub mod camera_plugin;
pub mod components;

View File

@@ -3,13 +3,14 @@ use bevy::prelude::*;
use bevy::render::texture::{ImageAddressMode, ImageFilterMode, ImageSamplerDescriptor};
use bevy::window::PresentMode;
use bevy_inspector_egui::quick::WorldInspectorPlugin;
use phos::PhosGamePlugin;
mod camera_system;
mod map_init;
mod phos;
mod prelude;
mod shader_extensions;
mod utlis;
use phos::PhosGamePlugin;
fn main() {
App::new()

View File

@@ -1,7 +1,6 @@
use bevy::{asset::LoadState, pbr::ExtendedMaterial, prelude::*};
use bevy_inspector_egui::quick::ResourceInspectorPlugin;
use bevy_rapier3d::geometry::{Collider, TriMeshFlags};
use camera_system::prelude::{CameraBounds, PhosCamera};
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
use world_generation::{
biome_painter::*,
@@ -15,6 +14,7 @@ use world_generation::{
};
use crate::{
camera_system::components::*,
prelude::{ChunkAtlas, PhosChunk, PhosMap},
shader_extensions::chunk_material::ChunkMaterial,
utlis::render_distance_system::RenderDistanceVisibility,
@@ -235,7 +235,11 @@ fn spawn_map(
commands.spawn((PbrBundle {
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 {
base_color: Color::AQUAMARINE.with_a(0.5),
alpha_mode: AlphaMode::Blend,

View File

@@ -1,3 +1,5 @@
use crate::camera_system::camera_plugin::PhosCameraPlugin;
use crate::camera_system::components::PhosCamera;
use crate::map_init::MapInitPlugin;
use crate::prelude::*;
use crate::shader_extensions::chunk_material::ChunkMaterial;
@@ -10,8 +12,6 @@ use bevy::{
use bevy_rapier3d::dynamics::{Ccd, RigidBody, Velocity};
use bevy_rapier3d::geometry::Collider;
use bevy_rapier3d::plugin::{NoUserData, RapierPhysicsPlugin};
use camera_system::prelude::PhosCamera;
use camera_system::PhosCameraPlugin;
use iyes_perf_ui::prelude::*;
use world_generation::biome_painter::BiomePainterPlugin;
use world_generation::tile_manager::TileAssetPlugin;

View File

@@ -1,5 +1,6 @@
use bevy::prelude::*;
use camera_system::prelude::PhosCamera;
use crate::camera_system::components::PhosCamera;
pub struct RenderDistancePlugin;