Saltar al contenido
GameGenresEnglish
Disparos

Run and gun

Avanzas a pie por niveles con desplazamiento, corriendo, saltando y disparando sin parar a enemigos que llegan desde todos lados.

También se llama: corre y dispara

Mecánicas que lo definen

  • Disparo casi continuo mientras te mueves: correr y disparar ocurren a la vez, nunca por turnos.
  • Puntería en varias direcciones (a menudo ocho) con la misma palanca o flechas con las que te mueves.
  • Plataformas y saltos en la variante lateral, o un campo abierto con desplazamiento vertical en la variante cenital.
  • Enemigos de a pie que corren hacia ti y torretas fijas que disparan apuntando, a menudo desde arriba.
  • Armas que se recogen por el camino (dispersión, láser, munición limitada) y pocas vidas o un solo impacto para morir.
  • Jefes grandes al final de cada nivel, con patrones de ataque que hay que aprender.

Bucle de juego

Avanzar, ver quién aparece y desde dónde, apuntar hacia ahí sin dejar de moverte, esquivar sus disparos y llegar al jefe del final.

Demo propia

Controles. Flechas o WASD para moverte y apuntar (arriba y diagonales; abajo solo en el aire), espacio, Z o K para saltar, mantén X o J para disparar. En móvil, los botones en pantalla.

Abrir en pantalla completa

Un nivel lateral con soldados que corren hacia ti, torretas en lo alto, un foso que saltar y un jefe al final. Lo justo para sentir lo que define al género, que es moverse y disparar a la vez en varias direcciones.

Hecha con Kaplay, en unas 184 líneas de JavaScript.

Cómo está hecha

  1. Configuración y controles

    Se definen botones virtuales para las cuatro direcciones, saltar y disparar. Las flechas cumplen dos funciones a la vez, mover y apuntar, como en los arcades de una sola palanca. FIRE_RATE fija cuántas balas salen por segundo y LIVES cuántos golpes aguantas.

    const k = kaplay({
      width: 640,
      height: 360,
      letterbox: true, pixelDensity,
      background: [28, 40, 56],
      buttons: {
        left: { keyboard: ["left", "a"] },
        right: { keyboard: ["right", "d"] },
        up: { keyboard: ["up", "w"] },
        down: { keyboard: ["down", "s"] },
        jump: { keyboard: ["space", "z", "k"] },
        shoot: { keyboard: ["x", "j"] },
      },
    });
    touchControls(k, [
      { button: "left", label: "◀" },
      { button: "up", label: "▲" },
      { button: "down", label: "▼" },
      { button: "right", label: "▶" },
      { button: "shoot", label: "•", side: "right" },
      { button: "jump", label: "⤒", side: "right" },
    ]);
    
    const TILE = 32;
    const SPEED = 200;
    const JUMP_FORCE = 560;
    const BULLET_SPEED = 520;
    const FIRE_RATE = 0.14; // seconds between shots while the button is held
    const LIVES = 5;
    const BOSS_X = 1600; // where the boss arena starts
    setGravity(1500);
  2. El nivel como texto

    El nivel es una lista de cadenas que addLevel convierte en suelo, bloques, soldados (s) y torretas (T). Las torretas están sobre plataformas altas a propósito, para que tengas que apuntar hacia arriba.

    // = ground · # block · s soldier · T turret. The boss arena is the last screen.
    const MAP = [
      "                                                                      ",
      "                                                                      ",
      "                                                                      ",
      "                                                                      ",
      "                                                                      ",
      "                            T           T                             ",
      "                          #####       #####                           ",
      "                                               ##                     ",
      "          ##  s          s       s          s  ## s                   ",
      "===================   ================================================",
      "===================   ================================================",
    ];
    const solid = (c) => [rect(TILE, TILE), color(c), area(), body({ isStatic: true }), "solid"];
    const buildLevel = () =>
      addLevel(MAP, {
        tileWidth: TILE,
        tileHeight: TILE,
        pos: vec2(0, 8),
        tiles: {
          "=": () => solid(rgb(80, 120, 90)),
          "#": () => solid(rgb(130, 110, 90)),
          s: () => [rect(22, 32), color(220, 80, 70), pos(5, 0), area(), body(), { hp: 1 }, "enemy", "soldier"],
          T: () => [rect(26, 26), color(240, 150, 60), pos(3, 6), area(), { hp: 3, reload: 1 }, "enemy", "turret"],
        },
      });
  3. El jugador

    Moverse y saltar funciona como en un juego de plataformas. Cada golpe resta una vida y da 1,2 segundos de invulnerabilidad, en los que el personaje parpadea; sin ese margen, varios enemigos juntos te quitarían todas las vidas a la vez. Caer al foso también hace perder.

    const player = add([
      rect(22, 34), pos(64, 200), anchor("bot"), color(120, 200, 255), area(), body(), opacity(1),
      { dir: 1, lives: LIVES, safe: 0 },
    ]);
    onButtonDown("left", () => (player.move(-SPEED, 0), (player.dir = -1)));
    onButtonDown("right", () => (player.move(SPEED, 0), (player.dir = 1)));
    onButtonPress("jump", () => player.isGrounded() && player.jump(JUMP_FORCE));
    function hurt() {
      if (player.safe > 0) return;
      player.lives--;
      player.safe = 1.2; // a moment of invulnerability after each hit
      shake(5);
      if (player.lives <= 0) go("end", false);
    }
    player.onUpdate(() => {
      player.safe -= dt();
      player.opacity = player.safe > 0 && Math.floor(time() * 16) % 2 ? 0.3 : 1;
      hud.text = t({ es: "Vidas: ", en: "Lives: " }) + "♥".repeat(Math.max(0, player.lives));
      if (player.pos.y > 500) go("end", false);
    });
    player.onCollide("enemy", hurt);
    player.onCollide("ebullet", (b) => (destroy(b), hurt()));
  4. Apuntar en ocho direcciones

    aimDir() convierte las flechas que mantienes en un vector: arriba, abajo, izquierda, derecha y sus combinaciones. Si no mantienes ninguna, disparas hacia donde miras. Apuntar hacia abajo solo vale en el aire, porque en el suelo la bala chocaría con tus pies. Al final se normaliza el vector (unit()) para que la diagonal no sea más rápida que la horizontal.

    // Eight directions from the arrows you hold: up, diagonals, and down only in
    // mid-air. With no arrow held, you shoot where you face.
    function aimDir() {
      let x = (isButtonDown("right") ? 1 : 0) - (isButtonDown("left") ? 1 : 0);
      let y = (isButtonDown("down") ? 1 : 0) - (isButtonDown("up") ? 1 : 0);
      if (y > 0 && player.isGrounded()) y = 0;
      if (x === 0 && y === 0) x = player.dir;
      return vec2(x, y).unit();
    }
  5. Disparo continuo

    Mientras mantienes el botón sale una bala cada FIRE_RATE segundos. Cada bala lleva move() en la dirección de apuntado, se destruye al chocar con un bloque o al salir de la pantalla (offscreen) y resta una vida al enemigo que toca.

    // Holding the button fires a steady stream: in this genre you almost never stop shooting.
    let cooldown = 0;
    onUpdate(() => {
      cooldown -= dt();
      if (!isButtonDown("shoot") || cooldown > 0) return;
      cooldown = FIRE_RATE;
      const d = aimDir();
      add([
        circle(4), color(255, 240, 120), anchor("center"), pos(player.pos.add(d.scale(18)).add(0, -20)),
        move(d, BULLET_SPEED), area(), offscreen({ destroy: true }), "bullet",
      ]);
    });
    onCollide("bullet", "solid", (b) => destroy(b));
    onCollide("bullet", "enemy", (b, e) => {
      destroy(b);
      e.hp--;
      if (e.hp > 0) return;
      if (e.is("boss")) go("end", true);
      else destroy(e);
    });
  6. Soldados y torretas

    Hay dos enemigos que piden respuestas distintas. Los soldados corren hacia ti por el suelo y se resuelven disparando de frente. Las torretas no se mueven, pero disparan balas apuntadas a tu posición cada pocos segundos desde lo alto, así que hay que apuntar en diagonal o hacia arriba y esquivar a la vez.

    // Soldiers run at you along the ground; turrets wait on ledges and fire aimed
    // shots, so you have to aim up and diagonally to clear them.
    function enemyShot(from, angleOffset = 0, speed = 200) {
      const d = player.pos.add(0, -17).sub(from).unit();
      const a = Math.atan2(d.y, d.x) + angleOffset;
      add([circle(5), color(255, 90, 90), anchor("center"), pos(from), move(vec2(Math.cos(a), Math.sin(a)), speed),
        area(), offscreen({ destroy: true }), "ebullet"]);
    }
    onUpdate("soldier", (s) => {
      if (Math.abs(s.pos.x - player.pos.x) < 420) s.move(s.pos.x > player.pos.x ? -90 : 90, 0);
      if (s.pos.y > 500) destroy(s);
    });
    onUpdate("turret", (tr) => {
      tr.reload -= dt();
      if (tr.reload <= 0 && Math.abs(tr.pos.x - player.pos.x) < 420) {
        tr.reload = 2.2;
        enemyShot(tr.worldPos().add(13, 13));
      }
    });
    onCollide("ebullet", "solid", (b) => destroy(b));
  7. El jefe

    El jefe aparece al entrar en la última pantalla. Sube y baja siguiendo un seno, así que a veces lo alcanzas de frente y a veces tienes que saltar o apuntar en diagonal. Cada dos segundos dispara un abanico de tres balas hacia ti. Aguanta 24 impactos y la barra de arriba muestra cuántos le quedan.

    // The last screen locks the camera. The boss floats up and down, fires a fan
    // of three shots and only falls after many hits: a test of everything above.
    let boss = null;
    let bossTime = 0;
    const bossBar = add([rect(0, 10), pos(170, 18), color(240, 80, 80), fixed(), z(10)]);
    onUpdate(() => {
      if (!boss && player.pos.x > BOSS_X + 40) {
        boss = add([rect(80, 110), pos(BOSS_X + 560, 200), anchor("center"), color(170, 90, 200), area(),
          { hp: 24, reload: 2 }, "enemy", "boss"]);
      }
      if (!boss) return;
      bossTime += dt();
      boss.pos.y = 200 + Math.sin(bossTime * 1.3) * 80;
      boss.reload -= dt();
      if (boss.reload <= 0) {
        boss.reload = 2;
        for (const off of [-0.35, 0, 0.35]) enemyShot(boss.pos.sub(40, 0), off, 170);
      }
      bossBar.width = boss.hp * 12;
    });
  8. La cámara y la arena final

    La cámara sigue al jugador en horizontal hasta la arena del jefe; ahí se queda fija y el jugador no puede volver atrás. Es el mismo bloqueo que usan casi todos los juegos de acción para los combates contra jefes.

    // The camera follows you until the boss arena, then stays put and walls you in.
    const levelWidth = MAP[0].length * TILE;
    player.onUpdate(() => {
      const arena = player.pos.x > BOSS_X;
      if (arena) player.pos.x = Math.max(player.pos.x, BOSS_X + 12);
      player.pos.x = Math.max(12, Math.min(player.pos.x, levelWidth - 12));
      const x = arena ? BOSS_X + 320 : Math.min(Math.max(player.pos.x, 320), levelWidth - 320);
      camPos(x, 180);
    });
  9. Escenas

    El juego tiene tres escenas (title, game y end) y go() salta de una a otra. Vencer al jefe o perder todas las vidas lleva a end.

    function screen(title, subtitle, next) {
      add([text(title, { size: 34, font: FONT, align: "center" }), pos(center().sub(0, 40)), anchor("center")]);
      add([
        text(subtitle, { size: 16, font: FONT, align: "center", width: 560 }),
        pos(center().add(0, 30)),
        anchor("center"),
        color(200, 210, 255),
      ]);
      onButtonPress("jump", next);
      onKeyPress("enter", next);
      onClick(next);
    }
    
    scene("title", () =>
      screen(
        t({ es: "Run and gun", en: "Run and gun" }),
        t({
          es: "Flechas para moverte y apuntar (arriba y diagonales), espacio o Z para saltar, mantén X para disparar. Llega al final y vence al jefe.\nPulsa espacio o toca para empezar.",
          en: "Arrows to move and aim (up and diagonals), space or Z to jump, hold X to shoot. Reach the end and beat the boss.\nPress space or tap to start.",
        }),
        () => go("game"),
      ),
    );
    
    scene("end", (won) =>
      screen(
        won ? t({ es: "¡Jefe derrotado!", en: "Boss defeated!" }) : t({ es: "Inténtalo otra vez", en: "Try again" }),
        t({ es: "Pulsa espacio para jugar otra vez.", en: "Press space to play again." }),
        () => go("game"),
      ),
    );
    
    go("title");

Qué simplificamos

  • El personaje, los enemigos y el jefe son rectángulos; no hay animaciones ni sonido.
  • Hay una sola arma; no hay mejoras que recoger ni granadas.
  • Tienes cinco vidas y un momento de invulnerabilidad tras cada golpe; en los clásicos del género un solo impacto suele bastar para morir.

Para modificarla

  • Añade una mejora que se recoja en el camino y cambie el disparo por un abanico de tres balas.
  • Añade un botón que fije la dirección de disparo mientras lo mantienes, para poder moverte sin dejar de apuntar en diagonal.
  • Haz que el jefe cambie de patrón cuando le quede la mitad de vida, por ejemplo disparando más rápido o bajando hasta el suelo.
Código completo
// Run and gun demo
// Engine: Kaplay 3001 (https://kaplayjs.com). MIT licence.
import kaplay from "../../vendor/kaplay.mjs";
import { t, FONT, touchControls, pixelDensity } from "../common.js";

// #region setup
const k = kaplay({
  width: 640,
  height: 360,
  letterbox: true, pixelDensity,
  background: [28, 40, 56],
  buttons: {
    left: { keyboard: ["left", "a"] },
    right: { keyboard: ["right", "d"] },
    up: { keyboard: ["up", "w"] },
    down: { keyboard: ["down", "s"] },
    jump: { keyboard: ["space", "z", "k"] },
    shoot: { keyboard: ["x", "j"] },
  },
});
touchControls(k, [
  { button: "left", label: "◀" },
  { button: "up", label: "▲" },
  { button: "down", label: "▼" },
  { button: "right", label: "▶" },
  { button: "shoot", label: "•", side: "right" },
  { button: "jump", label: "⤒", side: "right" },
]);

const TILE = 32;
const SPEED = 200;
const JUMP_FORCE = 560;
const BULLET_SPEED = 520;
const FIRE_RATE = 0.14; // seconds between shots while the button is held
const LIVES = 5;
const BOSS_X = 1600; // where the boss arena starts
setGravity(1500);
// #endregion

// #region level
// = ground · # block · s soldier · T turret. The boss arena is the last screen.
const MAP = [
  "                                                                      ",
  "                                                                      ",
  "                                                                      ",
  "                                                                      ",
  "                                                                      ",
  "                            T           T                             ",
  "                          #####       #####                           ",
  "                                               ##                     ",
  "          ##  s          s       s          s  ## s                   ",
  "===================   ================================================",
  "===================   ================================================",
];
const solid = (c) => [rect(TILE, TILE), color(c), area(), body({ isStatic: true }), "solid"];
const buildLevel = () =>
  addLevel(MAP, {
    tileWidth: TILE,
    tileHeight: TILE,
    pos: vec2(0, 8),
    tiles: {
      "=": () => solid(rgb(80, 120, 90)),
      "#": () => solid(rgb(130, 110, 90)),
      s: () => [rect(22, 32), color(220, 80, 70), pos(5, 0), area(), body(), { hp: 1 }, "enemy", "soldier"],
      T: () => [rect(26, 26), color(240, 150, 60), pos(3, 6), area(), { hp: 3, reload: 1 }, "enemy", "turret"],
    },
  });
// #endregion

scene("game", () => {
  buildLevel();
  const hud = add([text("", { size: 18, font: FONT }), pos(16, 12), fixed(), z(10)]);

  // #region player
  const player = add([
    rect(22, 34), pos(64, 200), anchor("bot"), color(120, 200, 255), area(), body(), opacity(1),
    { dir: 1, lives: LIVES, safe: 0 },
  ]);
  onButtonDown("left", () => (player.move(-SPEED, 0), (player.dir = -1)));
  onButtonDown("right", () => (player.move(SPEED, 0), (player.dir = 1)));
  onButtonPress("jump", () => player.isGrounded() && player.jump(JUMP_FORCE));
  function hurt() {
    if (player.safe > 0) return;
    player.lives--;
    player.safe = 1.2; // a moment of invulnerability after each hit
    shake(5);
    if (player.lives <= 0) go("end", false);
  }
  player.onUpdate(() => {
    player.safe -= dt();
    player.opacity = player.safe > 0 && Math.floor(time() * 16) % 2 ? 0.3 : 1;
    hud.text = t({ es: "Vidas: ", en: "Lives: " }) + "♥".repeat(Math.max(0, player.lives));
    if (player.pos.y > 500) go("end", false);
  });
  player.onCollide("enemy", hurt);
  player.onCollide("ebullet", (b) => (destroy(b), hurt()));
  // #endregion

  // #region aim
  // Eight directions from the arrows you hold: up, diagonals, and down only in
  // mid-air. With no arrow held, you shoot where you face.
  function aimDir() {
    let x = (isButtonDown("right") ? 1 : 0) - (isButtonDown("left") ? 1 : 0);
    let y = (isButtonDown("down") ? 1 : 0) - (isButtonDown("up") ? 1 : 0);
    if (y > 0 && player.isGrounded()) y = 0;
    if (x === 0 && y === 0) x = player.dir;
    return vec2(x, y).unit();
  }
  // #endregion

  // #region shooting
  // Holding the button fires a steady stream: in this genre you almost never stop shooting.
  let cooldown = 0;
  onUpdate(() => {
    cooldown -= dt();
    if (!isButtonDown("shoot") || cooldown > 0) return;
    cooldown = FIRE_RATE;
    const d = aimDir();
    add([
      circle(4), color(255, 240, 120), anchor("center"), pos(player.pos.add(d.scale(18)).add(0, -20)),
      move(d, BULLET_SPEED), area(), offscreen({ destroy: true }), "bullet",
    ]);
  });
  onCollide("bullet", "solid", (b) => destroy(b));
  onCollide("bullet", "enemy", (b, e) => {
    destroy(b);
    e.hp--;
    if (e.hp > 0) return;
    if (e.is("boss")) go("end", true);
    else destroy(e);
  });
  // #endregion

  // #region enemies
  // Soldiers run at you along the ground; turrets wait on ledges and fire aimed
  // shots, so you have to aim up and diagonally to clear them.
  function enemyShot(from, angleOffset = 0, speed = 200) {
    const d = player.pos.add(0, -17).sub(from).unit();
    const a = Math.atan2(d.y, d.x) + angleOffset;
    add([circle(5), color(255, 90, 90), anchor("center"), pos(from), move(vec2(Math.cos(a), Math.sin(a)), speed),
      area(), offscreen({ destroy: true }), "ebullet"]);
  }
  onUpdate("soldier", (s) => {
    if (Math.abs(s.pos.x - player.pos.x) < 420) s.move(s.pos.x > player.pos.x ? -90 : 90, 0);
    if (s.pos.y > 500) destroy(s);
  });
  onUpdate("turret", (tr) => {
    tr.reload -= dt();
    if (tr.reload <= 0 && Math.abs(tr.pos.x - player.pos.x) < 420) {
      tr.reload = 2.2;
      enemyShot(tr.worldPos().add(13, 13));
    }
  });
  onCollide("ebullet", "solid", (b) => destroy(b));
  // #endregion

  // #region boss
  // The last screen locks the camera. The boss floats up and down, fires a fan
  // of three shots and only falls after many hits: a test of everything above.
  let boss = null;
  let bossTime = 0;
  const bossBar = add([rect(0, 10), pos(170, 18), color(240, 80, 80), fixed(), z(10)]);
  onUpdate(() => {
    if (!boss && player.pos.x > BOSS_X + 40) {
      boss = add([rect(80, 110), pos(BOSS_X + 560, 200), anchor("center"), color(170, 90, 200), area(),
        { hp: 24, reload: 2 }, "enemy", "boss"]);
    }
    if (!boss) return;
    bossTime += dt();
    boss.pos.y = 200 + Math.sin(bossTime * 1.3) * 80;
    boss.reload -= dt();
    if (boss.reload <= 0) {
      boss.reload = 2;
      for (const off of [-0.35, 0, 0.35]) enemyShot(boss.pos.sub(40, 0), off, 170);
    }
    bossBar.width = boss.hp * 12;
  });
  // #endregion

  // #region camera
  // The camera follows you until the boss arena, then stays put and walls you in.
  const levelWidth = MAP[0].length * TILE;
  player.onUpdate(() => {
    const arena = player.pos.x > BOSS_X;
    if (arena) player.pos.x = Math.max(player.pos.x, BOSS_X + 12);
    player.pos.x = Math.max(12, Math.min(player.pos.x, levelWidth - 12));
    const x = arena ? BOSS_X + 320 : Math.min(Math.max(player.pos.x, 320), levelWidth - 320);
    camPos(x, 180);
  });
  // #endregion
});

// #region scenes
function screen(title, subtitle, next) {
  add([text(title, { size: 34, font: FONT, align: "center" }), pos(center().sub(0, 40)), anchor("center")]);
  add([
    text(subtitle, { size: 16, font: FONT, align: "center", width: 560 }),
    pos(center().add(0, 30)),
    anchor("center"),
    color(200, 210, 255),
  ]);
  onButtonPress("jump", next);
  onKeyPress("enter", next);
  onClick(next);
}

scene("title", () =>
  screen(
    t({ es: "Run and gun", en: "Run and gun" }),
    t({
      es: "Flechas para moverte y apuntar (arriba y diagonales), espacio o Z para saltar, mantén X para disparar. Llega al final y vence al jefe.\nPulsa espacio o toca para empezar.",
      en: "Arrows to move and aim (up and diagonals), space or Z to jump, hold X to shoot. Reach the end and beat the boss.\nPress space or tap to start.",
    }),
    () => go("game"),
  ),
);

scene("end", (won) =>
  screen(
    won ? t({ es: "¡Jefe derrotado!", en: "Boss defeated!" }) : t({ es: "Inténtalo otra vez", en: "Try again" }),
    t({ es: "Pulsa espacio para jugar otra vez.", en: "Press space to play again." }),
    () => go("game"),
  ),
);

go("title");
// #endregion

Retos de diseño

  • Que el jugador lea siempre la pantalla: balas enemigas de un color y tamaño distintos de las propias y del fondo.
  • Resolver la puntería con pocos botones: decidir si moverse y apuntar comparten las mismas flechas, si hay un botón para fijar la dirección o si se apunta con el ratón.
  • Colocar enemigos y torretas de modo que obliguen a usar todas las direcciones de disparo, no solo la horizontal.
  • Diseñar un jefe que sea un examen de lo aprendido en el nivel, con avisos claros antes de cada ataque.

Historia

  1. 1979
    Origen

    Sus orígenes se remontan a Sheriff (Nintendo, 1979); el género se popularizó a mediados de los ochenta con juegos de temática militar como Commando (1985).

    Run and gun (Wikipedia)
  2. 1985
    Commando

    Commando, de Capcom, con un soldado que dispara en ocho direcciones y lanza granadas en un campo de desplazamiento vertical, fija la fórmula del género y lo populariza.

    Commando (Wikipedia)
  3. 1985

    Green Beret, de Konami, lleva la fórmula de Commando al desplazamiento lateral.

    Run and gun (Wikipedia)
  4. 1986

    Rolling Thunder, de Namco, añade a la fórmula la mecánica de cubrirse.

    Run and gun (Wikipedia)
  5. 1987
    Contra

    Contra, de Konami, destaca por su puntería en ocho direcciones, también hacia abajo en pleno salto, y su cooperativo simultáneo para dos.

    Contra (Wikipedia)
  6. 1993
    Gunstar Heroes

    Gunstar Heroes, de Treasure, deja combinar sus cuatro tipos de disparo de dos en dos para crear armas nuevas.

    Gunstar Heroes (Wikipedia)
  7. 1996
    Metal Slug

    Metal Slug, para Neo Geo, suma ataques cuerpo a cuerpo, armas de munición limitada y un tanque que puedes conducir, e inicia una saga que sigue recibiendo entregas.

    Metal Slug (Wikipedia)
  8. 2017
    Cuphead

    Cuphead, de Studio MDHR, centra el género en los combates contra jefes, con animación hecha a mano al estilo de los dibujos de los años treinta.

    Cuphead (Wikipedia)

Juegos de referencia

1985

Commando

Capcom (Tokuro Fujiwara). arcade, NES, Commodore 64, ZX Spectrum

Un soldado avanza a pie por un campo de batalla con desplazamiento vertical, disparando en ocho direcciones y lanzando granadas a lo que tiene delante. Popularizó el run and gun y tuvo muchos imitadores.

1987

Contra

Konami. arcade, NES

Dos soldados corren y saltan por niveles de desplazamiento lateral disparando en ocho direcciones, también hacia abajo en pleno salto. Su cooperativo simultáneo para dos fue la clave de su popularidad.

1993

Gunstar Heroes

Treasure. Mega Drive

Un run and gun frenético en el que los cuatro tipos de disparo se combinan de dos en dos para crear armas nuevas, como una ametralladora con proyectiles teledirigidos.

1996

Metal Slug

Nazca Corporation. arcade, Neo Geo

Avanzas disparando contra un ejército, con ataques cuerpo a cuerpo cuando el enemigo está cerca, armas potentes de munición limitada y un pequeño tanque al que te puedes subir. Inició una saga de larga vida, conocida por su humor.

2017

Cuphead

Studio MDHR. Windows, Xbox One, Nintendo Switch, PlayStation 4

Un run and gun construido casi entero alrededor de combates contra jefes, intercalados con niveles de correr y disparar. Todo está animado a mano al estilo de los dibujos animados de los años treinta.

2019

Captain Photon and the planet of chaos

Shiv Games. navegador

Un run and gun corto al estilo de Contra, hecho en Construct para una game jam. Apuntas con las flechas, puedes fijar la dirección del disparo y saltas entre plataformas.

Ejercicio

Juega la demo, luego cambia FIRE_RATE y la cantidad de vidas (LIVES) y anota cómo cambia la dificultad. Después añade un arma que se recoja en el camino y dispare tres balas en abanico, como el clásico disparo de dispersión.

Fuentes