Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

higher dezoom + m hotkey to load another map #223

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions TUTORIAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ rotate the camera around its focus point on the terrain.
# Hotkeys

* Press `Esc` — cancel current action.
* Key `M` — Cycle through default maps

# Building Construction

Expand Down
3 changes: 3 additions & 0 deletions assets/de_map_test.tar
Git LFS file not shown
4 changes: 2 additions & 2 deletions assets/shaders/terrain.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ fn draw_circle(
radius: f32,
) -> vec4<f32> {
let distance: f32 = distance(uv, center);
if distance <= (radius + SHAPE_THICKNESS) && radius <= distance {
if distance <= (radius + SHAPE_THICKNESS) && radius <= distance {
return mix_colors(base, SHAPE_COLOR);
}
return base;
Expand Down Expand Up @@ -103,7 +103,7 @@ fn nearest(uv: vec2<f32>) -> u32 {

let axis = next.depth % 2u;
let diff = uv[axis] - node.location[axis];

var close = 2u * next.index + 2u;
var away = 2u * next.index + 1u;

Expand Down
21 changes: 15 additions & 6 deletions crates/camera/src/camera.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,18 @@ const CAMERA_HORIZONTAL_SPEED: InverseSecond = Quantity::new_unchecked(2.0);
/// Minimum camera distance from terrain achievable with zooming along.
const MIN_CAMERA_DISTANCE: Metre = Quantity::new_unchecked(20.);
/// Maximum camera distance from terrain achievable with zooming alone.
const MAX_CAMERA_DISTANCE: Metre = Quantity::new_unchecked(100.);
const MAX_CAMERA_DISTANCE: Metre = Quantity::new_unchecked(300.);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally think those are better defaults (for now at least), as the default map is way too big and needs a long scroll to see other units

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, at this point in time this change makes sense.

A bit of a context:

  • In the long run, I would like to implement a custom LOD so zooming out a lot is feasible from performance perspective.

    • Until this happens, it might be necessary to change this back to a lower value after we plug in better unit models (with possibly higher triangle counts etc.).
  • The appearance / UI has to change on high camera distances: drawing simple colored squares instead of true 3D models, not displaying health bars and selection circles etc. More info here LOD, "cartographic rendering", split screen & full-screen minimap #153.

  • Implementing some kind of a mini map (displaying at least all units & buildings & camera) is high on my priority list. That would solve most of the issue you mention (long scroll -> single click on the mini map, getting disoriented -> looking where you are looking at at the mini map).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is related #68.

/// Maximum camera distance from terrain achievable with zooming alone.
const DEFAULT_CAMERA_DISTANCE: Metre = Quantity::new_unchecked(
(MIN_CAMERA_DISTANCE.inner() + (MAX_CAMERA_DISTANCE.inner() - MIN_CAMERA_DISTANCE.inner()))
* 0.4,
);
/// Minimum temporary distance from terrain. Forward/backward camera motion is
/// smooth within this range. Step adjustment is applied outside of this range.
const HARD_MIN_CAMERA_DISTANCE: Metre = Quantity::new_unchecked(16.);
/// Maximum temporary distance from terrain. Forward/backward camera motion is
/// smooth within this range. Step adjustment is applied outside of this range.
const HARD_MAX_CAMERA_DISTANCE: Metre = Quantity::new_unchecked(110.);
const HARD_MAX_CAMERA_DISTANCE: Metre = Quantity::new_unchecked(310.);
/// Camera moves along forward axis (zooming) at speed `distance *
/// CAMERA_VERTICAL_SPEED`.
const CAMERA_VERTICAL_SPEED: InverseSecond = Quantity::new_unchecked(2.0);
Expand Down Expand Up @@ -209,19 +214,23 @@ impl DesiredPoW {
}
}

fn setup(mut commands: Commands) {
fn setup(mut commands: Commands, camera_query: Query<Entity, With<Camera3d>>) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will have to thing about it a bit more, but my current thought is that the whole map cycling & game setup has to be done differently:

  • Proper clean up after GameState::Playing is existed has to be implemented.
  • Map selection should be done via main menu. It might be very simplistic at this point (a button for each available map?).
  • Generally: once you enter a game (GameState::Playing) you cannot change its configuration (like in most RTS games). You have to quit the game first and then start a new game.

My second point is of highest priority IMO.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related #34.

commands.insert_resource(HorizontalMovement::default());
commands.insert_resource(DesiredPoW {
distance: MAX_CAMERA_DISTANCE,
distance: DEFAULT_CAMERA_DISTANCE,
off_nadir: Radian::ZERO,
azimuth: Radian::ZERO,
});
commands.insert_resource(CameraFocus {
point: Vec3::ZERO,
distance: MAX_CAMERA_DISTANCE,
distance: DEFAULT_CAMERA_DISTANCE,
});
if let Ok(cam_entity) = camera_query.get_single() {
commands.entity(cam_entity).despawn();
}

commands.spawn_bundle(Camera3dBundle {
transform: Transform::from_xyz(0.0, MAX_CAMERA_DISTANCE.into(), 0.0)
transform: Transform::from_xyz(0.0, DEFAULT_CAMERA_DISTANCE.into(), 0.0)
.looking_at(Vec3::ZERO, -Vec3::Z),
..Default::default()
});
Expand Down
2 changes: 2 additions & 0 deletions crates/loader/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ use bevy::{app::PluginGroupBuilder, prelude::PluginGroup};
use map::MapLoaderPlugin;

mod map;
mod map_select;

pub struct LoaderPluginGroup;

impl PluginGroup for LoaderPluginGroup {
fn build(&mut self, group: &mut PluginGroupBuilder) {
group.add(MapLoaderPlugin);
group.add(map_select::MapSelectPlugin);
}
}
30 changes: 21 additions & 9 deletions crates/loader/src/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ impl Plugin for MapLoaderPlugin {

struct MapLoadingTask(Task<Result<Map, MapLoadingError>>);

#[derive(Component, Reflect)]
pub struct RemoveBeforeLoad;

fn load_map_system(mut commands: Commands, game_config: Res<GameConfig>) {
let map_path = if game_config.map_path().is_relative() {
asset_path(game_config.map_path())
Expand All @@ -48,6 +51,7 @@ fn spawn_map(
task: Option<ResMut<MapLoadingTask>>,
mut move_focus_events: EventWriter<MoveFocusEvent>,
game_config: Res<GameConfig>,
entities_to_remove: Query<Entity, Or<(With<Handle<Scene>>, With<RemoveBeforeLoad>)>>,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we might want a better strategy for removing stuff between loading states, I would err on the side of tagging everything that should not be removed (as I guess there should be a less amount of entities) rather than the opposite, but that was easier to implement.

I might have missed edge cases like the selection rectangle, or projectiles ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that the desired solution to this problem is to add on exist system(s) to every plugin so that the responsibility is moved to where the entities / resources were inserted in the first place.

This all thing might not be needed to add map selection (see the other comment): I would just implement simple main menu where you click on a button with a map name to start the game. You would have to restart the game to select another map to decouple proper system clenaups with map selection.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related #135.

) -> Progress {
let mut task = match task {
Some(task) => task,
Expand All @@ -59,6 +63,10 @@ fn spawn_map(
None => return false.into(),
};

info!("Map loaded, removing old one");
for to_remove in entities_to_remove.iter() {
commands.entity(to_remove).despawn_recursive();
}
info!("Map loaded, spawning");
commands.remove_resource::<MapLoadingTask>();

Expand Down Expand Up @@ -91,7 +99,9 @@ fn spawn_map(
}

setup_light(&mut commands);
commands.spawn_bundle(TerrainBundle::flat(map.bounds()));
commands
.spawn_bundle(TerrainBundle::flat(map.bounds()))
.insert(RemoveBeforeLoad);

for object in map.objects() {
let mut entity_commands = commands.spawn();
Expand Down Expand Up @@ -120,13 +130,15 @@ fn setup_light(commands: &mut Commands) {

let mut transform = Transform::identity();
transform.look_at(Vec3::new(1., -1., 0.), Vec3::new(1., 1., 0.));
commands.spawn_bundle(DirectionalLightBundle {
directional_light: DirectionalLight {
color: Color::WHITE,
illuminance: 30000.,
commands
.spawn_bundle(DirectionalLightBundle {
directional_light: DirectionalLight {
color: Color::WHITE,
illuminance: 30000.,
..Default::default()
},
transform,
..Default::default()
},
transform,
..Default::default()
});
})
.insert(RemoveBeforeLoad);
}
39 changes: 39 additions & 0 deletions crates/loader/src/map_select.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use bevy::prelude::*;
use de_core::{gconfig::GameConfig, player::Player, state::GameState};
use iyes_loopless::{prelude::IntoConditionalSystem, state::NextState};

pub struct MapSelectPlugin;

impl Plugin for MapSelectPlugin {
fn build(&self, app: &mut App) {
app.init_resource::<MapList>();
app.add_system(cycle_map.run_in_state(GameState::Playing));
}
}

pub struct MapList {
pub maps: Vec<String>,
pub current_id: usize,
}

impl Default for MapList {
fn default() -> Self {
Self {
maps: vec!["map.tar".into(), "de_map_test.tar".into()],
current_id: 0,
}
}
}

fn cycle_map(
mut commands: Commands,
mut config: ResMut<GameConfig>,
mut map_list: ResMut<MapList>,
kbd: Res<Input<KeyCode>>,
) {
if kbd.just_pressed(KeyCode::M) {
map_list.current_id = (map_list.current_id + 1) % map_list.maps.len();
*config = GameConfig::new(&map_list.maps[map_list.current_id], Player::Player1);
commands.insert_resource(NextState(GameState::Loading));
}
}
4 changes: 4 additions & 0 deletions crates/uom/src/quantity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ impl<const U: Unit> Quantity<U> {
panic_on_invalid(self.0);
Self::new(self.0.abs())
}

pub const fn inner(&self) -> f32 {
self.0
}
}

impl<const U: Unit> Clone for Quantity<U> {
Expand Down