Skip to content

Commit 4a656f9

Browse files
authored
add Camera (#66)
* add camera * buttons on top * buttons on top * buttons on top * buttons on top * buttons on top
1 parent 5eb4bce commit 4a656f9

10 files changed

+199
-147
lines changed

client/src/advance_ui.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use server::resource_pile::AdvancePaymentOptions;
1515
use server::status_phase::{StatusPhaseAction, StatusPhaseState};
1616

1717
use crate::client_state::{ActiveDialog, ShownPlayer, StateUpdate};
18-
use crate::dialog_ui::full_dialog;
18+
use crate::dialog_ui::dialog;
1919
use crate::payment_ui::{payment_dialog, HasPayment, Payment, ResourcePayment};
2020
use crate::resource_ui::{new_resource_map, ResourceType};
2121
use crate::select_ui::HasCountSelectableObject;
@@ -101,7 +101,7 @@ pub fn show_generic_advance_menu(
101101
player: &ShownPlayer,
102102
new_update: impl Fn(&str) -> StateUpdate,
103103
) -> StateUpdate {
104-
full_dialog(title, |ui| {
104+
dialog(player, title, |ui| {
105105
let p = player.get(game);
106106
let mut update = StateUpdate::None;
107107
let mut current_group = None;

client/src/client.rs

+19-40
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use macroquad::input::{is_mouse_button_pressed, mouse_position, MouseButton};
2-
use macroquad::prelude::{clear_background, vec2, WHITE};
3-
use macroquad::ui::root_ui;
2+
use macroquad::prelude::*;
43

54
use server::action::Action;
65
use server::game::Game;
@@ -12,13 +11,11 @@ use crate::client_state::{ActiveDialog, ShownPlayer, State, StateUpdate, StateUp
1211
use crate::collect_ui::{click_collect_option, collect_resources_dialog};
1312
use crate::construct_ui::pay_construction_dialog;
1413
use crate::dialog_ui::active_dialog_window;
15-
use crate::happiness_ui::{
16-
add_increase_happiness, increase_happiness_menu, show_increase_happiness,
17-
};
14+
use crate::happiness_ui::{add_increase_happiness, increase_happiness_menu};
1815
use crate::hex_ui::pixel_to_coordinate;
1916
use crate::log_ui::show_log;
2017
use crate::map_ui::{draw_map, show_tile_menu};
21-
use crate::player_ui::{show_global_controls, show_globals, show_player_status, show_wonders};
18+
use crate::player_ui::{show_global_controls, show_globals};
2219
use crate::{combat_ui, dialog_ui, influence_ui, move_ui, recruit_unit_ui, status_phase_ui};
2320

2421
pub async fn init(features: &Features) -> State {
@@ -45,55 +42,36 @@ pub fn render_and_update(
4542
state.update(game, update)
4643
}
4744

48-
fn render(game: &Game, state: &State, features: &Features) -> StateUpdate {
49-
let player_index = game.active_player();
45+
fn render(game: &Game, state: &mut State, features: &Features) -> StateUpdate {
5046
let player = &state.shown_player(game);
5147
clear_background(WHITE);
5248

53-
draw_map(game, state);
49+
state.camera = Camera2D {
50+
zoom: vec2(state.zoom, state.zoom * screen_width() / screen_height()),
51+
offset: state.offset,
52+
..Default::default()
53+
};
54+
set_camera(&state.camera);
55+
56+
if matches!(state.active_dialog, ActiveDialog::None) || state.active_dialog.is_map_dialog() {
57+
draw_map(game, state);
58+
}
5459
let mut updates = StateUpdates::new();
5560
let update = show_globals(game, player);
5661
updates.add(update);
57-
show_player_status(game, player_index);
58-
show_wonders(game, player_index);
59-
60-
if root_ui().button(vec2(1200., 100.), "Advances") {
61-
return StateUpdate::OpenDialog(ActiveDialog::AdvanceMenu);
62-
};
63-
if root_ui().button(vec2(1200., 130.), "Log") {
64-
return StateUpdate::OpenDialog(ActiveDialog::Log);
65-
};
66-
let d = state.game_state_dialog(game, &ActiveDialog::None);
67-
if !matches!(d, ActiveDialog::None)
68-
&& d.title() != state.active_dialog.title()
69-
&& root_ui().button(vec2(1200., 160.), format!("Back to {}", d.title()))
70-
{
71-
return StateUpdate::OpenDialog(d);
72-
}
7362

74-
if features.import_export && player.can_control {
75-
if root_ui().button(vec2(1200., 290.), "Import") {
76-
return StateUpdate::Import;
77-
};
78-
if root_ui().button(vec2(1250., 290.), "Export") {
79-
return StateUpdate::Export;
80-
};
81-
}
8263
if player.can_control {
8364
if let Some(u) = &state.pending_update {
8465
updates.add(dialog_ui::show_pending_update(u, player));
8566
return updates.result();
8667
}
8768
}
8869

89-
if player.can_play_action {
90-
updates.add(show_increase_happiness(game, player_index));
91-
}
92-
updates.add(show_global_controls(game, state));
70+
updates.add(show_global_controls(game, state, features));
9371

9472
updates.add(match &state.active_dialog {
9573
ActiveDialog::None => StateUpdate::None,
96-
ActiveDialog::Log => show_log(game),
74+
ActiveDialog::Log => show_log(game, player),
9775
ActiveDialog::TileMenu(p) => show_tile_menu(game, *p, player),
9876
ActiveDialog::WaitingForUpdate => {
9977
active_dialog_window(player, "Waiting for update", |_ui| StateUpdate::None)
@@ -143,8 +121,9 @@ pub fn try_click(game: &Game, state: &State, player: &ShownPlayer) -> StateUpdat
143121
return StateUpdate::None;
144122
}
145123
let (x, y) = mouse_position();
146-
147-
let pos = Position::from_coordinate(pixel_to_coordinate(x, y));
124+
let pos = Position::from_coordinate(pixel_to_coordinate(
125+
state.camera.screen_to_world(vec2(x, y)),
126+
));
148127
if !game.map.tiles.contains_key(&pos) {
149128
return StateUpdate::None;
150129
}

client/src/client_state.rs

+31-12
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,19 @@ impl ActiveDialog {
8080
ActiveDialog::RemoveCasualties(_) => "remove casualties",
8181
}
8282
}
83+
84+
#[must_use]
85+
pub fn is_map_dialog(&self) -> bool {
86+
matches!(
87+
self,
88+
ActiveDialog::TileMenu(_)
89+
| ActiveDialog::IncreaseHappiness(_)
90+
| ActiveDialog::CollectResources(_)
91+
| ActiveDialog::MoveUnits(_)
92+
| ActiveDialog::PlaceSettler
93+
| ActiveDialog::RazeSize1City
94+
)
95+
}
8396
}
8497

8598
pub struct PendingUpdate {
@@ -181,6 +194,7 @@ pub struct ShownPlayer {
181194
pub index: usize,
182195
pub can_control: bool,
183196
pub can_play_action: bool,
197+
pub active_dialog: ActiveDialog,
184198
}
185199

186200
impl ShownPlayer {
@@ -195,19 +209,28 @@ pub struct State {
195209
pub control_player: Option<usize>,
196210
pub show_player: usize,
197211
pub active_dialog: ActiveDialog,
198-
dialog_stack: Vec<ActiveDialog>,
199212
pub pending_update: Option<PendingUpdate>,
213+
pub camera: Camera2D,
214+
pub zoom: f32,
215+
pub offset: Vec2,
200216
}
201217

218+
pub const ZOOM: f32 = 0.001;
219+
pub const OFFSET: Vec2 = vec2(-0.8, 0.45);
220+
202221
impl State {
203222
pub async fn new(features: &Features) -> State {
204223
State {
205224
active_dialog: ActiveDialog::None,
206-
dialog_stack: vec![],
207225
pending_update: None,
208226
assets: Assets::new(features).await,
209227
control_player: None,
210228
show_player: 0,
229+
camera: Camera2D {
230+
..Default::default()
231+
},
232+
zoom: ZOOM,
233+
offset: OFFSET,
211234
}
212235
}
213236

@@ -219,12 +242,12 @@ impl State {
219242
index: self.show_player,
220243
can_control: control,
221244
can_play_action: control && game.state == GameState::Playing && game.actions_left > 0,
245+
active_dialog: self.active_dialog.clone(),
222246
}
223247
}
224248

225249
pub fn clear(&mut self) {
226250
self.active_dialog = ActiveDialog::None;
227-
self.dialog_stack.clear();
228251
self.pending_update = None;
229252
}
230253

@@ -280,26 +303,22 @@ impl State {
280303
}
281304

282305
fn open_dialog(&mut self, dialog: ActiveDialog) {
283-
if matches!(self.active_dialog, ActiveDialog::TileMenu(_)) {
306+
if self.active_dialog.title() == dialog.title() {
284307
self.close_dialog();
308+
return;
285309
}
286-
if !matches!(self.active_dialog, ActiveDialog::None) {
287-
self.dialog_stack.push(self.active_dialog.clone());
310+
if matches!(self.active_dialog, ActiveDialog::TileMenu(_)) {
311+
self.close_dialog();
288312
}
289313
self.active_dialog = dialog;
290314
}
291315

292316
pub fn set_dialog(&mut self, dialog: ActiveDialog) {
293317
self.active_dialog = dialog;
294-
self.dialog_stack.clear();
295318
}
296319

297320
fn close_dialog(&mut self) {
298-
if let Some(dialog) = self.dialog_stack.pop() {
299-
self.active_dialog = dialog;
300-
} else {
301-
self.active_dialog = ActiveDialog::None;
302-
}
321+
self.active_dialog = ActiveDialog::None;
303322
}
304323

305324
pub fn update_from_game(&mut self, game: &Game) -> GameSyncRequest {

client/src/dialog_ui.rs

+24-16
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1+
use crate::client_state::{PendingUpdate, ShownPlayer, StateUpdate};
12
use macroquad::hash;
23
use macroquad::math::{vec2, Vec2};
4+
use macroquad::prelude::screen_height;
35
use macroquad::ui::widgets::Window;
46
use macroquad::ui::{root_ui, Ui};
5-
6-
use crate::client_state::{PendingUpdate, ShownPlayer, StateUpdate};
7+
use macroquad::window::screen_width;
78

89
pub fn active_dialog_window<F>(player: &ShownPlayer, title: &str, f: F) -> StateUpdate
910
where
1011
F: FnOnce(&mut Ui) -> StateUpdate,
1112
{
12-
dialog(title, |ui| {
13+
dialog(player, title, |ui| {
1314
if player.can_control {
1415
f(ui)
1516
} else {
@@ -18,18 +19,17 @@ where
1819
})
1920
}
2021

21-
pub fn dialog<F>(title: &str, f: F) -> StateUpdate
22+
pub fn dialog<F>(player: &ShownPlayer, title: &str, f: F) -> StateUpdate
2223
where
2324
F: FnOnce(&mut Ui) -> StateUpdate,
2425
{
25-
custom_dialog(title, vec2(1100., 400.), vec2(800., 350.), f)
26-
}
27-
28-
pub fn full_dialog<F>(title: &str, f: F) -> StateUpdate
29-
where
30-
F: FnOnce(&mut Ui) -> StateUpdate,
31-
{
32-
custom_dialog(title, vec2(100., 100.), vec2(1600., 800.), f)
26+
let width = screen_width() - 20.;
27+
let size = if player.active_dialog.is_map_dialog() {
28+
vec2(width / 2.0, 100.)
29+
} else {
30+
vec2(width, screen_height() - 100.)
31+
};
32+
custom_dialog(title, vec2(10., 70.), size, f)
3333
}
3434

3535
pub fn custom_dialog<F>(title: &str, position: Vec2, size: Vec2, f: F) -> StateUpdate
@@ -42,10 +42,7 @@ where
4242
.label(title)
4343
.close_button(true);
4444

45-
let ui = &mut root_ui();
46-
let token = window.begin(ui);
47-
let update = f(ui);
48-
let open = token.end(ui);
45+
let (update, open) = show_window(window, f);
4946
if matches!(update, StateUpdate::None) {
5047
if open {
5148
StateUpdate::None
@@ -57,6 +54,17 @@ where
5754
}
5855
}
5956

57+
fn show_window<F, R>(window: Window, f: F) -> (R, bool)
58+
where
59+
F: FnOnce(&mut Ui) -> R,
60+
{
61+
let ui = &mut root_ui();
62+
let token = window.begin(ui);
63+
let update = f(ui);
64+
let open = token.end(ui);
65+
(update, open)
66+
}
67+
6068
pub fn show_pending_update(update: &PendingUpdate, player: &ShownPlayer) -> StateUpdate {
6169
active_dialog_window(player, "Are you sure?", |ui| {
6270
ui.label(None, &format!("Warning: {}", update.warning.join(", ")));

client/src/happiness_ui.rs

+9-16
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
use macroquad::math::vec2;
2-
use macroquad::ui::root_ui;
3-
41
use server::action::Action;
52
use server::city::City;
63
use server::game::Game;
@@ -103,17 +100,13 @@ pub fn increase_happiness_menu(h: &IncreaseHappiness, player: &ShownPlayer) -> S
103100
})
104101
}
105102

106-
pub fn show_increase_happiness(game: &Game, player_index: usize) -> StateUpdate {
107-
if root_ui().button(vec2(1200., 60.), "Increase Happiness") {
108-
return StateUpdate::SetDialog(ActiveDialog::IncreaseHappiness(IncreaseHappiness::new(
109-
game.get_player(player_index)
110-
.cities
111-
.iter()
112-
.map(|c| (c.position, 0))
113-
.collect(),
114-
ResourcePile::empty(),
115-
)));
116-
}
117-
118-
StateUpdate::None
103+
pub fn start_increase_happiness(game: &Game, player: &ShownPlayer) -> StateUpdate {
104+
StateUpdate::OpenDialog(ActiveDialog::IncreaseHappiness(IncreaseHappiness::new(
105+
game.get_player(player.index)
106+
.cities
107+
.iter()
108+
.map(|c| (c.position, 0))
109+
.collect(),
110+
ResourcePile::empty(),
111+
)))
119112
}

client/src/hex_ui.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::f32::consts::PI;
22

33
use hex2d::{Coordinate, Spacing};
44
use macroquad::color::Color;
5-
use macroquad::math::{f32, i32, vec2};
5+
use macroquad::math::{f32, i32, vec2, Vec2};
66
use macroquad::prelude::{
77
draw_text, draw_texture_ex, DrawTextureParams, Rect, Texture2D, BLACK, DARKGRAY, WHITE,
88
};
@@ -49,8 +49,8 @@ pub fn draw_hex_center_text(p: Position, text: &str) {
4949
draw_text(text, c.x - 5., c.y + 6., 25.0, BLACK);
5050
}
5151

52-
pub fn pixel_to_coordinate(x: f32, y: f32) -> Coordinate {
53-
let p = Point::new(x, y).to_game();
52+
pub fn pixel_to_coordinate(p: Vec2) -> Coordinate {
53+
let p = Point::new(p.x, p.y).to_game();
5454
Coordinate::from_pixel(p.x, p.y, SPACING)
5555
}
5656

@@ -89,5 +89,5 @@ impl Point {
8989
}
9090
}
9191

92-
const TOP_BORDER: f32 = 130.0;
93-
const LEFT_BORDER: f32 = 90.0;
92+
const TOP_BORDER: f32 = 0.0;
93+
const LEFT_BORDER: f32 = 0.0;

client/src/local_client/bin/main.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
use client::client::Features;
22
use client::local_client;
3-
use macroquad::window::set_fullscreen;
43
use server::game::Game;
54

65
#[macroquad::main("Clash")]
76
async fn main() {
8-
set_fullscreen(true);
7+
// set_fullscreen(true);
98

109
let features = Features {
11-
import_export: false,
10+
import_export: true,
1211
assets_url: "assets/".to_string(),
1312
};
1413

client/src/log_ui.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
use macroquad::ui::Ui;
22
use server::game::Game;
33

4-
use crate::client_state::StateUpdate;
4+
use crate::client_state::{ShownPlayer, StateUpdate};
55
use crate::dialog_ui::dialog;
66

7-
pub fn show_log(game: &Game) -> StateUpdate {
8-
dialog("Log", |ui| {
7+
pub fn show_log(game: &Game, player: &ShownPlayer) -> StateUpdate {
8+
dialog(player, "Log", |ui| {
99
game.log.iter().for_each(|l| {
1010
multiline(ui, l);
1111
});

0 commit comments

Comments
 (0)