Browse Source

display terrain opacity

Bastien Sevajol 3 years ago
parent
commit
f43ab3f960
8 changed files with 217 additions and 83 deletions
  1. 0 4
      src/config.rs
  2. 8 0
      src/main.rs
  3. 3 3
      src/physics/mod.rs
  4. 3 3
      src/physics/util.rs
  5. 28 16
      src/scene/item.rs
  6. 118 57
      src/scene/main.rs
  7. 1 0
      src/scene/mod.rs
  8. 56 0
      src/scene/util.rs

+ 0 - 4
src/config.rs View File

@@ -22,10 +22,6 @@ pub const SCENE_ITEMS_SPRITE_SHEET_HEIGHT: f32 = 600.0;
22 22
 pub const UI_SPRITE_SHEET_WIDTH: f32 = 800.0;
23 23
 // Height of sprite sheet
24 24
 pub const UI_SPRITE_SHEET_HEIGHT: f32 = 600.0;
25
-// Width of one grid tile
26
-pub const GRID_TILE_WIDTH: f32 = 5.0;
27
-// Height of one grid tile
28
-pub const GRID_TILE_HEIGHT: f32 = 5.0;
29 25
 //
30 26
 pub const DEFAULT_SELECTED_SQUARE_SIDE: f32 = 14.0;
31 27
 //

+ 8 - 0
src/main.rs View File

@@ -4,6 +4,8 @@ use std::path;
4 4
 use ggez::{event, GameResult};
5 5
 use glam::Vec2;
6 6
 
7
+use crate::scene::item::SceneItemModifier;
8
+use crate::scene::main::MainStateModifier;
7 9
 use scene::main::MainState;
8 10
 
9 11
 mod behavior;
@@ -17,6 +19,12 @@ mod util;
17 19
 type WindowPoint = Vec2;
18 20
 type Offset = Vec2;
19 21
 type ScenePoint = Vec2;
22
+type SceneItemId = usize;
23
+
24
+enum Message {
25
+    SceneItemMessage(SceneItemId, SceneItemModifier),
26
+    MainStateMessage(MainStateModifier),
27
+}
20 28
 
21 29
 pub fn main() -> GameResult {
22 30
     let resource_dir = if let Ok(manifest_dir) = env::var("CARGO_MANIFEST_DIR") {

+ 3 - 3
src/physics/mod.rs View File

@@ -10,13 +10,13 @@ pub enum MetaEvent {
10 10
     FeelExplosion,
11 11
 }
12 12
 
13
-#[derive(Eq, PartialEq, Hash)]
14
-pub struct GridPosition {
13
+#[derive(Eq, PartialEq, Hash, Clone)]
14
+pub struct GridPoint {
15 15
     x: i32,
16 16
     y: i32,
17 17
 }
18 18
 
19
-impl GridPosition {
19
+impl GridPoint {
20 20
     pub fn new(x: i32, y: i32) -> Self {
21 21
         Self { x, y }
22 22
     }

+ 3 - 3
src/physics/util.rs View File

@@ -1,9 +1,9 @@
1 1
 use crate::map::Map;
2
-use crate::physics::GridPosition;
2
+use crate::physics::GridPoint;
3 3
 use crate::{ScenePoint, WindowPoint};
4 4
 
5
-pub fn grid_position_from_scene_point(position: &ScenePoint, map: &Map) -> GridPosition {
6
-    GridPosition::new(
5
+pub fn grid_position_from_scene_point(position: &ScenePoint, map: &Map) -> GridPoint {
6
+    GridPoint::new(
7 7
         (position.x / map.terrain_tileset.tile_width as f32) as i32,
8 8
         (position.y / map.terrain_tileset.tile_height as f32) as i32,
9 9
     )

+ 28 - 16
src/scene/item.rs View File

@@ -4,7 +4,7 @@ use crate::behavior::order::Order;
4 4
 use crate::behavior::ItemBehavior;
5 5
 use crate::config::{SCENE_ITEMS_SPRITE_SHEET_HEIGHT, SCENE_ITEMS_SPRITE_SHEET_WIDTH};
6 6
 use crate::map::Map;
7
-use crate::physics::GridPosition;
7
+use crate::physics::GridPoint;
8 8
 use crate::physics::{util, MetaEvent};
9 9
 use crate::scene::SpriteType;
10 10
 use crate::{Offset, ScenePoint};
@@ -61,7 +61,7 @@ pub enum SceneItemType {
61 61
 pub struct SceneItem {
62 62
     pub type_: SceneItemType,
63 63
     pub position: ScenePoint,
64
-    pub grid_position: GridPosition,
64
+    pub grid_position: GridPoint,
65 65
     pub state: ItemState,
66 66
     pub meta_events: Vec<MetaEvent>,
67 67
     pub current_frame: f32,
@@ -127,22 +127,34 @@ pub enum SceneItemModifier {
127 127
     SwitchToNextOrder,
128 128
     ChangeDisplayAngle(f32),
129 129
     ChangeState(ItemState),
130
+    ChangePosition(ScenePoint),
131
+    ChangeGridPosition(GridPoint),
130 132
 }
131 133
 
132
-pub fn apply_scene_item_modifier(scene_item: &mut SceneItem, modifiers: Vec<SceneItemModifier>) {
133
-    for modifier in modifiers {
134
-        match modifier {
135
-            SceneItemModifier::SwitchToNextOrder => {
136
-                let next_order = scene_item.next_order.clone();
137
-                scene_item.current_order = next_order;
138
-                scene_item.next_order = None;
139
-            }
140
-            SceneItemModifier::ChangeDisplayAngle(new_angle) => {
141
-                scene_item.display_angle = new_angle;
142
-            }
143
-            SceneItemModifier::ChangeState(new_state) => {
144
-                scene_item.state = new_state;
145
-            }
134
+pub fn apply_scene_item_modifiers(scene_item: &mut SceneItem, modifiers: Vec<SceneItemModifier>) {
135
+    for modifier in modifiers.into_iter() {
136
+        apply_scene_item_modifier(scene_item, modifier)
137
+    }
138
+}
139
+
140
+pub fn apply_scene_item_modifier(scene_item: &mut SceneItem, modifier: SceneItemModifier) {
141
+    match modifier {
142
+        SceneItemModifier::SwitchToNextOrder => {
143
+            let next_order = scene_item.next_order.clone();
144
+            scene_item.current_order = next_order;
145
+            scene_item.next_order = None;
146
+        }
147
+        SceneItemModifier::ChangeDisplayAngle(new_angle) => {
148
+            scene_item.display_angle = new_angle;
149
+        }
150
+        SceneItemModifier::ChangeState(new_state) => {
151
+            scene_item.state = new_state;
152
+        }
153
+        SceneItemModifier::ChangePosition(new_point) => {
154
+            scene_item.position = new_point;
155
+        }
156
+        SceneItemModifier::ChangeGridPosition(new_grid_point) => {
157
+            scene_item.grid_position = new_grid_point;
146 158
         }
147 159
     }
148 160
 }

+ 118 - 57
src/scene/main.rs View File

@@ -1,5 +1,7 @@
1 1
 use std::cmp;
2 2
 use std::collections::HashMap;
3
+use std::path::Path;
4
+use std::time::Instant;
3 5
 
4 6
 use ggez::event::MouseButton;
5 7
 use ggez::graphics::{DrawMode, MeshBuilder, StrokeOptions};
@@ -18,16 +20,28 @@ use crate::config::{
18 20
 use crate::map::Map;
19 21
 use crate::physics::util::scene_point_from_window_point;
20 22
 use crate::physics::util::window_point_from_scene_point;
21
-use crate::physics::GridPosition;
23
+use crate::physics::GridPoint;
22 24
 use crate::physics::{util, MetaEvent, PhysicEvent};
23
-use crate::scene::item::{apply_scene_item_modifier, ItemState, SceneItem, SceneItemType};
25
+use crate::scene::item::{
26
+    apply_scene_item_modifier, apply_scene_item_modifiers, ItemState, SceneItem, SceneItemModifier,
27
+    SceneItemType,
28
+};
24 29
 use crate::ui::vertical_menu::vertical_menu_sprite_info;
25 30
 use crate::ui::MenuItem;
26 31
 use crate::ui::{SceneItemPrepareOrder, UiComponent, UserEvent};
27 32
 use crate::util::velocity_for_behavior;
28
-use crate::{Offset, ScenePoint, WindowPoint};
29
-use std::path::Path;
30
-use std::time::Instant;
33
+use crate::{scene, Message, Offset, SceneItemId, ScenePoint, WindowPoint};
34
+
35
+#[derive(PartialEq)]
36
+enum DebugTerrain {
37
+    None,
38
+    Tiles,
39
+    Opacity,
40
+}
41
+
42
+pub enum MainStateModifier {
43
+    ChangeSceneItemGridPosition(SceneItemId, GridPoint, GridPoint),
44
+}
31 45
 
32 46
 pub struct MainState {
33 47
     // time
@@ -39,16 +53,17 @@ pub struct MainState {
39 53
 
40 54
     // display
41 55
     debug: bool,
42
-    debug_terrain: bool,
56
+    debug_terrain: DebugTerrain,
43 57
     display_offset: Offset,
44 58
     sprite_sheet_batch: graphics::spritebatch::SpriteBatch,
45 59
     map_batch: graphics::spritebatch::SpriteBatch,
46 60
     ui_batch: graphics::spritebatch::SpriteBatch,
47
-    terrain_batch: graphics::spritebatch::SpriteBatch,
61
+    debug_terrain_batch: graphics::spritebatch::SpriteBatch,
62
+    debug_terrain_opacity_mesh_builder: MeshBuilder,
48 63
 
49 64
     // scene items
50 65
     scene_items: Vec<SceneItem>,
51
-    scene_items_by_grid_position: HashMap<GridPosition, Vec<usize>>,
66
+    scene_items_by_grid_position: HashMap<GridPoint, Vec<usize>>,
52 67
 
53 68
     // events
54 69
     physics_events: Vec<PhysicEvent>,
@@ -64,32 +79,6 @@ pub struct MainState {
64 79
     scene_item_prepare_order: Option<SceneItemPrepareOrder>,
65 80
 }
66 81
 
67
-fn update_terrain_batch(
68
-    mut terrain_batch: graphics::spritebatch::SpriteBatch,
69
-    map: &Map,
70
-) -> graphics::spritebatch::SpriteBatch {
71
-    terrain_batch.clear();
72
-    for ((grid_x, grid_y), tile) in map.tiles.iter() {
73
-        // FIXME pre compute these data
74
-        let src_x = tile.tile_x as f32 * tile.relative_tile_width;
75
-        let src_y = tile.tile_y as f32 * tile.relative_tile_height;
76
-        let dest_x = *grid_x as f32 * tile.tile_width as f32;
77
-        let dest_y = *grid_y as f32 * tile.tile_height as f32;
78
-        terrain_batch.add(
79
-            graphics::DrawParam::new()
80
-                .src(graphics::Rect::new(
81
-                    src_x,
82
-                    src_y,
83
-                    tile.relative_tile_width,
84
-                    tile.relative_tile_height,
85
-                ))
86
-                .dest(ScenePoint::new(dest_x, dest_y)),
87
-        );
88
-    }
89
-
90
-    terrain_batch
91
-}
92
-
93 82
 impl MainState {
94 83
     pub fn new(ctx: &mut Context) -> GameResult<MainState> {
95 84
         let map = Map::new(&Path::new("resources/map1.tmx"))?;
@@ -107,18 +96,14 @@ impl MainState {
107 96
         let ui_batch = graphics::spritebatch::SpriteBatch::new(ui_image);
108 97
 
109 98
         let terrain_image = graphics::Image::new(ctx, format!("/{}", map.terrain_image.source))?;
110
-        let mut terrain_batch = graphics::spritebatch::SpriteBatch::new(terrain_image);
111
-        terrain_batch = update_terrain_batch(terrain_batch, &map);
99
+        let mut debug_terrain_batch = graphics::spritebatch::SpriteBatch::new(terrain_image);
100
+        debug_terrain_batch = scene::util::update_terrain_batch(debug_terrain_batch, &map);
101
+        let debug_terrain_opacity_mesh_builder =
102
+            scene::util::create_debug_terrain_opacity_mesh_builder(&map)?;
112 103
 
113 104
         let mut scene_items = vec![];
114 105
         for x in 0..1 {
115 106
             for y in 0..4 {
116
-                // let current_behavior = if y % 2 == 0 {
117
-                //     ItemBehavior::WalkingTo(util::vec_from_angle(90.0))
118
-                // } else {
119
-                //     ItemBehavior::CrawlingTo()
120
-                // };
121
-
122 107
                 scene_items.push(SceneItem::new(
123 108
                     SceneItemType::Soldier,
124 109
                     ScenePoint::new((x as f32 * 24.0) + 100.0, (y as f32 * 24.0) + 100.0),
@@ -128,7 +113,7 @@ impl MainState {
128 113
             }
129 114
         }
130 115
 
131
-        let mut scene_items_by_grid_position: HashMap<GridPosition, Vec<usize>> = HashMap::new();
116
+        let mut scene_items_by_grid_position: HashMap<GridPoint, Vec<usize>> = HashMap::new();
132 117
         for (i, scene_item) in scene_items.iter().enumerate() {
133 118
             let grid_position = util::grid_position_from_scene_point(&scene_item.position, &map);
134 119
             scene_items_by_grid_position
@@ -137,17 +122,18 @@ impl MainState {
137 122
                 .push(i);
138 123
         }
139 124
 
140
-        let mut main_state = MainState {
125
+        let main_state = MainState {
141 126
             frame_i: 0,
142 127
             start: Instant::now(),
143 128
             map,
144 129
             debug: false,
145
-            debug_terrain: false,
130
+            debug_terrain: DebugTerrain::None,
146 131
             display_offset: Offset::new(0.0, 0.0),
147 132
             sprite_sheet_batch,
148 133
             map_batch,
149 134
             ui_batch,
150
-            terrain_batch,
135
+            debug_terrain_batch,
136
+            debug_terrain_opacity_mesh_builder,
151 137
             scene_items,
152 138
             scene_items_by_grid_position,
153 139
             physics_events: vec![],
@@ -219,7 +205,11 @@ impl MainState {
219 205
                 .as_millis()
220 206
                 > 250
221 207
             {
222
-                self.debug_terrain = !self.debug_terrain;
208
+                self.debug_terrain = match &self.debug_terrain {
209
+                    DebugTerrain::None => DebugTerrain::Tiles,
210
+                    DebugTerrain::Tiles => DebugTerrain::Opacity,
211
+                    DebugTerrain::Opacity => DebugTerrain::None,
212
+                };
223 213
                 self.last_key_consumed.insert(KeyCode::F10, Instant::now());
224 214
             }
225 215
         }
@@ -330,10 +320,33 @@ impl MainState {
330 320
             .extend(self.get_scene_items_for_scene_area(&scene_from, &scene_to));
331 321
     }
332 322
 
323
+    fn change_scene_item_grid_position(
324
+        &mut self,
325
+        scene_item_i: usize,
326
+        from_grid_position: GridPoint,
327
+        to_grid_position: GridPoint,
328
+    ) {
329
+        let grid_position_scene_items = self
330
+            .scene_items_by_grid_position
331
+            .get_mut(&from_grid_position)
332
+            .expect("Scene item should be here !");
333
+        let x = grid_position_scene_items
334
+            .iter()
335
+            .position(|x| *x == scene_item_i)
336
+            .expect("Scene item should be here !");
337
+        grid_position_scene_items.remove(x);
338
+        self.scene_items_by_grid_position
339
+            .entry(to_grid_position)
340
+            .or_default()
341
+            .push(scene_item_i)
342
+    }
343
+
333 344
     // TODO: manage errors
334 345
     fn physics(&mut self) {
346
+        let mut messages: Vec<Message> = vec![];
347
+
335 348
         // Scene items movements
336
-        for scene_item in self.scene_items.iter_mut() {
349
+        for (scene_item_i, scene_item) in self.scene_items.iter_mut().enumerate() {
337 350
             match scene_item.state.current_behavior {
338 351
                 ItemBehavior::Standing => {}
339 352
                 ItemBehavior::MoveTo(move_to_scene_point)
@@ -343,11 +356,29 @@ impl MainState {
343 356
                         .expect("must have velocity here");
344 357
                     let move_vector =
345 358
                         (move_to_scene_point - scene_item.position).normalize() * velocity;
346
-                    // TODO ici il faut calculer le déplacement réél (en fonction des ticks, etc ...)
347
-                    scene_item.position.x += move_vector.x;
348
-                    scene_item.position.y += move_vector.y;
349
-                    scene_item.grid_position =
359
+                    let new_position = ScenePoint::new(
360
+                        scene_item.position.x + move_vector.x,
361
+                        scene_item.position.y + move_vector.y,
362
+                    );
363
+                    messages.push(Message::SceneItemMessage(
364
+                        scene_item_i,
365
+                        SceneItemModifier::ChangePosition(new_position),
366
+                    ));
367
+                    let new_grid_position =
350 368
                         util::grid_position_from_scene_point(&scene_item.position, &self.map);
369
+                    if scene_item.grid_position != new_grid_position {
370
+                        messages.push(Message::MainStateMessage(
371
+                            MainStateModifier::ChangeSceneItemGridPosition(
372
+                                scene_item_i,
373
+                                scene_item.grid_position.clone(),
374
+                                new_grid_position.clone(),
375
+                            ),
376
+                        ));
377
+                        messages.push(Message::SceneItemMessage(
378
+                            scene_item_i,
379
+                            SceneItemModifier::ChangeGridPosition(new_grid_position.clone()),
380
+                        ));
381
+                    }
351 382
                 }
352 383
             }
353 384
         }
@@ -356,6 +387,32 @@ impl MainState {
356 387
         if self.frame_i % 600 == 0 && self.frame_i != 0 {
357 388
             self.physics_events.push(PhysicEvent::Explosion);
358 389
         }
390
+
391
+        self.consume_messages(messages);
392
+    }
393
+
394
+    fn consume_messages(&mut self, messages: Vec<Message>) {
395
+        for message in messages.into_iter() {
396
+            match message {
397
+                Message::SceneItemMessage(i, scene_item_modifier) => {
398
+                    let scene_item = self.get_scene_item_mut(i);
399
+                    apply_scene_item_modifier(scene_item, scene_item_modifier);
400
+                }
401
+                Message::MainStateMessage(main_state_modifier) => match main_state_modifier {
402
+                    MainStateModifier::ChangeSceneItemGridPosition(
403
+                        scene_item_i,
404
+                        from_grid_position,
405
+                        to_grid_position,
406
+                    ) => {
407
+                        self.change_scene_item_grid_position(
408
+                            scene_item_i,
409
+                            from_grid_position,
410
+                            to_grid_position,
411
+                        );
412
+                    }
413
+                },
414
+            }
415
+        }
359 416
     }
360 417
 
361 418
     fn metas(&mut self) {
@@ -372,9 +429,9 @@ impl MainState {
372 429
 
373 430
     fn animate(&mut self) {
374 431
         for (_, scene_item) in self.scene_items.iter_mut().enumerate() {
375
-            apply_scene_item_modifier(scene_item, digest_next_order(&scene_item));
376
-            apply_scene_item_modifier(scene_item, digest_current_order(&scene_item));
377
-            apply_scene_item_modifier(scene_item, digest_current_behavior(&scene_item));
432
+            apply_scene_item_modifiers(scene_item, digest_next_order(&scene_item));
433
+            apply_scene_item_modifiers(scene_item, digest_current_order(&scene_item));
434
+            apply_scene_item_modifiers(scene_item, digest_current_behavior(&scene_item));
378 435
         }
379 436
     }
380 437
 
@@ -640,8 +697,12 @@ impl event::EventHandler for MainState {
640 697
         ));
641 698
 
642 699
         graphics::draw(ctx, &self.map_batch, window_draw_param)?;
643
-        if self.debug_terrain {
644
-            graphics::draw(ctx, &self.terrain_batch, window_draw_param)?;
700
+        if self.debug_terrain == DebugTerrain::Tiles {
701
+            graphics::draw(ctx, &self.debug_terrain_batch, window_draw_param)?;
702
+        } else if self.debug_terrain == DebugTerrain::Opacity {
703
+            let debug_terrain_opacity_mesh =
704
+                self.debug_terrain_opacity_mesh_builder.build(ctx).unwrap();
705
+            graphics::draw(ctx, &debug_terrain_opacity_mesh, window_draw_param)?;
645 706
         }
646 707
         graphics::draw(ctx, &self.sprite_sheet_batch, window_draw_param)?;
647 708
         if let Ok(scene_mesh) = scene_mesh_builder.build(ctx) {

+ 1 - 0
src/scene/mod.rs View File

@@ -1,5 +1,6 @@
1 1
 pub mod item;
2 2
 pub mod main;
3
+pub mod util;
3 4
 
4 5
 pub enum SpriteType {
5 6
     WalkingSoldier,

+ 56 - 0
src/scene/util.rs View File

@@ -0,0 +1,56 @@
1
+use ggez::graphics::{Color, DrawMode, MeshBuilder};
2
+use ggez::{graphics, GameResult};
3
+
4
+use crate::map::Map;
5
+use crate::ScenePoint;
6
+
7
+pub fn update_terrain_batch(
8
+    mut terrain_batch: graphics::spritebatch::SpriteBatch,
9
+    map: &Map,
10
+) -> graphics::spritebatch::SpriteBatch {
11
+    terrain_batch.clear();
12
+    for ((grid_x, grid_y), tile) in map.tiles.iter() {
13
+        // FIXME pre compute these data ?
14
+        let src_x = tile.tile_x as f32 * tile.relative_tile_width;
15
+        let src_y = tile.tile_y as f32 * tile.relative_tile_height;
16
+        let dest_x = *grid_x as f32 * tile.tile_width as f32;
17
+        let dest_y = *grid_y as f32 * tile.tile_height as f32;
18
+        terrain_batch.add(
19
+            graphics::DrawParam::new()
20
+                .src(graphics::Rect::new(
21
+                    src_x,
22
+                    src_y,
23
+                    tile.relative_tile_width,
24
+                    tile.relative_tile_height,
25
+                ))
26
+                .dest(ScenePoint::new(dest_x, dest_y)),
27
+        );
28
+    }
29
+
30
+    terrain_batch
31
+}
32
+
33
+pub fn create_debug_terrain_opacity_mesh_builder(map: &Map) -> GameResult<MeshBuilder> {
34
+    let mut debug_terrain_opacity_mesh = MeshBuilder::new();
35
+    for ((grid_x, grid_y), tile) in map.tiles.iter() {
36
+        let dest_x = *grid_x as f32 * tile.tile_width as f32;
37
+        let dest_y = *grid_y as f32 * tile.tile_height as f32;
38
+        let color_modifier = 0.6 * tile.opacity;
39
+        debug_terrain_opacity_mesh.rectangle(
40
+            DrawMode::fill(),
41
+            graphics::Rect::new(
42
+                dest_x,
43
+                dest_y,
44
+                tile.tile_width as f32,
45
+                tile.tile_height as f32,
46
+            ),
47
+            Color {
48
+                r: 0.4 - color_modifier,
49
+                g: 0.4 - color_modifier,
50
+                b: 0.4 - color_modifier,
51
+                a: 1.0,
52
+            },
53
+        )?;
54
+    }
55
+    Ok(debug_terrain_opacity_mesh)
56
+}