Tir du personnage (Jetpack Hero)
Le personnage doit pouvoir tirer au laser pour dégommer les aliens. Voyons comment gérer les entrées, ajouter du son, animer le tir, etc…
Un tir très simple pour commencer
Dans cette première version il est impossible de tirer plus d’une fois. Impossible aussi de tirer à gauche, le laser part toujours à droite. Bref, pas très utile, mais il faut bien commencer quelque part.
Je commence par ajouter l’état shooting dans le hash hero pour savoir si un
tir est en cours.
    state.hero ||= {
      # ...
      shooting: false,
    }Il nous faut un hash pour conserver les sprites de laser, et il faut les afficher.
    state.shots ||= []
    outputs.sprites << state.shotsOn déclenche le tir avec la touche ALT ou un bouton de la manette.
Sans la ligne if state.shots.empty? un tir serait déclenché à chaque frame. Essayez pour voir le problème.
    if inputs.keyboard.alt || inputs.controller_one.b
      if state.shots.empty?
        state.hero.shooting = true
        audio[:laser] = { input: 'sounds/laser.wav' }
      end
    endSi un tir à eu lieu, on ajoute un sprite dans le hash shots. Ce sprite sera
déplacé de 5 pixels vers la droite à chaque frame.
  def calc_shot
    if state.hero.shooting
      state.shots << {
        x: state.hero.x,
        y: state.hero.y + 20,
        w: 24,
        h: 10,
        path: 'sprites/laser.png',
      }
      state.hero.shooting = false
    end
    state.shots.each do |shot|
      shot.x += 5
    end
  endPouvoir tirer et re-tirer
On ajoute un état dead à chaque tir, qui passe à true quand le sprite
disparait de l’écran. Ça permet de supprimer les tirs hors jeu avec reject!.
De cette manière on obtient un tir à la space invaders.
  def calc_shot
    if state.hero.shooting
      state.shots << {
        # ...
        dead: false,
      }
      state.hero.shooting = false
    end
    state.shots.each do |shot|
      shot.x += 5
      shot.dead = true if shot.x > Grid.w
    end
    state.shots.reject!(&:dead)
  endTirer à droite et à gauche
L’état hero.moving nous permet de savoir si le perso bouge vers la droite ou la gauche,
mais ne nous apprend rien quand à la direction à laquelle il fait face
lorsqu’il ne bouge pas. On va ajouter hero.facing pour toujours savoir où le
perso regarde, même quand il est à l’arrêt.
    state.hero ||= {
      # ...
      moving: :none,
      facing: :right,
      # ...
    }
  def input
    if inputs.left
      state.hero.moving = :left
      state.hero.facing = :left
    elsif inputs.right
      state.hero.moving = :right
      state.hero.facing = :right
    else
      state.hero.moving = :none
    end
  endMaintenant on peut tirer dans la direction du regard du perso, par l’intermédiaire de
speed.
  def calc_shot
    if state.hero.shooting
      state.shots << {
        # ...
        speed: state.hero.facing == :right ? LASER_SPEED : -LASER_SPEED,
      }
      state.hero.shooting = false
    end
    state.shots.each do |shot|
      shot.x += shot.speed
      shot.dead = true if shot.x > Grid.w || shot.x < 0
    end
    state.shots.reject!(&:dead)
  endCadence de tir
Disons qu’on veut pouvoir tirer toutes les 1/2 secondes, donc toutes les 30 frames :
    FIRE_RATE = 30 # Maximum is one shot every FIRE_RATE framesOn va se souvenir du moment du dernier tir :
    state.hero ||= {
      # ...
      last_shot_at: 0,
    }On autorisera un tir seulement si le dernier a eu lieu il y a plus d’une demi seconde :
    if inputs.keyboard.alt || inputs.controller_one.b
      if state.hero.last_shot_at + FIRE_RATE < Kernel.tick_count
        state.hero.shooting = true
        audio[:laser] = { input: 'sounds/laser.wav' }
      end
    endOn met à jour le moment du tir :
  def calc_shot
    if state.hero.shooting
      state.shots << {
        # ...
      }
      state.hero.shooting = false
      state.hero.last_shot_at = Kernel.tick_count
    endAnimation
Pour finir, voici une animation toute simple du laser. Celui-ci est retourné verticallement toutes les 10 frames :
  LASER_ANIMATION = 10
  def calc_shot
    if state.hero.shooting
      state.shots << {
        # ...
        animation_counter: LASER_ANIMATION,
        flip_vertically: false,
      }
      state.hero.shooting = false
      state.hero.last_shot_at = Kernel.tick_count
    end
    state.shots.each do |shot|
      shot.animation_counter -= 1
      if shot.animation_counter == 0
        shot.animation_counter = LASER_ANIMATION
        shot.flip_vertically = !shot.flip_vertically
      end
      shot.x += shot.speed
      shot.dead = true if shot.x > Grid.w || shot.x < 0
    end
    state.shots.reject!(&:dead)
  endRéférences
- Vous trouverez le code de Jetpack Hero sur github
 - Documentation de DragonRuby
 
Cet article fait partie d’une série :
- Jetpack Hero
 - Partie II
 - Une platforme, des collisions
 - Première animation du personnage
 - Ajouter des platformes
 - Du carburant pour le jetpack
 - Collecte de minerai
 - Effets sonores
 - Du rangement avec la classe Game
 - Apparition des aliens
 - Tir du personnage
 - On dégomme de l’alien
 - GAME OVER
 - Les aliens bougent enfin
 - Plusieurs petites animations
 - Un score et des vies
 
Commentaires
Pas encore trouvé de solution simple et non-invasive pour avoir des commentaires sur le blog. En attendant vous pouvez laisser votre Commentaire sur mastodon@lkdjiin