loading...
Cover image for Backshot Tactics - A Multiplayer Game for js13kGames

Backshot Tactics - A Multiplayer Game for js13kGames

salvan13 profile image Antonio Salvati 🦊 Updated on ・5 min read

The Competition

This game was made for js13kGames, a JavaScript coding competition for HTML5 Game Developers. The fun part is the file size limit set to 13 kilobytes. Theme for 2019 was back.

The Initial Idea

Since I enjoy play multiplayer and competitive games, the initial idea was to create a multiplayer online 1vs1 tactical game, inspired by Teamfight Tactics

tft

Even if the final result is a completely different game as you can see

the initial splash screen

the ingame view

The Process

It was way too complex to do everything in 13kb and in the spare time I had, so I started removing features from the initial idea:

  • Removed different characters, they are all equal (no different sprites / UI to create)
  • The characters are placed on the field from the beginning (no drag and drop to implement)
  • Removed armor, weapons and character classes (less code and complexity)

The Prototype

With less features I could write a prototype in almost 6 hours, and I demonstrated it in Berlin at the JS13kGames 2019 hackday alongside with other awesome devs

The Evolution

In the initial prototype two players had just to pick their characters at the beginning and then they were fighting automatically, I've found it boring and probably complex for players to understand what's going on.

So I've changed the gameplay: It became a turn based game, each turn the player chose the character to activate and he moves in a predefined direction then he attacks an opponent.

Other changes I made:

  • The character always attack the nearest opponent
  • The damage is calculated based on the characters distance
  • if the character is hit from the back side the damage is much higher
  • "Characters" became "Ships" :)

Then I polished the UI, added mobile support, and added a ranking based on the Elo rating system

Then the final rules became clear

  • Pick phase: select your 4 ships on the grid.
  • Play phase: When your turn come, you can activate a ship
    • It moves in the active direction (the highlighted arrow below the ship) by 4 cells (when it reach the border the ship wraps on the opposite side)
    • It shots the nearest opponent damaging him by distance between them * 3 (bullets don't wrap the field)
    • If the opponent is hit on the back side the damage is tripled
  • Kill all the enemy ships to win

The 13kb limit

13kb (zipped) seems not much space, but it is a lot if you don't use assets and libraries (or just very small ones like those listed here) there is lot of room to write code. That's why for my game there was no images, only a font and an external library to make sound effects (jsfxr).

Here listed all the game files in the submitted version (minified, unzipped):
List of all the game files

Competitive game

I wanted make a game easy to play but hard to master, it's easy to start playing the game, you have just to click on ships, you can do it without thinking, you can also win plying like this. But it's hard to master, only with practice you can understand which ships are better to pick and which moves to do.

Also I wanted make a game without randomness during the game.
There is an initial random setup when the ships and directions are created and placed on the field before the game starts, but then the game is completely drove by player choices. (only in one case there is randomness involved: when two or more ships are at same distance, the one to shot is chosen randomly, but I plan to remove this behaviour and pick the ship with less HP instead)

Technical details

The game was made for Desktop, Mobile and Server categories using the js13kServer sandbox, it works on Firefox, Chrome, Safari, Opera, and probably on all modern browsers.

Web Sockets are used to send events between the two clients and the server who manage the Game logic.

The client is HTML, CSS and JS based, no canvas involved, I already used this approach in my previous game Spacefield League.

Client side all the dimensions are relative to the viewport, so the interface scales well on all kind of screens, thanks to viewport relative units, rem units, percentages and CSS custom properties.
All animations are made via CSS transitions.

.field {
  --field-size: 90vmin;
  height: var(--field-size);
  width: var(--field-size);
  /* --h and --w are set via js based on server game state */
  --cell-h: calc(var(--field-size) / var(--h));
  --cell-w: calc(var(--field-size) / var(--w));
  background-color: var(--black);
  background-size: var(--cell-w) var(--cell-h);
  /* ... */
}

.field > * {
  position: absolute;
  top: 0;
  left: 0;
  height: var(--cell-h);
  width: var(--cell-w);
  /* again --x and --y are set via js based on server game state, see the next js snippet */
  transform: translateX(calc(var(--cell-w) * var(--x))) translateY(calc(var(--cell-h) * var(--y))) scale(var(--scale, 1));
  /* ... */
}
socket.on('new-pos', (e) => {
  let c = field.querySelector('#' + e.char.id);
  /* ... */
  c.style.setProperty('--x', positionX);
  c.style.setProperty('--y', positionY);
  /* ... */
});

Ships are DIVs clipped via clip-path

.char .body {
  clip-path: polygon(0% 0%, 50% 0%, 100% 0%, 50% 100%);
}

There is a single Game class who manage the game state.
There are also some tests to be sure the game logic is working

const game = new Game();

/* ... */

(async function play() {
  while(game.state === 'play') {

    // get the id of the current turn player
    let pid = game.players[game.turn % 2].id;

    // pick a random available player character
    let cid = pick(game.chars.filter(c => c.owner === pid && c.hp > 0)).id;

    // move that character
    await game.move(pid, cid);
  }

  // at a certain point the game should end
  assert.ok(game.state === 'game-over');

  console.log('Game test OK');
})();

Future Plans

  • Improve the game thanks to all the feedbacks from experts and other competition's participants
  • Add a real login
  • Add a turn timer
  • Manage disconnections / re-connections
  • Progressive web app and port on other platforms (like messenger instant games or mobile stores)
  • Remove randomness on shots when more ships are at same distance
  • Web monetisation

Links
JS13KGames
Entry page
GitHub repository
Play the game!

Results

The result was so good and unexpected

Overall: 19th place
Mobile: 5th place
Server: 1st place

Discussion

pic
Editor guide
Collapse
rooktko profile image
Olaf Minkowicz

That's super cool. I play tft too, so it's awesome to see a game being made with it as an inspiration.