|
@@ -1,15 +1,31 @@
|
|
1
|
+use std::cmp;
|
|
2
|
+use std::collections::HashMap;
|
|
3
|
+use std::env;
|
|
4
|
+use std::path;
|
|
5
|
+
|
1
|
6
|
use ggez;
|
|
7
|
+use ggez::{event, input};
|
|
8
|
+use ggez::{Context, GameResult};
|
2
|
9
|
use ggez::event::{KeyCode, MouseButton};
|
3
|
10
|
use ggez::graphics;
|
4
|
11
|
use ggez::graphics::{Color, DrawMode, FillOptions, MeshBuilder, StrokeOptions};
|
5
|
12
|
use ggez::timer::check_update_time;
|
6
|
|
-use ggez::{event, input};
|
7
|
|
-use ggez::{Context, GameResult};
|
8
|
13
|
use glam::Vec2;
|
9
|
|
-use std::cmp;
|
10
|
|
-use std::collections::HashMap;
|
11
|
|
-use std::env;
|
12
|
|
-use std::path;
|
|
14
|
+
|
|
15
|
+use behavior::ItemBehavior;
|
|
16
|
+use physics::{MetaEvent, PhysicEvent, util};
|
|
17
|
+use scene::item::{ItemState, SceneItem, SceneItemSpriteInfo, SceneItemType};
|
|
18
|
+use scene::main::MainState;
|
|
19
|
+use scene::SpriteType;
|
|
20
|
+use ui::{SceneItemPrepareOrder, UiItem, UiSpriteInfo, UserEvent};
|
|
21
|
+use ui::scene_item_menu::SceneItemMenuItem;
|
|
22
|
+
|
|
23
|
+use crate::physics::position::GridPosition;
|
|
24
|
+
|
|
25
|
+mod physics;
|
|
26
|
+mod ui;
|
|
27
|
+mod scene;
|
|
28
|
+mod behavior;
|
13
|
29
|
|
14
|
30
|
// TODO: create a ScenePosition and a WindowPosition to be more explicit
|
15
|
31
|
type Point2 = Vec2;
|
|
@@ -33,725 +49,6 @@ const DEFAULT_SELECTED_SQUARE_SIDE: f32 = 14.0;
|
33
|
49
|
const DEFAULT_SELECTED_SQUARE_SIDE_HALF: f32 = DEFAULT_SELECTED_SQUARE_SIDE / 2.0;
|
34
|
50
|
const SCENE_ITEMS_CHANGE_ERR_MSG: &str = "scene_items content change !";
|
35
|
51
|
|
36
|
|
-#[derive(Eq, PartialEq, Hash)]
|
37
|
|
-pub struct GridPosition {
|
38
|
|
- x: i32,
|
39
|
|
- y: i32,
|
40
|
|
-}
|
41
|
|
-
|
42
|
|
-impl GridPosition {
|
43
|
|
- pub fn new(x: i32, y: i32) -> Self {
|
44
|
|
- Self { x, y }
|
45
|
|
- }
|
46
|
|
-}
|
47
|
|
-
|
48
|
|
-fn vec_from_angle(angle: f32) -> Vector2 {
|
49
|
|
- let vx = angle.sin();
|
50
|
|
- let vy = angle.cos();
|
51
|
|
- Vector2::new(vx, vy)
|
52
|
|
-}
|
53
|
|
-
|
54
|
|
-fn grid_position_from_position(position: &Point2) -> GridPosition {
|
55
|
|
- GridPosition::new(
|
56
|
|
- (position.x / GRID_TILE_WIDTH) as i32,
|
57
|
|
- (position.y / GRID_TILE_HEIGHT) as i32,
|
58
|
|
- )
|
59
|
|
-}
|
60
|
|
-
|
61
|
|
-enum UiItem {
|
62
|
|
- SceneItemMenu,
|
63
|
|
-}
|
64
|
|
-
|
65
|
|
-enum SceneItemMenuItem {
|
66
|
|
- Move,
|
67
|
|
-}
|
68
|
|
-
|
69
|
|
-struct UiSpriteInfo {
|
70
|
|
- relative_start_x: f32,
|
71
|
|
- relative_start_y: f32,
|
72
|
|
- relative_width: f32,
|
73
|
|
- relative_height: f32,
|
74
|
|
- width: f32,
|
75
|
|
- height: f32,
|
76
|
|
-}
|
77
|
|
-
|
78
|
|
-impl UiSpriteInfo {
|
79
|
|
- pub fn from_type(type_: UiItem) -> Self {
|
80
|
|
- match type_ {
|
81
|
|
- UiItem::SceneItemMenu => Self {
|
82
|
|
- relative_start_x: 0.0,
|
83
|
|
- relative_start_y: 0.0,
|
84
|
|
- relative_width: 71.0 / UI_SPRITE_SHEET_WIDTH,
|
85
|
|
- relative_height: 68.0 / UI_SPRITE_SHEET_HEIGHT,
|
86
|
|
- width: 71.0,
|
87
|
|
- height: 68.0,
|
88
|
|
- },
|
89
|
|
- }
|
90
|
|
- }
|
91
|
|
-
|
92
|
|
- pub fn as_draw_param(&self) -> graphics::DrawParam {
|
93
|
|
- graphics::DrawParam::new().src(graphics::Rect::new(
|
94
|
|
- self.relative_start_x,
|
95
|
|
- self.relative_start_y,
|
96
|
|
- self.relative_width,
|
97
|
|
- self.relative_height,
|
98
|
|
- ))
|
99
|
|
- }
|
100
|
|
-
|
101
|
|
- pub fn which_item_clicked(
|
102
|
|
- &self,
|
103
|
|
- menu_position: Point2,
|
104
|
|
- click_position: Point2,
|
105
|
|
- scene_item: &SceneItem,
|
106
|
|
- ) -> Option<SceneItemMenuItem> {
|
107
|
|
- Some(SceneItemMenuItem::Move)
|
108
|
|
- }
|
109
|
|
-}
|
110
|
|
-
|
111
|
|
-struct SpriteInfo {
|
112
|
|
- relative_start_y: f32,
|
113
|
|
- relative_tile_width: f32,
|
114
|
|
- relative_tile_height: f32,
|
115
|
|
- tile_count: u16,
|
116
|
|
- tile_width: f32,
|
117
|
|
- tile_height: f32,
|
118
|
|
- _half_tile_width: f32,
|
119
|
|
- _half_tile_height: f32,
|
120
|
|
-}
|
121
|
|
-
|
122
|
|
-impl SpriteInfo {
|
123
|
|
- // TODO: ask on rust community if this is performant, or how to make it static
|
124
|
|
- pub fn from_type(type_: &SpriteType) -> Self {
|
125
|
|
- let (start_y, tile_width, tile_height, tile_count) = match type_ {
|
126
|
|
- SpriteType::WalkingSoldier => (12.0, 12.0, 12.0, 8),
|
127
|
|
- SpriteType::CrawlingSoldier => (26.0, 26.0, 26.0, 8),
|
128
|
|
- SpriteType::StandingSoldier => (0.0, 12.0, 12.0, 1),
|
129
|
|
- };
|
130
|
|
-
|
131
|
|
- Self {
|
132
|
|
- relative_start_y: start_y / SCENE_ITEMS_SPRITE_SHEET_HEIGHT,
|
133
|
|
- relative_tile_width: tile_width / SCENE_ITEMS_SPRITE_SHEET_WIDTH,
|
134
|
|
- relative_tile_height: tile_height / SCENE_ITEMS_SPRITE_SHEET_HEIGHT,
|
135
|
|
- tile_count,
|
136
|
|
- tile_width,
|
137
|
|
- tile_height,
|
138
|
|
- _half_tile_width: tile_width / 2.0,
|
139
|
|
- _half_tile_height: tile_height / 2.0,
|
140
|
|
- }
|
141
|
|
- }
|
142
|
|
-}
|
143
|
|
-
|
144
|
|
-enum SpriteType {
|
145
|
|
- WalkingSoldier,
|
146
|
|
- CrawlingSoldier,
|
147
|
|
- StandingSoldier,
|
148
|
|
-}
|
149
|
|
-
|
150
|
|
-enum ItemBehavior {
|
151
|
|
- Standing(u32), // since
|
152
|
|
- Crawling,
|
153
|
|
- Walking(Vector2),
|
154
|
|
-}
|
155
|
|
-
|
156
|
|
-struct ItemState {
|
157
|
|
- current_behavior: ItemBehavior,
|
158
|
|
-}
|
159
|
|
-
|
160
|
|
-enum SceneItemType {
|
161
|
|
- Soldier,
|
162
|
|
-}
|
163
|
|
-
|
164
|
|
-impl ItemState {
|
165
|
|
- pub fn new(current_behavior: ItemBehavior) -> Self {
|
166
|
|
- Self { current_behavior }
|
167
|
|
- }
|
168
|
|
-}
|
169
|
|
-
|
170
|
|
-struct SceneItem {
|
171
|
|
- type_: SceneItemType,
|
172
|
|
- position: Point2,
|
173
|
|
- grid_position: GridPosition,
|
174
|
|
- state: ItemState,
|
175
|
|
- meta_events: Vec<MetaEvent>,
|
176
|
|
- current_frame: u16,
|
177
|
|
-}
|
178
|
|
-
|
179
|
|
-impl SceneItem {
|
180
|
|
- pub fn new(type_: SceneItemType, position: Point2, state: ItemState) -> Self {
|
181
|
|
- Self {
|
182
|
|
- type_,
|
183
|
|
- position: position.clone(),
|
184
|
|
- grid_position: grid_position_from_position(&position.clone()),
|
185
|
|
- state,
|
186
|
|
- meta_events: vec![],
|
187
|
|
- current_frame: 0,
|
188
|
|
- }
|
189
|
|
- }
|
190
|
|
-
|
191
|
|
- pub fn sprite_info(&self) -> SpriteInfo {
|
192
|
|
- SpriteInfo::from_type(&self.sprite_type())
|
193
|
|
- }
|
194
|
|
-
|
195
|
|
- pub fn tick_sprite(&mut self) {
|
196
|
|
- self.current_frame += 1;
|
197
|
|
- // TODO: good way to have sprite info ? performant ?
|
198
|
|
- if self.current_frame >= self.sprite_info().tile_count {
|
199
|
|
- self.current_frame = 0;
|
200
|
|
- }
|
201
|
|
- }
|
202
|
|
-
|
203
|
|
- pub fn as_draw_param(&self, current_frame: f32) -> graphics::DrawParam {
|
204
|
|
- let sprite_info = self.sprite_info();
|
205
|
|
- graphics::DrawParam::new()
|
206
|
|
- .src(graphics::Rect::new(
|
207
|
|
- current_frame as f32 * sprite_info.relative_tile_width,
|
208
|
|
- sprite_info.relative_start_y,
|
209
|
|
- sprite_info.relative_tile_width,
|
210
|
|
- sprite_info.relative_tile_height,
|
211
|
|
- ))
|
212
|
|
- .rotation(90.0f32.to_radians())
|
213
|
|
- .offset(Point2::new(0.5, 0.5))
|
214
|
|
- }
|
215
|
|
-
|
216
|
|
- pub fn sprite_type(&self) -> SpriteType {
|
217
|
|
- // Here some logical about state, nature (soldier, tank, ...) and current behavior to
|
218
|
|
- // determine sprite type
|
219
|
|
- match self.state.current_behavior {
|
220
|
|
- ItemBehavior::Crawling => SpriteType::CrawlingSoldier,
|
221
|
|
- ItemBehavior::Walking(_) => SpriteType::WalkingSoldier,
|
222
|
|
- ItemBehavior::Standing(_) => SpriteType::StandingSoldier,
|
223
|
|
- }
|
224
|
|
- }
|
225
|
|
-}
|
226
|
|
-
|
227
|
|
-#[derive(Debug)]
|
228
|
|
-enum PhysicEvent {
|
229
|
|
- Explosion,
|
230
|
|
-}
|
231
|
|
-
|
232
|
|
-#[derive(Debug)]
|
233
|
|
-enum MetaEvent {
|
234
|
|
- FearAboutExplosion,
|
235
|
|
-}
|
236
|
|
-
|
237
|
|
-#[derive(Debug)]
|
238
|
|
-enum UserEvent {
|
239
|
|
- Click(Point2), // Window coordinates
|
240
|
|
- RightClick(Point2), // Window coordinates
|
241
|
|
- AreaSelection(Point2, Point2), // Window coordinates
|
242
|
|
-}
|
243
|
|
-
|
244
|
|
-enum SceneItemPrepareOrder {
|
245
|
|
- Move(usize), // scene_item usize
|
246
|
|
-}
|
247
|
|
-
|
248
|
|
-struct MainState {
|
249
|
|
- // time
|
250
|
|
- frame_i: u32,
|
251
|
|
-
|
252
|
|
- // display
|
253
|
|
- display_offset: Point2,
|
254
|
|
- sprite_sheet_batch: graphics::spritebatch::SpriteBatch,
|
255
|
|
- map_batch: graphics::spritebatch::SpriteBatch,
|
256
|
|
- ui_batch: graphics::spritebatch::SpriteBatch,
|
257
|
|
-
|
258
|
|
- // scene items
|
259
|
|
- scene_items: Vec<SceneItem>,
|
260
|
|
- scene_items_by_grid_position: HashMap<GridPosition, Vec<usize>>,
|
261
|
|
-
|
262
|
|
- // events
|
263
|
|
- physics_events: Vec<PhysicEvent>,
|
264
|
|
-
|
265
|
|
- // user interactions
|
266
|
|
- left_click_down: Option<Point2>,
|
267
|
|
- right_click_down: Option<Point2>,
|
268
|
|
- current_cursor_position: Point2,
|
269
|
|
- user_events: Vec<UserEvent>,
|
270
|
|
- selected_scene_items: Vec<usize>, // scene_item usize
|
271
|
|
- scene_item_menu: Option<(usize, Point2)>, // scene_item usize, display_at
|
272
|
|
- scene_item_prepare_order: Option<SceneItemPrepareOrder>,
|
273
|
|
-}
|
274
|
|
-
|
275
|
|
-impl MainState {
|
276
|
|
- fn new(ctx: &mut Context) -> GameResult<MainState> {
|
277
|
|
- let sprite_sheet = graphics::Image::new(ctx, "/sprite_sheet.png").unwrap();
|
278
|
|
- let sprite_sheet_batch = graphics::spritebatch::SpriteBatch::new(sprite_sheet);
|
279
|
|
- let map = graphics::Image::new(ctx, "/map1bg.png").unwrap();
|
280
|
|
- let map_batch = graphics::spritebatch::SpriteBatch::new(map);
|
281
|
|
- let ui = graphics::Image::new(ctx, "/ui.png").unwrap();
|
282
|
|
- let ui_batch = graphics::spritebatch::SpriteBatch::new(ui);
|
283
|
|
-
|
284
|
|
- let mut scene_items = vec![];
|
285
|
|
- for x in 0..1 {
|
286
|
|
- for y in 0..4 {
|
287
|
|
- let current_behavior = if y % 2 == 0 {
|
288
|
|
- ItemBehavior::Walking(vec_from_angle(90.0))
|
289
|
|
- } else {
|
290
|
|
- ItemBehavior::Crawling
|
291
|
|
- };
|
292
|
|
-
|
293
|
|
- scene_items.push(SceneItem::new(
|
294
|
|
- SceneItemType::Soldier,
|
295
|
|
- Point2::new((x as f32 * 24.0) + 100.0, (y as f32 * 24.0) + 100.0),
|
296
|
|
- ItemState::new(current_behavior),
|
297
|
|
- ));
|
298
|
|
- }
|
299
|
|
- }
|
300
|
|
-
|
301
|
|
- let mut main_state = MainState {
|
302
|
|
- frame_i: 0,
|
303
|
|
- display_offset: Point2::new(0.0, 0.0),
|
304
|
|
- sprite_sheet_batch,
|
305
|
|
- map_batch,
|
306
|
|
- ui_batch,
|
307
|
|
- scene_items,
|
308
|
|
- scene_items_by_grid_position: HashMap::new(),
|
309
|
|
- physics_events: vec![],
|
310
|
|
- left_click_down: None,
|
311
|
|
- right_click_down: None,
|
312
|
|
- current_cursor_position: Point2::new(0.0, 0.0),
|
313
|
|
- user_events: vec![],
|
314
|
|
- selected_scene_items: vec![],
|
315
|
|
- scene_item_menu: None,
|
316
|
|
- scene_item_prepare_order: None,
|
317
|
|
- };
|
318
|
|
-
|
319
|
|
- for (i, scene_item) in main_state.scene_items.iter().enumerate() {
|
320
|
|
- let grid_position = grid_position_from_position(&scene_item.position);
|
321
|
|
- main_state
|
322
|
|
- .scene_items_by_grid_position
|
323
|
|
- .entry(grid_position)
|
324
|
|
- .or_default()
|
325
|
|
- .push(i);
|
326
|
|
- }
|
327
|
|
-
|
328
|
|
- Ok(main_state)
|
329
|
|
- }
|
330
|
|
-
|
331
|
|
- fn inputs(&mut self, ctx: &Context) {
|
332
|
|
- let display_offset_by =
|
333
|
|
- if input::keyboard::is_mod_active(ctx, input::keyboard::KeyMods::SHIFT) {
|
334
|
|
- DISPLAY_OFFSET_BY_SPEED
|
335
|
|
- } else {
|
336
|
|
- DISPLAY_OFFSET_BY
|
337
|
|
- };
|
338
|
|
-
|
339
|
|
- if input::keyboard::is_key_pressed(ctx, KeyCode::Left) {
|
340
|
|
- self.display_offset.x += display_offset_by;
|
341
|
|
- }
|
342
|
|
- if input::keyboard::is_key_pressed(ctx, KeyCode::Right) {
|
343
|
|
- self.display_offset.x -= display_offset_by;
|
344
|
|
- }
|
345
|
|
- if input::keyboard::is_key_pressed(ctx, KeyCode::Up) {
|
346
|
|
- self.display_offset.y += display_offset_by;
|
347
|
|
- }
|
348
|
|
- if input::keyboard::is_key_pressed(ctx, KeyCode::Down) {
|
349
|
|
- self.display_offset.y -= display_offset_by;
|
350
|
|
- }
|
351
|
|
-
|
352
|
|
- while let Some(user_event) = self.user_events.pop() {
|
353
|
|
- match user_event {
|
354
|
|
- UserEvent::Click(click_position) => {
|
355
|
|
- let scene_position = Point2::new(
|
356
|
|
- click_position.x - self.display_offset.x,
|
357
|
|
- click_position.y - self.display_offset.y,
|
358
|
|
- );
|
359
|
|
- self.selected_scene_items.drain(..);
|
360
|
|
- if let Some(scene_item_usize) =
|
361
|
|
- self.get_first_scene_item_for_position(&scene_position)
|
362
|
|
- {
|
363
|
|
- self.selected_scene_items.push(scene_item_usize);
|
364
|
|
- }
|
365
|
|
-
|
366
|
|
- if let Some(scene_item_prepare_order) = &self.scene_item_prepare_order {
|
367
|
|
- // TODO: Add order to scene_item
|
368
|
|
- self.scene_item_prepare_order = None;
|
369
|
|
- }
|
370
|
|
-
|
371
|
|
- // FIXME BS NOW: interpreter sur quel element du menu on a click ...
|
372
|
|
- if let Some((scene_item_usize, menu_position)) = self.scene_item_menu {
|
373
|
|
- let menu_sprite_info = UiSpriteInfo::from_type(UiItem::SceneItemMenu);
|
374
|
|
- let scene_item = self
|
375
|
|
- .scene_items
|
376
|
|
- .get(scene_item_usize)
|
377
|
|
- .expect(SCENE_ITEMS_CHANGE_ERR_MSG);
|
378
|
|
- if click_position.x >= menu_position.x
|
379
|
|
- && click_position.x <= menu_position.x + menu_sprite_info.width
|
380
|
|
- && click_position.y >= menu_position.y
|
381
|
|
- && click_position.y <= menu_position.y + menu_sprite_info.height
|
382
|
|
- {
|
383
|
|
- if let Some(menu_item) = menu_sprite_info.which_item_clicked(
|
384
|
|
- menu_position,
|
385
|
|
- click_position,
|
386
|
|
- scene_item,
|
387
|
|
- ) {
|
388
|
|
- match menu_item {
|
389
|
|
- SceneItemMenuItem::Move => {
|
390
|
|
- self.scene_item_prepare_order =
|
391
|
|
- Some(SceneItemPrepareOrder::Move(scene_item_usize));
|
392
|
|
- self.scene_item_menu = None;
|
393
|
|
- }
|
394
|
|
- }
|
395
|
|
- }
|
396
|
|
- } else {
|
397
|
|
- self.scene_item_menu = None;
|
398
|
|
- }
|
399
|
|
- };
|
400
|
|
- }
|
401
|
|
- UserEvent::AreaSelection(from, to) => {
|
402
|
|
- let scene_from = Point2::new(
|
403
|
|
- from.x - self.display_offset.x,
|
404
|
|
- from.y - self.display_offset.y,
|
405
|
|
- );
|
406
|
|
- let scene_to =
|
407
|
|
- Point2::new(to.x - self.display_offset.x, to.y - self.display_offset.y);
|
408
|
|
- self.selected_scene_items.drain(..);
|
409
|
|
- self.selected_scene_items
|
410
|
|
- .extend(self.get_scene_items_for_area(&scene_from, &scene_to));
|
411
|
|
- }
|
412
|
|
- UserEvent::RightClick(position) => {
|
413
|
|
- if let Some(scene_item_usize) =
|
414
|
|
- self.get_first_scene_item_for_position(&position)
|
415
|
|
- {
|
416
|
|
- if self.selected_scene_items.contains(&scene_item_usize) {
|
417
|
|
- let scene_item = self
|
418
|
|
- .scene_items
|
419
|
|
- .get(scene_item_usize)
|
420
|
|
- .expect(SCENE_ITEMS_CHANGE_ERR_MSG);
|
421
|
|
- self.scene_item_menu =
|
422
|
|
- Some((scene_item_usize, scene_item.position.clone()))
|
423
|
|
- }
|
424
|
|
- }
|
425
|
|
- }
|
426
|
|
- }
|
427
|
|
- }
|
428
|
|
- }
|
429
|
|
-
|
430
|
|
- // TODO: manage errors
|
431
|
|
- fn physics(&mut self) {
|
432
|
|
- // Scene items movements
|
433
|
|
- for scene_item in self.scene_items.iter_mut() {
|
434
|
|
- match scene_item.state.current_behavior {
|
435
|
|
- ItemBehavior::Walking(vector) => {
|
436
|
|
- // TODO ici il faut calculer le déplacement réél (en fonction des ticks, etc ...)
|
437
|
|
- scene_item.position.x += 1.0;
|
438
|
|
- scene_item.grid_position = grid_position_from_position(&scene_item.position);
|
439
|
|
- }
|
440
|
|
- _ => {}
|
441
|
|
- }
|
442
|
|
- }
|
443
|
|
-
|
444
|
|
- // (FAKE) Drop a bomb to motivate stop move
|
445
|
|
- if self.frame_i % 600 == 0 && self.frame_i != 0 {
|
446
|
|
- self.physics_events.push(PhysicEvent::Explosion);
|
447
|
|
- }
|
448
|
|
- }
|
449
|
|
-
|
450
|
|
- fn metas(&mut self) {
|
451
|
|
- for physic_event in &self.physics_events {
|
452
|
|
- match physic_event {
|
453
|
|
- PhysicEvent::Explosion => {
|
454
|
|
- for scene_item in self.scene_items.iter_mut() {
|
455
|
|
- scene_item.meta_events.push(MetaEvent::FearAboutExplosion);
|
456
|
|
- }
|
457
|
|
- }
|
458
|
|
- }
|
459
|
|
- }
|
460
|
|
- }
|
461
|
|
-
|
462
|
|
- fn animate(&mut self) {
|
463
|
|
- // TODO: ici il faut reflechir a comment organiser les comportements
|
464
|
|
-
|
465
|
|
- for scene_item in self.scene_items.iter_mut() {
|
466
|
|
- for meta_event in &scene_item.meta_events {
|
467
|
|
- match meta_event {
|
468
|
|
- MetaEvent::FearAboutExplosion => {
|
469
|
|
- scene_item.state = ItemState::new(ItemBehavior::Standing(self.frame_i));
|
470
|
|
- }
|
471
|
|
- }
|
472
|
|
- }
|
473
|
|
-
|
474
|
|
- match scene_item.state.current_behavior {
|
475
|
|
- ItemBehavior::Crawling => {
|
476
|
|
- scene_item.state = ItemState::new(ItemBehavior::Walking(vec_from_angle(90.0)));
|
477
|
|
- }
|
478
|
|
- ItemBehavior::Walking(_) => {
|
479
|
|
- scene_item.state = ItemState::new(ItemBehavior::Crawling);
|
480
|
|
- }
|
481
|
|
- ItemBehavior::Standing(since) => {
|
482
|
|
- if self.frame_i - since >= 120 {
|
483
|
|
- scene_item.state =
|
484
|
|
- ItemState::new(ItemBehavior::Walking(vec_from_angle(90.0)));
|
485
|
|
- }
|
486
|
|
- }
|
487
|
|
- }
|
488
|
|
-
|
489
|
|
- scene_item.meta_events.drain(..);
|
490
|
|
- }
|
491
|
|
- }
|
492
|
|
-
|
493
|
|
- fn tick_sprites(&mut self) {
|
494
|
|
- for scene_item in self.scene_items.iter_mut() {
|
495
|
|
- scene_item.tick_sprite();
|
496
|
|
- }
|
497
|
|
- }
|
498
|
|
-
|
499
|
|
- fn position_with_display_offset(&self, position: &Point2) -> Point2 {
|
500
|
|
- Point2::new(
|
501
|
|
- position.x + self.display_offset.x,
|
502
|
|
- position.y + self.display_offset.y,
|
503
|
|
- )
|
504
|
|
- }
|
505
|
|
-
|
506
|
|
- fn get_first_scene_item_for_position(&self, position: &Point2) -> Option<usize> {
|
507
|
|
- // TODO: if found multiple: select nearest
|
508
|
|
- for (i, scene_item) in self.scene_items.iter().enumerate() {
|
509
|
|
- let sprite_info = scene_item.sprite_info();
|
510
|
|
- if scene_item.position.x >= position.x - sprite_info.tile_width
|
511
|
|
- && scene_item.position.x <= position.x + sprite_info.tile_width
|
512
|
|
- && scene_item.position.y >= position.y - sprite_info.tile_height
|
513
|
|
- && scene_item.position.y <= position.y + sprite_info.tile_height
|
514
|
|
- {
|
515
|
|
- return Some(i);
|
516
|
|
- }
|
517
|
|
- }
|
518
|
|
-
|
519
|
|
- None
|
520
|
|
- }
|
521
|
|
-
|
522
|
|
- fn get_scene_items_for_area(&self, from: &Point2, to: &Point2) -> Vec<usize> {
|
523
|
|
- let mut selection = vec![];
|
524
|
|
-
|
525
|
|
- for (i, scene_item) in self.scene_items.iter().enumerate() {
|
526
|
|
- if scene_item.position.x >= from.x
|
527
|
|
- && scene_item.position.x <= to.x
|
528
|
|
- && scene_item.position.y >= from.y
|
529
|
|
- && scene_item.position.y <= to.y
|
530
|
|
- {
|
531
|
|
- selection.push(i);
|
532
|
|
- }
|
533
|
|
- }
|
534
|
|
-
|
535
|
|
- selection
|
536
|
|
- }
|
537
|
|
-}
|
538
|
|
-
|
539
|
|
-impl event::EventHandler for MainState {
|
540
|
|
- fn update(&mut self, ctx: &mut Context) -> GameResult {
|
541
|
|
- while check_update_time(ctx, TARGET_FPS) {
|
542
|
|
- self.inputs(ctx);
|
543
|
|
-
|
544
|
|
- // TODO: meta: calculer par ex qui voit qui (soldat voit un ennemi: ajouter l'event a vu
|
545
|
|
- // ennemi, dans animate il se mettra a tirer)
|
546
|
|
- let tick_sprite = self.frame_i % SPRITE_EACH == 0;
|
547
|
|
- let tick_animate = self.frame_i % ANIMATE_EACH == 0;
|
548
|
|
- let tick_physics = self.frame_i % PHYSICS_EACH == 0;
|
549
|
|
- let tick_meta = self.frame_i % META_EACH == 0;
|
550
|
|
-
|
551
|
|
- // Apply moves, explosions, etc
|
552
|
|
- if tick_physics {
|
553
|
|
- self.physics();
|
554
|
|
- }
|
555
|
|
-
|
556
|
|
- // Generate meta events according to physics events and current physic state
|
557
|
|
- if tick_meta {
|
558
|
|
- self.metas();
|
559
|
|
- }
|
560
|
|
-
|
561
|
|
- // Animate scene items according to meta events
|
562
|
|
- if tick_animate {
|
563
|
|
- self.animate();
|
564
|
|
- };
|
565
|
|
-
|
566
|
|
- // Change scene items tiles
|
567
|
|
- if tick_sprite {
|
568
|
|
- self.tick_sprites();
|
569
|
|
- }
|
570
|
|
-
|
571
|
|
- // Increment frame counter
|
572
|
|
- self.frame_i += 1;
|
573
|
|
- if self.frame_i >= MAX_FRAME_I {
|
574
|
|
- self.frame_i = 0;
|
575
|
|
- }
|
576
|
|
-
|
577
|
|
- // Empty physics event
|
578
|
|
- self.physics_events.drain(..);
|
579
|
|
- }
|
580
|
|
-
|
581
|
|
- Ok(())
|
582
|
|
- }
|
583
|
|
-
|
584
|
|
- fn draw(&mut self, ctx: &mut Context) -> GameResult {
|
585
|
|
- graphics::clear(ctx, graphics::BLACK);
|
586
|
|
-
|
587
|
|
- let mut scene_mesh_builder = MeshBuilder::new();
|
588
|
|
-
|
589
|
|
- for scene_item in self.scene_items.iter() {
|
590
|
|
- self.sprite_sheet_batch.add(
|
591
|
|
- scene_item
|
592
|
|
- .as_draw_param(scene_item.current_frame as f32)
|
593
|
|
- .dest(scene_item.position.clone()),
|
594
|
|
- );
|
595
|
|
- scene_mesh_builder.circle(
|
596
|
|
- DrawMode::fill(),
|
597
|
|
- scene_item.position.clone(),
|
598
|
|
- 2.0,
|
599
|
|
- 2.0,
|
600
|
|
- graphics::WHITE,
|
601
|
|
- )?;
|
602
|
|
- }
|
603
|
|
-
|
604
|
|
- for i in &self.selected_scene_items {
|
605
|
|
- let selected_scene_item = self.scene_items.get(*i).expect(SCENE_ITEMS_CHANGE_ERR_MSG);
|
606
|
|
- scene_mesh_builder.rectangle(
|
607
|
|
- DrawMode::Stroke(StrokeOptions::default()),
|
608
|
|
- graphics::Rect::new(
|
609
|
|
- selected_scene_item.position.x - DEFAULT_SELECTED_SQUARE_SIDE_HALF,
|
610
|
|
- selected_scene_item.position.y - DEFAULT_SELECTED_SQUARE_SIDE_HALF,
|
611
|
|
- DEFAULT_SELECTED_SQUARE_SIDE,
|
612
|
|
- DEFAULT_SELECTED_SQUARE_SIDE,
|
613
|
|
- ),
|
614
|
|
- graphics::GREEN,
|
615
|
|
- )?;
|
616
|
|
- }
|
617
|
|
-
|
618
|
|
- if let Some(left_click_down) = self.left_click_down {
|
619
|
|
- if left_click_down != self.current_cursor_position {
|
620
|
|
- scene_mesh_builder.rectangle(
|
621
|
|
- DrawMode::fill(),
|
622
|
|
- graphics::Rect::new(
|
623
|
|
- left_click_down.x - self.display_offset.x,
|
624
|
|
- left_click_down.y - self.display_offset.y,
|
625
|
|
- self.current_cursor_position.x - left_click_down.x,
|
626
|
|
- self.current_cursor_position.y - left_click_down.y,
|
627
|
|
- ),
|
628
|
|
- graphics::GREEN,
|
629
|
|
- )?;
|
630
|
|
- }
|
631
|
|
-
|
632
|
|
- scene_mesh_builder.circle(
|
633
|
|
- DrawMode::fill(),
|
634
|
|
- left_click_down,
|
635
|
|
- 2.0,
|
636
|
|
- 2.0,
|
637
|
|
- graphics::YELLOW,
|
638
|
|
- )?;
|
639
|
|
- }
|
640
|
|
-
|
641
|
|
- if let Some((_, position)) = self.scene_item_menu {
|
642
|
|
- self.ui_batch.add(
|
643
|
|
- UiSpriteInfo::from_type(UiItem::SceneItemMenu)
|
644
|
|
- .as_draw_param()
|
645
|
|
- .dest(position),
|
646
|
|
- );
|
647
|
|
- }
|
648
|
|
-
|
649
|
|
- if let Some(scene_item_prepare_order) = &self.scene_item_prepare_order {
|
650
|
|
- match scene_item_prepare_order {
|
651
|
|
- SceneItemPrepareOrder::Move(scene_item_usize) => {
|
652
|
|
- let scene_item = self
|
653
|
|
- .scene_items
|
654
|
|
- .get(*scene_item_usize)
|
655
|
|
- .expect(SCENE_ITEMS_CHANGE_ERR_MSG);
|
656
|
|
- scene_mesh_builder.line(
|
657
|
|
- &vec![scene_item.position.clone(), self.current_cursor_position],
|
658
|
|
- 2.0,
|
659
|
|
- graphics::WHITE,
|
660
|
|
- )?;
|
661
|
|
- }
|
662
|
|
- }
|
663
|
|
- }
|
664
|
|
-
|
665
|
|
- self.map_batch.add(
|
666
|
|
- graphics::DrawParam::new()
|
667
|
|
- .src(graphics::Rect::new(0.0, 0.0, 1.0, 1.0))
|
668
|
|
- .dest(Point2::new(0.0, 0.0)),
|
669
|
|
- );
|
670
|
|
-
|
671
|
|
- let scene_mesh = scene_mesh_builder.build(ctx)?;
|
672
|
|
- graphics::draw(
|
673
|
|
- ctx,
|
674
|
|
- &self.map_batch,
|
675
|
|
- graphics::DrawParam::new()
|
676
|
|
- .dest(self.position_with_display_offset(&Point2::new(0.0, 0.0))),
|
677
|
|
- )?;
|
678
|
|
- graphics::draw(
|
679
|
|
- ctx,
|
680
|
|
- &self.sprite_sheet_batch,
|
681
|
|
- graphics::DrawParam::new()
|
682
|
|
- .dest(self.position_with_display_offset(&Point2::new(0.0, 0.0))),
|
683
|
|
- )?;
|
684
|
|
- graphics::draw(
|
685
|
|
- ctx,
|
686
|
|
- &scene_mesh,
|
687
|
|
- graphics::DrawParam::new()
|
688
|
|
- .dest(self.position_with_display_offset(&Point2::new(0.0, 0.0))),
|
689
|
|
- )?;
|
690
|
|
- graphics::draw(
|
691
|
|
- ctx,
|
692
|
|
- &self.ui_batch,
|
693
|
|
- graphics::DrawParam::new()
|
694
|
|
- .dest(self.position_with_display_offset(&Point2::new(0.0, 0.0))),
|
695
|
|
- )?;
|
696
|
|
-
|
697
|
|
- self.sprite_sheet_batch.clear();
|
698
|
|
- self.map_batch.clear();
|
699
|
|
- self.ui_batch.clear();
|
700
|
|
- graphics::present(ctx)?;
|
701
|
|
-
|
702
|
|
- println!("FPS: {}", ggez::timer::fps(ctx));
|
703
|
|
- Ok(())
|
704
|
|
- }
|
705
|
|
-
|
706
|
|
- fn mouse_button_down_event(&mut self, _ctx: &mut Context, button: MouseButton, x: f32, y: f32) {
|
707
|
|
- match button {
|
708
|
|
- MouseButton::Left => {
|
709
|
|
- self.left_click_down = Some(Point2::new(x, y));
|
710
|
|
- }
|
711
|
|
- MouseButton::Right => {
|
712
|
|
- self.right_click_down = Some(Point2::new(x, y));
|
713
|
|
- }
|
714
|
|
- MouseButton::Middle => {}
|
715
|
|
- MouseButton::Other(_) => {}
|
716
|
|
- }
|
717
|
|
- }
|
718
|
|
-
|
719
|
|
- fn mouse_button_up_event(&mut self, _ctx: &mut Context, button: MouseButton, x: f32, y: f32) {
|
720
|
|
- match button {
|
721
|
|
- MouseButton::Left => {
|
722
|
|
- if let Some(left_click_down) = self.left_click_down {
|
723
|
|
- if left_click_down == Point2::new(x, y) {
|
724
|
|
- self.user_events.push(UserEvent::Click(left_click_down));
|
725
|
|
- } else {
|
726
|
|
- let from = Point2::new(
|
727
|
|
- cmp::min(left_click_down.x as i32, x as i32) as f32,
|
728
|
|
- cmp::min(left_click_down.y as i32, y as i32) as f32,
|
729
|
|
- );
|
730
|
|
- let to = Point2::new(
|
731
|
|
- cmp::max(left_click_down.x as i32, x as i32) as f32,
|
732
|
|
- cmp::max(left_click_down.y as i32, y as i32) as f32,
|
733
|
|
- );
|
734
|
|
- self.user_events.push(UserEvent::AreaSelection(from, to));
|
735
|
|
- }
|
736
|
|
- }
|
737
|
|
- self.left_click_down = None;
|
738
|
|
- }
|
739
|
|
- MouseButton::Right => {
|
740
|
|
- if let Some(right_click_down) = self.right_click_down {
|
741
|
|
- self.user_events
|
742
|
|
- .push(UserEvent::RightClick(right_click_down));
|
743
|
|
- }
|
744
|
|
- }
|
745
|
|
- MouseButton::Middle => {}
|
746
|
|
- MouseButton::Other(_) => {}
|
747
|
|
- }
|
748
|
|
- }
|
749
|
|
-
|
750
|
|
- fn mouse_motion_event(&mut self, _ctx: &mut Context, x: f32, y: f32, _dx: f32, _dy: f32) {
|
751
|
|
- self.current_cursor_position = Point2::new(x, y);
|
752
|
|
- }
|
753
|
|
-}
|
754
|
|
-
|
755
|
52
|
pub fn main() -> GameResult {
|
756
|
53
|
let resource_dir = if let Ok(manifest_dir) = env::var("CARGO_MANIFEST_DIR") {
|
757
|
54
|
let mut path = path::PathBuf::from(manifest_dir);
|