item.rs 4.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. use ggez::graphics;
  2. use crate::behavior::order::Order;
  3. use crate::behavior::ItemBehavior;
  4. use crate::config::{SCENE_ITEMS_SPRITE_SHEET_HEIGHT, SCENE_ITEMS_SPRITE_SHEET_WIDTH};
  5. use crate::map::Map;
  6. use crate::physics::GridPosition;
  7. use crate::physics::{util, MetaEvent};
  8. use crate::scene::SpriteType;
  9. use crate::{Offset, ScenePoint};
  10. pub struct SceneItemSpriteInfo {
  11. pub relative_start_y: f32,
  12. pub relative_tile_width: f32,
  13. pub relative_tile_height: f32,
  14. pub tile_count: u16,
  15. pub tile_width: f32,
  16. pub tile_height: f32,
  17. pub _half_tile_width: f32,
  18. pub _half_tile_height: f32,
  19. pub tick_speed: f32,
  20. }
  21. impl SceneItemSpriteInfo {
  22. // TODO: ask on rust community if this is performant, or how to make it static
  23. pub fn from_type(type_: &SpriteType) -> Self {
  24. let (start_y, tile_width, tile_height, tile_count, tick_speed) = match type_ {
  25. SpriteType::WalkingSoldier => (12.0, 12.0, 12.0, 8, 0.5),
  26. SpriteType::CrawlingSoldier => (26.0, 26.0, 26.0, 8, 1.0),
  27. SpriteType::StandingSoldier => (0.0, 12.0, 12.0, 1, 0.0),
  28. };
  29. Self {
  30. relative_start_y: start_y / SCENE_ITEMS_SPRITE_SHEET_HEIGHT,
  31. relative_tile_width: tile_width / SCENE_ITEMS_SPRITE_SHEET_WIDTH,
  32. relative_tile_height: tile_height / SCENE_ITEMS_SPRITE_SHEET_HEIGHT,
  33. tile_count,
  34. tile_width,
  35. tile_height,
  36. _half_tile_width: tile_width / 2.0,
  37. _half_tile_height: tile_height / 2.0,
  38. tick_speed,
  39. }
  40. }
  41. }
  42. pub struct ItemState {
  43. pub current_behavior: ItemBehavior,
  44. }
  45. impl ItemState {
  46. pub fn new(current_behavior: ItemBehavior) -> Self {
  47. Self { current_behavior }
  48. }
  49. }
  50. pub enum SceneItemType {
  51. Soldier,
  52. }
  53. pub struct SceneItem {
  54. pub type_: SceneItemType,
  55. pub position: ScenePoint,
  56. pub grid_position: GridPosition,
  57. pub state: ItemState,
  58. pub meta_events: Vec<MetaEvent>,
  59. pub current_frame: f32,
  60. pub current_order: Option<Order>,
  61. pub next_order: Option<Order>,
  62. pub display_angle: f32,
  63. }
  64. impl SceneItem {
  65. pub fn new(type_: SceneItemType, position: ScenePoint, state: ItemState, map: &Map) -> Self {
  66. Self {
  67. type_,
  68. position: position.clone(),
  69. grid_position: util::grid_position_from_scene_point(&position.clone(), map),
  70. state,
  71. meta_events: vec![],
  72. current_frame: 0.0,
  73. current_order: None,
  74. next_order: None,
  75. display_angle: 0.0,
  76. }
  77. }
  78. pub fn sprite_info(&self) -> SceneItemSpriteInfo {
  79. SceneItemSpriteInfo::from_type(&self.sprite_type())
  80. }
  81. pub fn tick_sprite(&mut self) {
  82. let sprite_info = self.sprite_info();
  83. self.current_frame += sprite_info.tick_speed;
  84. // TODO: good way to have sprite info ? performant ?
  85. if self.current_frame as u16 >= sprite_info.tile_count {
  86. self.current_frame = 0.0;
  87. }
  88. }
  89. pub fn as_draw_param(&self, current_frame: f32) -> graphics::DrawParam {
  90. let sprite_info = self.sprite_info();
  91. graphics::DrawParam::new()
  92. .src(graphics::Rect::new(
  93. (current_frame as u16) as f32 * sprite_info.relative_tile_width,
  94. sprite_info.relative_start_y,
  95. sprite_info.relative_tile_width,
  96. sprite_info.relative_tile_height,
  97. ))
  98. .rotation(self.display_angle)
  99. .offset(Offset::new(0.5, 0.5))
  100. }
  101. pub fn sprite_type(&self) -> SpriteType {
  102. // Here some logical about state, nature (soldier, tank, ...) and current behavior to
  103. // determine sprite type
  104. match self.state.current_behavior {
  105. ItemBehavior::HideTo(_) => SpriteType::CrawlingSoldier,
  106. ItemBehavior::MoveTo(_) => SpriteType::WalkingSoldier,
  107. ItemBehavior::MoveFastTo(_) => SpriteType::WalkingSoldier,
  108. ItemBehavior::Standing => SpriteType::StandingSoldier,
  109. }
  110. }
  111. }
  112. pub enum SceneItemModifier {
  113. SwitchToNextOrder,
  114. ChangeDisplayAngle(f32),
  115. ChangeState(ItemState),
  116. }
  117. pub fn apply_scene_item_modifier(scene_item: &mut SceneItem, modifiers: Vec<SceneItemModifier>) {
  118. for modifier in modifiers {
  119. match modifier {
  120. SceneItemModifier::SwitchToNextOrder => {
  121. let next_order = scene_item.next_order.clone();
  122. scene_item.current_order = next_order;
  123. scene_item.next_order = None;
  124. }
  125. SceneItemModifier::ChangeDisplayAngle(new_angle) => {
  126. scene_item.display_angle = new_angle;
  127. }
  128. SceneItemModifier::ChangeState(new_state) => {
  129. scene_item.state = new_state;
  130. }
  131. }
  132. }
  133. }