snake.rs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. use crate::components as c;
  2. use bevy::prelude::*;
  3. fn spawn_segment(
  4. mut commands: Commands,
  5. material: &Handle<ColorMaterial>,
  6. position: c::Position,
  7. ) -> Entity {
  8. commands
  9. .spawn_bundle(SpriteBundle {
  10. material: material.clone(),
  11. ..Default::default()
  12. })
  13. .insert(c::SnakeSegment)
  14. .insert(position)
  15. .insert(c::GridSize::square(0.65))
  16. .id()
  17. }
  18. pub fn spawn(
  19. mut commands: Commands,
  20. materials: Res<c::Materials>,
  21. mut segments: ResMut<c::SnakeSegments>,
  22. ) {
  23. segments.segments = vec![
  24. commands
  25. .spawn_bundle(SpriteBundle {
  26. material: materials.head_material.clone(),
  27. sprite: Sprite::new(Vec2::new(10.0, 10.0)),
  28. ..Default::default()
  29. })
  30. .insert(c::SnakeHead {
  31. direction: c::Direction::Up,
  32. intention: c::Direction::Up,
  33. })
  34. .insert(c::SnakeSegment)
  35. .insert(c::Position { x: 3, y: 3 })
  36. .insert(c::GridSize::square(0.8))
  37. .id(),
  38. spawn_segment(
  39. commands,
  40. &materials.segment_material,
  41. c::Position { x: 3, y: 2 },
  42. ),
  43. ]
  44. }
  45. pub fn input(keyboard_input: Res<Input<KeyCode>>, mut heads: Query<&mut c::SnakeHead>) {
  46. if let Some(mut head) = heads.iter_mut().next() {
  47. let dir = if keyboard_input.pressed(KeyCode::Left) {
  48. c::Direction::Left
  49. } else if keyboard_input.pressed(KeyCode::Down) {
  50. c::Direction::Down
  51. } else if keyboard_input.pressed(KeyCode::Up) {
  52. c::Direction::Up
  53. } else if keyboard_input.pressed(KeyCode::Right) {
  54. c::Direction::Right
  55. } else {
  56. head.intention
  57. };
  58. if dir != head.direction.opposite() {
  59. head.intention = dir;
  60. }
  61. }
  62. }
  63. pub fn movement(
  64. segments: ResMut<c::SnakeSegments>,
  65. mut last_tail_position: ResMut<c::LastTailPosition>,
  66. mut game_over_writer: EventWriter<c::GameOverEvent>,
  67. mut heads: Query<(Entity, &mut c::SnakeHead)>,
  68. mut positions: Query<&mut c::Position>,
  69. ) {
  70. if let Some((head_entity, mut head)) = heads.iter_mut().next() {
  71. let segment_positions = segments
  72. .segments
  73. .iter()
  74. .map(|e| *positions.get_mut(*e).unwrap())
  75. .collect::<Vec<c::Position>>();
  76. let mut head_pos = positions.get_mut(head_entity).unwrap();
  77. head.direction = head.intention;
  78. match &head.direction {
  79. c::Direction::Left => head_pos.x -= 1,
  80. c::Direction::Right => head_pos.x += 1,
  81. c::Direction::Up => head_pos.y += 1,
  82. c::Direction::Down => head_pos.y -= 1,
  83. }
  84. if head_pos.x < 0
  85. || head_pos.y < 0
  86. || head_pos.x as u32 >= c::ARENA_WIDTH
  87. || head_pos.y as u32 >= c::ARENA_HEIGHT
  88. || segment_positions.contains(&head_pos)
  89. {
  90. game_over_writer.send(c::GameOverEvent);
  91. }
  92. segment_positions
  93. .iter()
  94. .zip(segments.segments.iter().skip(1))
  95. .for_each(|(pos, segment)| {
  96. *positions.get_mut(*segment).unwrap() = *pos;
  97. });
  98. last_tail_position.pos = Some(*segment_positions.last().unwrap());
  99. }
  100. }
  101. pub fn eating(
  102. mut commands: Commands,
  103. mut growth_writer: EventWriter<c::GrowthEvent>,
  104. food_positions: Query<(Entity, &c::Position), With<c::Food>>,
  105. head_positions: Query<&c::Position, With<c::SnakeHead>>,
  106. ) {
  107. for head_pos in head_positions.iter() {
  108. for (ent, food_pos) in food_positions.iter() {
  109. if food_pos == head_pos {
  110. commands.entity(ent).despawn();
  111. growth_writer.send(c::GrowthEvent);
  112. }
  113. }
  114. }
  115. }
  116. pub fn growth(
  117. commands: Commands,
  118. last_tail_position: Res<c::LastTailPosition>,
  119. mut segments: ResMut<c::SnakeSegments>,
  120. mut growth_reader: EventReader<c::GrowthEvent>,
  121. materials: Res<c::Materials>,
  122. ) {
  123. if growth_reader.iter().next().is_some() {
  124. segments.segments.push(spawn_segment(
  125. commands,
  126. &materials.segment_material,
  127. last_tail_position.pos.unwrap(),
  128. ));
  129. }
  130. }