bevy_fighter 0.1.1

A mildly opinionated micro-engine for building 2D fighting games with bevy
Documentation
pub use crate::prelude::*;

#[derive(Debug)]
pub struct MotionEvent{
  pub motion: u8,
  pub player_id: u8,
  pub special_motion_duration: u8,
  pub special_motion: Option<CommandType>
}

#[derive(Debug)]
pub struct FighterInputEvent{
  pub player_id: u8,
  /// Direction of the input, expressed in numpad notation
  pub motion: u8,
  /// Any command motion found in the input event
  pub special_motion: Option<CommandType>,
  /// Duration of the current command motion
  pub special_motion_duration: u8,
  /// Buttons Pressed
  pub pressed: Vec<FighterButtonType>,
  /// Buttons Just Pressed
  pub just_pressed: Vec<FighterButtonType>
}

impl FighterInputEvent{
  fn new(
    motion: u8, 
    player_id: u8, 
    pressed: Vec<FighterButtonType>, 
    just_pressed: Vec<FighterButtonType>
  ) -> Self {
    FighterInputEvent {
      motion,
      player_id,
      special_motion_duration: 0,
      special_motion: None,
      pressed,
      just_pressed,
    }
  }
}
#[derive(Debug,Clone, Copy)]
pub enum FighterButtonType {
  A,
  B,
  C,
  D,
  E,
  F,
}

/// Notation, Priority, and Regex for special motions
#[derive(Debug)]
pub struct CommandMotion {
  pub priority: u8,
  regular_expression: Regex,
  pub command: CommandType
}

impl CommandMotion {
  pub fn new(priority: u8, regular_expression: Regex, command: CommandType) -> Self {
    CommandMotion { 
      priority, 
      regular_expression,
      command
    }
  }

  pub fn check(&self, buffer_string: &str, buffer_priority: u8) -> bool {
    return self.regular_expression.is_match(buffer_string) && self.priority > buffer_priority;
  }


}

#[derive(Debug, Clone, Copy)]
pub enum CommandType {
    FIREBALL,
    R_FIREBALL,
    DP,
    R_DP,
    HALF_CIRCLE_BACK,
    HALF_CIRCLE_FORWARD,
    DASH,
    BACK_DASH,
    INVITE_HELL
}

impl MotionEvent {
  fn new(motion: u8, player_id: u8) -> Self {
    MotionEvent {
      motion,
      player_id,
      special_motion_duration: 0,
      special_motion: None
    }
  }
}

// pub fn write_motion_inputs(
//   player_inputs: Res<PlayerInputs>,
//   keyboard_input: Res<Input<KeyCode>>, 
//   button_input: Res<Input<GamepadButton>>,
//   mut motion_writer: EventWriter<MotionEvent>
// ) {
//   for mapper in player_inputs.local_devices.iter() {
//     let mut h_axis: f32 = 0.0;
//     let mut v_axis: f32 = 0.0;
//     let InputMapper { player_id, ..} = mapper;
    
//     let InputActionsPressed {right, left, up, down, ..} = mapper.get_pressed_buttons(&keyboard_input, &button_input);


//     if left {
//       h_axis -= 1.0 *  mapper.get_facing_vector();
//     }

//     if right {
//       h_axis += 1.0 * mapper.get_facing_vector();
//     }

//     if up {
//       v_axis = 1.0;
//     }

//     if down {
//       if v_axis == 0.0 {
//         v_axis = -1.0;
//       }
//     }

//     let mut motion: u8 = 5;

//     if h_axis == 0.0 {
//       if v_axis == 1.0 {
//         motion = 8;
//       }

//       if v_axis == -1.0 {
//         motion = 2;
//       }
//     }

//     if h_axis == -1.0 {
//       if v_axis == 1.0 {
//         motion = 7;
//       }

//       if v_axis == 0.0 {
//         motion = 4;
//       }

//       if v_axis == -1.0 {
//         motion = 1;
//       }
//     }

//     if h_axis == 1.0 {
//       if v_axis == 1.0 {
//         motion = 9;
//       }

//       if v_axis == 0.0 {
//         motion = 6;
//       }

//       if v_axis == -1.0 {
//         motion = 3;
//       }
//     }
//     motion_writer.send(MotionEvent::new(motion,*player_id));
//   }
// }

// pub fn read_motion_inputs(
//   mut motion_input_reader: EventReader<MotionEvent>, 
//   mut query: Query<(&mut InputBuffer, &PlayerId)>,
// ) {
//   for (mut buffer, pid) in query.iter_mut() {
//     buffer.update(&mut motion_input_reader, pid.0);
//   };
// }

pub fn write_fighter_inputs(
  player_inputs: Res<PlayerInputs>,
  keyboard_input: Res<Input<KeyCode>>, 
  button_input: Res<Input<GamepadButton>>,
  mut input_writer: EventWriter<FighterInputEvent>
) {
  for mapper in player_inputs.local_devices.iter() {
    let mut h_axis: f32 = 0.0;
    let mut v_axis: f32 = 0.0;
    let InputMapper { player_id, ..} = mapper;
    
    let InputActionsPressed {
      right, 
      left, 
      up, 
      down,
      a, 
      b, 
      c, 
      d,
      e,
      f,
      ..} = mapper.get_pressed_buttons(&keyboard_input, &button_input);

    let InputActionsPressed {
      a:j_a, 
      b:j_b, 
      c:j_c, 
      d:j_d,
      e:j_e,
      f:j_f,
      ..} = mapper.get_just_pressed_buttons(&keyboard_input, &button_input);


    if left {
      h_axis -= 1.0 *  mapper.get_facing_vector();
    }

    if right {
      h_axis += 1.0 * mapper.get_facing_vector();
    }

    if up {
      v_axis = 1.0;
    }

    if down {
      if v_axis == 0.0 {
        v_axis = -1.0;
      }
    }

    let mut motion: u8 = 5;

    if h_axis == 0.0 {
      if v_axis == 1.0 {
        motion = 8;
      }

      if v_axis == -1.0 {
        motion = 2;
      }
    }

    if h_axis == -1.0 {
      if v_axis == 1.0 {
        motion = 7;
      }

      if v_axis == 0.0 {
        motion = 4;
      }

      if v_axis == -1.0 {
        motion = 1;
      }
    }

    if h_axis == 1.0 {
      if v_axis == 1.0 {
        motion = 9;
      }

      if v_axis == 0.0 {
        motion = 6;
      }

      if v_axis == -1.0 {
        motion = 3;
      }
    }

    let mut pressed = Vec::new();
    let mut just_pressed = Vec::new();

    if a {pressed.push(FighterButtonType::A)}
    if b {pressed.push(FighterButtonType::B)}
    if c {pressed.push(FighterButtonType::C)}
    if d {pressed.push(FighterButtonType::D)}
    if e {pressed.push(FighterButtonType::E)}
    if f {pressed.push(FighterButtonType::F)}

    if j_a {just_pressed.push(FighterButtonType::A)}
    if j_b {just_pressed.push(FighterButtonType::B)}
    if j_c {just_pressed.push(FighterButtonType::C)}
    if j_d {just_pressed.push(FighterButtonType::D)}
    if j_e {just_pressed.push(FighterButtonType::E)}
    if j_f {just_pressed.push(FighterButtonType::F)}
    
    input_writer.send(
      FighterInputEvent::new(
        motion,
        *player_id,
        pressed,
        just_pressed
      )
    );

  }
}

pub fn read_fighter_inputs(
  mut input_reader: EventReader<FighterInputEvent>, 
  mut player_inputs: ResMut<PlayerInputs>,
) {
  for buffer in player_inputs.buffers.iter_mut() {
    buffer.update(&mut input_reader);
  };
}

pub struct FighterInputPlugin;

impl Plugin for FighterInputPlugin {
  fn build(&self, app: &mut App) {
    app
    .add_event::<FighterInputEvent>()
    .insert_resource(PlayerInputs::default())
    .add_system_set(
      SystemSet::new()
        .with_run_criteria(FixedTimestep::step(0.01667))
        .with_system(write_fighter_inputs.label(FighterSystemLabels::InputWrite))
        .with_system(read_fighter_inputs.after(FighterSystemLabels::InputWrite))
    );
  }
}