Vanilla JS "Who's that Pokémon?" game with the PokéAPI
Tags: javascript, webdev, beginners, tutorial
Published: 2021-10-06 18:24:18

Remember that *"Who's that Pokémon?"* TV game? Well we can build our own version of this with the [PokéAPI](https://pokeapi.co/)!

If we make a `fetch` call to this endpoint (and specify that we want to limit it to the first 151 Pokémon), we'll get a results array:

```js
(async () => {
  const res = await fetch('https://pokeapi.co/api/v2/pokemon?limit=151');
  const json = await res.json();
  
  console.log(json.results);
})();

// Logs:
[
  {name: 'bulbasaur', url: 'https://pokeapi.co/api/v2/pokemon/1/'},
  {name: 'ivysaur', url: 'https://pokeapi.co/api/v2/pokemon/2/'},
  {name: 'venusaur', url: 'https://pokeapi.co/api/v2/pokemon/3/'},
 // ...
]
```

That `url` property inside each object is the pokémon-specific endpoint that can be hit for more information about that individual character. Inside this JSON, there will be a sprite URL like so: 
`https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png`

This is the sprite for Pokémon `#1`:
<img src="https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png">

Since we saw in the original data that Bulbasaur's `url` property shows its number  (`1`), and this number is the same that's used in the sprite URL, we can use just this original request to get all the information we need to create a "Who's that Pokémon?" game:

<img src="https://res.cloudinary.com/dzynqn10l/image/upload/v1633385632/JS%20Bits/bulbasaur_kga7x0.jpg">

The full code for this project is hosted [here](https://github.com/doctafaustus/whos-that-pokemon), but the rest of this article will show the core components we'll need to make this work.

First, our HTML structure:
```html
<main class="fetching">

  <div id="pokemon-container">
    <img id="pokeball" src="background.jpg">
    <img id="pokemon-image" src="placeholder.png">
  </div>

  <div id="answer">
    <div id="bg-overlay"></div>
    <div id="text-overlay"></div>
  </div>

  <section id="controls">
    <button id="play">Play</button>
    <div id="choices"></div>
  </section>
</main>
```

The `#pokemon-image` source will be set dynamically to show the featured pokémon, and the `#choices` element will be populated with multiple-choice answers from the PokéAPI data. The steps to get the need we'll need is as follows:
```js
getPokeData = async function() {
  const pokemon = await getPokemon(); // #1
  const randomPokemon = shuffle(pokemon); // #2
  const pokemonChoices = get4Pokemon(randomPokemon); // #3
  const [ firstPokemon ] = pokemonChoices; // #4
  const image = getPokemonImage(firstPokemon); // # 5

  return { 
    pokemonChoices: shuffle(pokemonChoices),
    correct: {
      image,
      name: firstPokemon.name,
    }
  };
};
```


1) Fetch the array of 151 Pokémon objects (show above).

2) Shuffle the array show we can show a random group to the user:
```js
function shuffle(unshuffled) {
  const shuffled = unshuffled
    .map((value) => ({ value, sort: Math.random() }))
    .sort((a, b) => a.sort - b.sort)
    .map(({ value }) => value);
  
  return shuffled;
}
```

3) Save the first 4 objects from this shuffled array:
```js
function get4Pokemon(randomPokemon) {
  return randomPokemon.splice(0, 4);
}
```

4) Save a reference to the first Pokémon object (the one we'll feature).

5) Return an object containing the 4 Pokémon choices (shuffled again), and a "correct" object, containing both the name of the featured pokémon and the image URL to show:
```js
function getPokemonImage({ url }) {
  const number = getNumber(url);
  return `https://raw.githubusercontent.com/PokeAPI/` +
  `sprites/master/sprites/pokemon/${number}.png`;
};

function getNumber(url) {
  const numberRegEx = /(\d+)\/$/;
  return (url.match(numberRegEx) || [])[1];
}
```

We'll then plug this URL source into our `<img id="pokemon-image">` element and set the brightness of the PNG to `0` with CSS:
```css
#pokemon-image {
  transform: scale(2.5);
  filter: brightness(0);
  transition: filter .5s ease-out;
}
```

And generate our `#choices` content with answer buttons:
```js
const { pokemonChoices } = gameData;
const choicesHTML = pokemonChoices.map(({ name }) => {
  return `<button data-name="${name}">${name}</button>`;
}).join('');

choices.innerHTML = choicesHTML;
```

Once we hook up some additional event handlers and logic to check if the `dataset.name` selected matches the correct pokémon, we can toggle some classes to reveal both the right answers and show the full-color pokémon image!

<img src="https://res.cloudinary.com/dzynqn10l/image/upload/v1633387082/JS%20Bits/bulbasaur-revealed_fadwt7.jpg">

Project code available here: [https://github.com/doctafaustus/whos-that-pokemon](https://github.com/doctafaustus/whos-that-pokemon)

#### Full YouTube Tutorial:
<a href="https://www.youtube.com/watch?v=iBR-Pmr-l6E" target="_blank">
  <img src="https://res.cloudinary.com/dzynqn10l/image/upload/v1633388056/JS%20Bits/maxresdefault_hvhdzq.jpg" />
</a>

----------
<b>Yo!</b> I post byte-sized tips like these often. Follow me if you crave more! 🍿

I'm on [TikTok](https://www.tiktok.com/@js_bits), [Twitter](https://twitter.com/JS_Bits_Bill) and I have a new [debugging course](https://jsbits-yo.com/bug-bash/) dropping soon!