Latest news about Bitcoin and all cryptocurrencies. Your daily crypto news habit.
In this article, we will create a Progressive Web Application!Donāt worry, we wonāt make another todo list. Instead, we will build a fun game that satisfies Googleās checklist for building aĀ PWA.
You can play it here and check the final source code onĀ Github.
1- Requirements: what do we want toĀ achieve?
Letās first understand what we want toĀ achieve.
Here are the gameās functional requirements:
- There is a 4 x 3 (4 rows, 3 columns) grid ofĀ cards.
- By default, each card shows its back and hides a certainĀ emoji.
- There are in total 6 unique emojis. Each emoji is duplicated, making the total number of emojisĀ 12.
- The player can flip any card that has not been matched yet, showing the emoji behindĀ it.
- If the player flips their second card and it does not match the previously flipped one (i.e. they donāt have the same emoji), then both cards are flipped back to their initial position.
- If the player flips their second card and it matches the previously flipped one, then both cards are matched and the playerās score is incremented.
- The maximum score is 6 (1 point per matched pair). Once the player reaches the maximum score, the game ends with a displayed winningĀ message.
Our game should also satisfy the following items to be considered aĀ PWA:
- The game is served overĀ HTTPS.
- All pages are responsive on tablets and mobileĀ devices.
- The game can be added to the home screen of the userās device and look like a nativeĀ app.
- Offline Loading: The game should be functional offline.
- Fast firstĀ load.
- Page transitions donāt feel like they block on theĀ network.
- Each page has aĀ URL.
2- Designing ourĀ pages
Before we jump into code, letās grab a pen and paper and draw what our pages will lookĀ like.
To keep it simple, the home page will just have the gameās title and a button to start a newĀ game:
The game page is basically a grid of cards and the score of the player aboveĀ it:
The cards can be either in the default, flipped or matchedĀ state:
The winning page is just a š emoji, a congratulations text below it and a button to start a newĀ game:
3- Bootstrapping the application with preact-cli
Now that we have our requirements in place, letās kick off our application development. We can quickly bootstrap our application using preact-cli.
First, letās install it globally:
npm i -g preact-cli
Then letās use preact-cli to bootstrap our match-game:
preact create match-game
The generated source code has the following structure:
āāā src āāā assets āāā components āāā index.js āāā manifest.json āāā routes āāā style
- assets will contain our assets (favicon and otherĀ icons)
- components will have our preact components including the main App component
- index.js is the entry point to our application
- manifetst.jsonĀ : will provide information about the icons of our game in AndroidĀ devices.
- routes will contain ourĀ routes.
- style will have global CSS for the application.
Letās empty both the components and routes directories since we will build our components and routes fromĀ scratch.
4- Setting up theĀ routes
Our game will have 3Ā routes:
- / Home route: points to the homepage containing the gameās title and a button to startĀ playing.
- /game Game route: points to the game page containing the score and the grid of cards to beĀ flipped.
- /win Win route: points to the winning page showing a message to congratulate the user afterĀ winning.
Letās first create theseĀ routes:
Home route:
Game route:
Win route:
Letās also configure our router in the App component:
5- Building theĀ pages
Now that we have our routes ready, we can start building theĀ pages.
First, letās define some global styles in the styles/index.css file. We will use the āPress Start 2Pā font, which is very common inĀ games.
After downloading the font and placing it inassets/fontsĀ , our final index.css should look likeĀ this:
The homepage
The homepage is quite simple since itās just a header and a button to start a newĀ game.
The button redirects to the /game route. Although we can either use a Link from preact-router (which acts as an anchor) or a button, a button, in this case, is more accessible due to its nativeĀ styling.
Note: we are importing the home styles from ā./style.cssā. This is because preact-cli provides out of the box support for CSS Modules! If you donāt know anything about CSS Modules and you donāt want to learn about them now, you can still continue the tutorial without a problem. All what you have to understand is that in order to map the styles of a JSX node in index.css to a CSS declaration in style.cssĀ , we just need set its class name to the corresponding declaration name (e.g. style.home is mapped to the CSS declaration with class name homeĀ ).HomepageThe winningĀ page
The winning page is actually very similar to the home page, except that it will have the winning message instead of the gameāsĀ title.
Winning PageThe card component
Letās first build the card component so that we can use it in the gameāsĀ grid.
The card component has a back and aĀ front.
- The component receives a value to hide, a flipStatus (whether itās DEFAULT, FLIPPED or MATCHED), and onClick listener to control the click on theĀ card.
- The front of the card is by default a question mark to show that the card is hiding something.
- The back has the hiddenĀ value.
Note: The CSS flip animation is inspired from here. The link is a really good source if youāre curious about how itĀ works.
The final result looks likeĀ this:
flipStatus = āDEFAULTāflipStatus = āFLIPPEDāflipStatus = āMATCHEDāThe gameĀ page
Every time we start a game, we should shuffle the positions of our cards. Moreover, every card should have a unique key to identify it in the grid and an emoji value. To do so, we can create a shuffling function in the App component and pass down its resulting cards to the GameĀ route:
Note: the schuffling function generateGridCards by creating an array that has two duplications of the emojis array, sorting the array randomly, and then mapping each emoji to a card object containing a unique key (the index) and the emojiĀ value.
We can represent the gameās state in a way that reflects exactly the requirements we discussed in the firstĀ section:
- state.flippedCards = { first: {}, second: {} }: only 2 cards can be flipped at the same time before deciding whether the player has a match or not. Thus, state.flippedCards contains the currently first and second flippedĀ cards.
- state.isMatched = {}Ā : is a map of emojis that were matched. Whenever the player matches a pair of cards, the corresponding emoji is set to true in this object. This helps us determine which cards were watched when rendering.
- state.score = 0Ā : the score of the user, which is 0 initially.
To get a cardās flip status (āDEFAULTā, āFLIPPEDā, or āMATCHEDā), we can do so based on state.flippedCards and state.isMatched objects:
- If the card is one of the state.flippedCards, then the card is actuallyĀ flipped.
- If the cardās emoji is in the isMatched map, then the card isĀ matched.
- Otherwise, the card is just in its default flipĀ status.
When the player flips a card, the following can beĀ done:
- If itās the first flipped card, then we simply set it in the state.flippedCardsĀ .
- If itās the second flipped card, then we simply set it in the state.flippedCards and check whether we got a match orĀ not.
- In case of a mismatch, we simply flip back the cards by resetting the state.flippedCards to its defaultĀ value.
- In case of a match, we wait 500 ms and then add the emoji of the card to the state.isMatched map (so that the user has enough time to see which cards are flipped before the match). We also increment the score and redirect the player to the winning page in case they reached the maximumĀ score.
When it comes to styling the gameās grid, we have THE perfect case for CSSĀ grid.
Andā¦ thatās it! The game should be complete by now!Ā š»
Game PageFinal touchesFinal icon of the game onĀ iOS
To do so, we first need to generate icons for Android and iOS. To keep things simple, we can choose our Card component to be the icon of theĀ game.
Once we have a screenshot of the Card component, we can use a tool like this to generate the different sizes of icons and place them in the assets/icons directory.
For iOS, we need to add special link tags pointing the apple-touch-iconĀ . In order to achieve that, we can create a template index.html in the src directory that has the required link tags. The following template is basically the default template of preact-cli with our link tags added toĀ it:
We can then modify our production NPM scripts in order to use the template:
"scripts": {
"build": "preact build --template src/index.html",
"serve": "npm run build && preact serve"
}
We also need to modify the src/manifest.json file in order to reflect our Android icons and gameāsĀ title:
We created aĀ beast!
Itās time to evaluate our game based on the requirements we set at the beginning.
To build the game, we can use the build NPMĀ script:
npm run build
The gameās build result should be available in the /build directory. We can then easily deploy and host the build directory somewhere likeĀ ā²now.
Letās then finally take a look at our gameās functional requirements and PWA checklist and see what we have achieved:
- ā The gameās functional requirements areĀ met.
- ā The game is served over HTTPS: this is supported out of the box by preact-cli.
- ā All pages are responsive on tablets and mobileĀ devices.
- ā The game can be added to the home screen of the userās device and look like a nativeĀ app.
- ā Offline Loading: The game can be totally functional offline! Once you add the game to the home screen, you can play it anytime without the need for Internet connection.
- ā Page transitions donāt feel like they block on the network: we literally have instant page transitions!
- ā Each page has a URL: this was met by having a route for eachĀ page.
Running Googleās Lighthouse tool gives the following:
Results of running Lighthouse tool on the deployedĀ game.Looks like the only thing we can further improve is our SEO skillsĀ š¤To wrap it upĀ š
It was really fun building this PWA. I hope you find this article useful enough to build your own PWA. If you do so, please share a link to it in the comments section. I would be really happy to check itĀ out.
I will also love to hear your feedback or questions if you haveĀ any.
P.S: you can find me over on twitter at @seif_ghezala. DMs are welcomeĀ :)
How to Create a PWA Game using Preact in 5 steps (Tutorial) was originally published in Hacker Noon on Medium, where people are continuing the conversation by highlighting and responding to this story.
Disclaimer
The views and opinions expressed in this article are solely those of the authors and do not reflect the views of Bitcoin Insider. Every investment and trading move involves risk - this is especially true for cryptocurrencies given their volatility. We strongly advise our readers to conduct their own research when making a decision.