Skip to content

Commit

Permalink
add Camera (#66)
Browse files Browse the repository at this point in the history
* add camera

* buttons on top

* buttons on top

* buttons on top

* buttons on top

* buttons on top
  • Loading branch information
zeitlinger authored Oct 6, 2024
1 parent 5eb4bce commit 4a656f9
Show file tree
Hide file tree
Showing 10 changed files with 199 additions and 147 deletions.
4 changes: 2 additions & 2 deletions client/src/advance_ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use server::resource_pile::AdvancePaymentOptions;
use server::status_phase::{StatusPhaseAction, StatusPhaseState};

use crate::client_state::{ActiveDialog, ShownPlayer, StateUpdate};
use crate::dialog_ui::full_dialog;
use crate::dialog_ui::dialog;
use crate::payment_ui::{payment_dialog, HasPayment, Payment, ResourcePayment};
use crate::resource_ui::{new_resource_map, ResourceType};
use crate::select_ui::HasCountSelectableObject;
Expand Down Expand Up @@ -101,7 +101,7 @@ pub fn show_generic_advance_menu(
player: &ShownPlayer,
new_update: impl Fn(&str) -> StateUpdate,
) -> StateUpdate {
full_dialog(title, |ui| {
dialog(player, title, |ui| {
let p = player.get(game);
let mut update = StateUpdate::None;
let mut current_group = None;
Expand Down
59 changes: 19 additions & 40 deletions client/src/client.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use macroquad::input::{is_mouse_button_pressed, mouse_position, MouseButton};
use macroquad::prelude::{clear_background, vec2, WHITE};
use macroquad::ui::root_ui;
use macroquad::prelude::*;

use server::action::Action;
use server::game::Game;
Expand All @@ -12,13 +11,11 @@ use crate::client_state::{ActiveDialog, ShownPlayer, State, StateUpdate, StateUp
use crate::collect_ui::{click_collect_option, collect_resources_dialog};
use crate::construct_ui::pay_construction_dialog;
use crate::dialog_ui::active_dialog_window;
use crate::happiness_ui::{
add_increase_happiness, increase_happiness_menu, show_increase_happiness,
};
use crate::happiness_ui::{add_increase_happiness, increase_happiness_menu};
use crate::hex_ui::pixel_to_coordinate;
use crate::log_ui::show_log;
use crate::map_ui::{draw_map, show_tile_menu};
use crate::player_ui::{show_global_controls, show_globals, show_player_status, show_wonders};
use crate::player_ui::{show_global_controls, show_globals};
use crate::{combat_ui, dialog_ui, influence_ui, move_ui, recruit_unit_ui, status_phase_ui};

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

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

draw_map(game, state);
state.camera = Camera2D {
zoom: vec2(state.zoom, state.zoom * screen_width() / screen_height()),
offset: state.offset,
..Default::default()
};
set_camera(&state.camera);

if matches!(state.active_dialog, ActiveDialog::None) || state.active_dialog.is_map_dialog() {
draw_map(game, state);
}
let mut updates = StateUpdates::new();
let update = show_globals(game, player);
updates.add(update);
show_player_status(game, player_index);
show_wonders(game, player_index);

if root_ui().button(vec2(1200., 100.), "Advances") {
return StateUpdate::OpenDialog(ActiveDialog::AdvanceMenu);
};
if root_ui().button(vec2(1200., 130.), "Log") {
return StateUpdate::OpenDialog(ActiveDialog::Log);
};
let d = state.game_state_dialog(game, &ActiveDialog::None);
if !matches!(d, ActiveDialog::None)
&& d.title() != state.active_dialog.title()
&& root_ui().button(vec2(1200., 160.), format!("Back to {}", d.title()))
{
return StateUpdate::OpenDialog(d);
}

if features.import_export && player.can_control {
if root_ui().button(vec2(1200., 290.), "Import") {
return StateUpdate::Import;
};
if root_ui().button(vec2(1250., 290.), "Export") {
return StateUpdate::Export;
};
}
if player.can_control {
if let Some(u) = &state.pending_update {
updates.add(dialog_ui::show_pending_update(u, player));
return updates.result();
}
}

if player.can_play_action {
updates.add(show_increase_happiness(game, player_index));
}
updates.add(show_global_controls(game, state));
updates.add(show_global_controls(game, state, features));

updates.add(match &state.active_dialog {
ActiveDialog::None => StateUpdate::None,
ActiveDialog::Log => show_log(game),
ActiveDialog::Log => show_log(game, player),
ActiveDialog::TileMenu(p) => show_tile_menu(game, *p, player),
ActiveDialog::WaitingForUpdate => {
active_dialog_window(player, "Waiting for update", |_ui| StateUpdate::None)
Expand Down Expand Up @@ -143,8 +121,9 @@ pub fn try_click(game: &Game, state: &State, player: &ShownPlayer) -> StateUpdat
return StateUpdate::None;
}
let (x, y) = mouse_position();

let pos = Position::from_coordinate(pixel_to_coordinate(x, y));
let pos = Position::from_coordinate(pixel_to_coordinate(
state.camera.screen_to_world(vec2(x, y)),
));
if !game.map.tiles.contains_key(&pos) {
return StateUpdate::None;
}
Expand Down
43 changes: 31 additions & 12 deletions client/src/client_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,19 @@ impl ActiveDialog {
ActiveDialog::RemoveCasualties(_) => "remove casualties",
}
}

#[must_use]
pub fn is_map_dialog(&self) -> bool {
matches!(
self,
ActiveDialog::TileMenu(_)
| ActiveDialog::IncreaseHappiness(_)
| ActiveDialog::CollectResources(_)
| ActiveDialog::MoveUnits(_)
| ActiveDialog::PlaceSettler
| ActiveDialog::RazeSize1City
)
}
}

pub struct PendingUpdate {
Expand Down Expand Up @@ -181,6 +194,7 @@ pub struct ShownPlayer {
pub index: usize,
pub can_control: bool,
pub can_play_action: bool,
pub active_dialog: ActiveDialog,
}

impl ShownPlayer {
Expand All @@ -195,19 +209,28 @@ pub struct State {
pub control_player: Option<usize>,
pub show_player: usize,
pub active_dialog: ActiveDialog,
dialog_stack: Vec<ActiveDialog>,
pub pending_update: Option<PendingUpdate>,
pub camera: Camera2D,
pub zoom: f32,
pub offset: Vec2,
}

pub const ZOOM: f32 = 0.001;
pub const OFFSET: Vec2 = vec2(-0.8, 0.45);

impl State {
pub async fn new(features: &Features) -> State {
State {
active_dialog: ActiveDialog::None,
dialog_stack: vec![],
pending_update: None,
assets: Assets::new(features).await,
control_player: None,
show_player: 0,
camera: Camera2D {
..Default::default()
},
zoom: ZOOM,
offset: OFFSET,
}
}

Expand All @@ -219,12 +242,12 @@ impl State {
index: self.show_player,
can_control: control,
can_play_action: control && game.state == GameState::Playing && game.actions_left > 0,
active_dialog: self.active_dialog.clone(),
}
}

pub fn clear(&mut self) {
self.active_dialog = ActiveDialog::None;
self.dialog_stack.clear();
self.pending_update = None;
}

Expand Down Expand Up @@ -280,26 +303,22 @@ impl State {
}

fn open_dialog(&mut self, dialog: ActiveDialog) {
if matches!(self.active_dialog, ActiveDialog::TileMenu(_)) {
if self.active_dialog.title() == dialog.title() {
self.close_dialog();
return;
}
if !matches!(self.active_dialog, ActiveDialog::None) {
self.dialog_stack.push(self.active_dialog.clone());
if matches!(self.active_dialog, ActiveDialog::TileMenu(_)) {
self.close_dialog();
}
self.active_dialog = dialog;
}

pub fn set_dialog(&mut self, dialog: ActiveDialog) {
self.active_dialog = dialog;
self.dialog_stack.clear();
}

fn close_dialog(&mut self) {
if let Some(dialog) = self.dialog_stack.pop() {
self.active_dialog = dialog;
} else {
self.active_dialog = ActiveDialog::None;
}
self.active_dialog = ActiveDialog::None;
}

pub fn update_from_game(&mut self, game: &Game) -> GameSyncRequest {
Expand Down
40 changes: 24 additions & 16 deletions client/src/dialog_ui.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
use crate::client_state::{PendingUpdate, ShownPlayer, StateUpdate};
use macroquad::hash;
use macroquad::math::{vec2, Vec2};
use macroquad::prelude::screen_height;
use macroquad::ui::widgets::Window;
use macroquad::ui::{root_ui, Ui};

use crate::client_state::{PendingUpdate, ShownPlayer, StateUpdate};
use macroquad::window::screen_width;

pub fn active_dialog_window<F>(player: &ShownPlayer, title: &str, f: F) -> StateUpdate
where
F: FnOnce(&mut Ui) -> StateUpdate,
{
dialog(title, |ui| {
dialog(player, title, |ui| {
if player.can_control {
f(ui)
} else {
Expand All @@ -18,18 +19,17 @@ where
})
}

pub fn dialog<F>(title: &str, f: F) -> StateUpdate
pub fn dialog<F>(player: &ShownPlayer, title: &str, f: F) -> StateUpdate
where
F: FnOnce(&mut Ui) -> StateUpdate,
{
custom_dialog(title, vec2(1100., 400.), vec2(800., 350.), f)
}

pub fn full_dialog<F>(title: &str, f: F) -> StateUpdate
where
F: FnOnce(&mut Ui) -> StateUpdate,
{
custom_dialog(title, vec2(100., 100.), vec2(1600., 800.), f)
let width = screen_width() - 20.;
let size = if player.active_dialog.is_map_dialog() {
vec2(width / 2.0, 100.)
} else {
vec2(width, screen_height() - 100.)
};
custom_dialog(title, vec2(10., 70.), size, f)
}

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

let ui = &mut root_ui();
let token = window.begin(ui);
let update = f(ui);
let open = token.end(ui);
let (update, open) = show_window(window, f);
if matches!(update, StateUpdate::None) {
if open {
StateUpdate::None
Expand All @@ -57,6 +54,17 @@ where
}
}

fn show_window<F, R>(window: Window, f: F) -> (R, bool)
where
F: FnOnce(&mut Ui) -> R,
{
let ui = &mut root_ui();
let token = window.begin(ui);
let update = f(ui);
let open = token.end(ui);
(update, open)
}

pub fn show_pending_update(update: &PendingUpdate, player: &ShownPlayer) -> StateUpdate {
active_dialog_window(player, "Are you sure?", |ui| {
ui.label(None, &format!("Warning: {}", update.warning.join(", ")));
Expand Down
25 changes: 9 additions & 16 deletions client/src/happiness_ui.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
use macroquad::math::vec2;
use macroquad::ui::root_ui;

use server::action::Action;
use server::city::City;
use server::game::Game;
Expand Down Expand Up @@ -103,17 +100,13 @@ pub fn increase_happiness_menu(h: &IncreaseHappiness, player: &ShownPlayer) -> S
})
}

pub fn show_increase_happiness(game: &Game, player_index: usize) -> StateUpdate {
if root_ui().button(vec2(1200., 60.), "Increase Happiness") {
return StateUpdate::SetDialog(ActiveDialog::IncreaseHappiness(IncreaseHappiness::new(
game.get_player(player_index)
.cities
.iter()
.map(|c| (c.position, 0))
.collect(),
ResourcePile::empty(),
)));
}

StateUpdate::None
pub fn start_increase_happiness(game: &Game, player: &ShownPlayer) -> StateUpdate {
StateUpdate::OpenDialog(ActiveDialog::IncreaseHappiness(IncreaseHappiness::new(
game.get_player(player.index)
.cities
.iter()
.map(|c| (c.position, 0))
.collect(),
ResourcePile::empty(),
)))
}
10 changes: 5 additions & 5 deletions client/src/hex_ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::f32::consts::PI;

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

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

Expand Down Expand Up @@ -89,5 +89,5 @@ impl Point {
}
}

const TOP_BORDER: f32 = 130.0;
const LEFT_BORDER: f32 = 90.0;
const TOP_BORDER: f32 = 0.0;
const LEFT_BORDER: f32 = 0.0;
5 changes: 2 additions & 3 deletions client/src/local_client/bin/main.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
use client::client::Features;
use client::local_client;
use macroquad::window::set_fullscreen;
use server::game::Game;

#[macroquad::main("Clash")]
async fn main() {
set_fullscreen(true);
// set_fullscreen(true);

let features = Features {
import_export: false,
import_export: true,
assets_url: "assets/".to_string(),
};

Expand Down
6 changes: 3 additions & 3 deletions client/src/log_ui.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use macroquad::ui::Ui;
use server::game::Game;

use crate::client_state::StateUpdate;
use crate::client_state::{ShownPlayer, StateUpdate};
use crate::dialog_ui::dialog;

pub fn show_log(game: &Game) -> StateUpdate {
dialog("Log", |ui| {
pub fn show_log(game: &Game, player: &ShownPlayer) -> StateUpdate {
dialog(player, "Log", |ui| {
game.log.iter().for_each(|l| {
multiline(ui, l);
});
Expand Down
Loading

0 comments on commit 4a656f9

Please sign in to comment.