main.rs 5.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. use ggez;
  2. use ggez::event;
  3. use ggez::graphics;
  4. use ggez::nalgebra as na;
  5. use ggez::timer::check_update_time;
  6. use ggez::{Context, GameResult};
  7. use std::env;
  8. use std::path;
  9. const TARGET_ANIMATION_FPS: u32 = 10;
  10. struct SpriteInfo {
  11. relative_start_y: f32,
  12. relative_tile_width: f32,
  13. relative_tile_height: f32,
  14. tile_count: u16,
  15. current_frame: u16,
  16. }
  17. impl SpriteInfo {
  18. pub fn new(
  19. relative_start_y: f32,
  20. relative_tile_width: f32,
  21. relative_tile_height: f32,
  22. tile_count: u16,
  23. ) -> Self {
  24. Self {
  25. relative_start_y,
  26. relative_tile_width,
  27. relative_tile_height,
  28. tile_count,
  29. current_frame: 0,
  30. }
  31. }
  32. pub fn from_type(
  33. type_: &SpriteType,
  34. sprite_sheet_width: f32,
  35. sprite_sheet_height: f32,
  36. ) -> Self {
  37. let (start_y, tile_width, tile_height, tile_count) = match type_ {
  38. SpriteType::WalkingSoldier => (0.0, 24.0, 24.0, 7),
  39. SpriteType::JumpingSoldier => (24.0, 24.0, 24.0, 2),
  40. };
  41. Self {
  42. relative_start_y: start_y / sprite_sheet_height,
  43. relative_tile_width: tile_width / sprite_sheet_width,
  44. relative_tile_height: tile_height / sprite_sheet_height,
  45. tile_count,
  46. current_frame: 0,
  47. }
  48. }
  49. }
  50. enum SpriteType {
  51. WalkingSoldier,
  52. JumpingSoldier,
  53. }
  54. fn sprite_batch_part_from_sprite_info(sprite_info: &SpriteInfo) -> graphics::DrawParam {
  55. let src = graphics::Rect::new(
  56. sprite_info.current_frame as f32 * sprite_info.relative_tile_width,
  57. sprite_info.relative_start_y,
  58. sprite_info.relative_tile_width,
  59. sprite_info.relative_tile_height,
  60. );
  61. graphics::DrawParam::new().src(src)
  62. }
  63. struct SceneItem {
  64. sprite_info: SpriteInfo,
  65. position: na::Point2<f32>,
  66. }
  67. impl SceneItem {
  68. pub fn new(
  69. sprite_type: SpriteType,
  70. position: na::Point2<f32>,
  71. sprite_sheet_width: f32,
  72. sprite_sheet_height: f32,
  73. ) -> Self {
  74. Self {
  75. sprite_info: SpriteInfo::from_type(
  76. &sprite_type,
  77. sprite_sheet_width,
  78. sprite_sheet_height,
  79. ),
  80. position,
  81. }
  82. }
  83. pub fn tick_frame(&mut self) {
  84. self.sprite_info.current_frame += 1;
  85. if self.sprite_info.current_frame >= self.sprite_info.tile_count {
  86. self.sprite_info.current_frame = 0;
  87. }
  88. }
  89. }
  90. enum Message {}
  91. struct MainState {
  92. scene_items_sprite_batch: graphics::spritebatch::SpriteBatch,
  93. scene_items: Vec<SceneItem>,
  94. }
  95. impl MainState {
  96. fn new(ctx: &mut Context) -> GameResult<MainState> {
  97. let image = graphics::Image::new(ctx, "/test.png").unwrap();
  98. let batch = graphics::spritebatch::SpriteBatch::new(image);
  99. let mut scene_items = vec![];
  100. for x in 0..1 {
  101. for y in 0..4 {
  102. let sprite_type = if y % 2 == 0 {
  103. SpriteType::WalkingSoldier
  104. } else {
  105. SpriteType::JumpingSoldier
  106. };
  107. scene_items.push(SceneItem::new(
  108. sprite_type,
  109. na::Point2::new(x as f32 * 24.0, y as f32 * 24.0),
  110. 168.0,
  111. 48.0,
  112. ));
  113. }
  114. }
  115. let s = MainState {
  116. scene_items_sprite_batch: batch,
  117. scene_items,
  118. };
  119. Ok(s)
  120. }
  121. }
  122. impl event::EventHandler for MainState {
  123. fn update(&mut self, ctx: &mut Context) -> GameResult {
  124. while check_update_time(ctx, TARGET_ANIMATION_FPS) {
  125. for scene_item in self.scene_items.iter_mut() {
  126. scene_item.tick_frame();
  127. }
  128. }
  129. Ok(())
  130. }
  131. fn draw(&mut self, ctx: &mut Context) -> GameResult {
  132. graphics::clear(ctx, graphics::BLACK);
  133. for scene_item in self.scene_items.iter() {
  134. let sprite_batch_part = sprite_batch_part_from_sprite_info(&scene_item.sprite_info)
  135. .dest(scene_item.position.clone());
  136. self.scene_items_sprite_batch.add(sprite_batch_part);
  137. }
  138. graphics::draw(
  139. ctx,
  140. &self.scene_items_sprite_batch,
  141. graphics::DrawParam::new().dest(na::Point2::new(0.0, 0.0)),
  142. )?;
  143. self.scene_items_sprite_batch.clear();
  144. graphics::present(ctx)?;
  145. println!("FPS: {}", ggez::timer::fps(ctx));
  146. Ok(())
  147. }
  148. }
  149. // TODO: spite i par objet, fabrication des sprite_info qu'une fois; channel pour modifs des objets ds update
  150. pub fn main() -> GameResult {
  151. let resource_dir = if let Ok(manifest_dir) = env::var("CARGO_MANIFEST_DIR") {
  152. let mut path = path::PathBuf::from(manifest_dir);
  153. path.push("resources");
  154. path
  155. } else {
  156. path::PathBuf::from("./resources")
  157. };
  158. let cb = ggez::ContextBuilder::new("oc", "bux")
  159. .add_resource_path(resource_dir)
  160. .window_mode(ggez::conf::WindowMode::default().dimensions(800.0, 600.0));
  161. let (ctx, event_loop) = &mut cb.build()?;
  162. let state = &mut MainState::new(ctx)?;
  163. event::run(ctx, event_loop, state)
  164. }