How to Build Hangman in Ember
We’ll call it Emberman, but it’s essentially the same game.
Wrapping your mind around Ember can be a struggle at first. There are many moving parts. Coming from a React background, Ember has a different taste and feel. However, like anything, with practice, you will get it.
We are going to kick-start your practice by building a simple word guessing game. The intention is to pull a bunch of random words from a word api. We will pick a random word and display __ (underscores) for each letter in the random word. If the player guesses a letter that is in the random word, we will display the letter instead of the underscore. Otherwise, we will show their incorrectly guessed letter in the incorrect letter section of the board. After a certain number of incorrect guesses, they will lose and the computer will score a point. This continues until the game is over.
Let’s begin!
Get Set Up
- create a new repo or local project
- visit the ember docs. These will be the best resource for learning ember.
- run
npm install -g ember-cli
- run
ember new my-new-app
to create your app - cd into your new app folder
- run
ember serve
Now you are up and running! You have a new ember app. You can connect this to a github repo if you like or keep it local.
Creating Your Routes
The first part of the Ember MVC set up is your routes.
For this game we want to make two routes: home and play. Home will be our main app page and then play will be our game board page.
Note: the app already comes with an application route. Just leave this as is. You will also see two other files which you can leave alone: app.js and index.html
To make your two routes use:
- ember g route home
- ember g route play
Now you have your two routes.
Home will serve as your home page so when you boot up your app and go to localhost:4200, that is your home route. localhost:4200/play is your game page route.
In your route play.js:
- create a store to hold the words from the api
- fetch the words from the api using fetch
- push your words into the store
Basic Ember Structure: Ember uses routes, templates, controllers, components, models, helpers, and styles. I know, it’s a lot when you are new to it.
Routes: make the different main pages/routes for your app
Templates: the main HTML for your app
Controllers: the logic and action for the HTML — where your javascript will be written
Components: smaller (reusable) pieces of your app such as a button, input, modal, etc.
Models: objects that represent the data in your app, not the same thing as the model methods you may use in your routes
Helpers: helper functions you can call from templates, keeps your templates clean
Styles: css style sheets
Making Templates
The Ember UI is built on html. Our main HTML will be stored in templates.
Templates are the basis of our app. In this case app, home, and play routes will all have templates.
Ember also uses Handlebars templates so all of your template files will end with .hbs as in play.hbs signifying a handlebars play template.
We want application.hbs (which comes with the app set up), home.hbs, and play.hbs.
Application.hbs will start out with {{outlet}}. This tag is basically an open door to all your other templates. Home.hbs and play.hbs will be rendered via {{outlet}} in your UI.
For this application, there is also a <header> for the app title and <footer>— these are both unnecessary and your application.hbs file could simply contain {{outlet}}, but this is ours:
In home.hbs we’ve added a button that starts the game and routes to our play gameboard page.
Now we want to write out our HTML in play.hbs. Inside this file we want to:
- add a section to display the correctly guessed letter or __ underscores if the letters haven’t been guessed yet
- add a section to display incorrectly guessed letters
- add a score container for player 1
- add a score container for player 2/CPU
- create the Keyboard component using “ember g component Keyboard” — *this is a stylistic choice, you could make an input or something else for guess input, but we have chosen to make a keyboard
- add the Keyboard component to your play template and eventually you will want to pass it props from the play controller
You can build your layout however you like. Play with your creative freedom and have fun! Here is a sample of the play.hbs file from this project so you can visually get familiar with the syntax.
At this point you might really be getting into your app and are feeling ready to style it! Trust me, there is a lot more to do, but here are the basics for styling.
Styles
Add classes to your elements in order to style them.
You will need to install ember install ember-cli-sass
In your style folder you already have app.scss. This will apply styles to your whole app, but you will write your styles in stylesheets for each template/component.
In app.sccs import the component stylesheets
Inside the style folder make a new folder called “Components”. Add your other stylesheets here such as _play.scss.
Note: Style classes are applied globally. If you use .word_container as a css class in play.hbs and in home.hbs, the same styles will apply in both template files.
Models
Models are objects that represent your data. We now have data from our api so let’s make a model. This model will be for our words and another one for our guesses.
- ember g model words
- ember g model guesses
Controllers
In our controller lies all of the logic (JS).
Let’s look at the play controller, our only controller for this game.
In here we want quite a bit of functionality.
- access to the store
- pieces of state: our guesses, words that have been used, the randomly chosen word, the player and cpu score, and whether or not the game has ended
We need several functions. We want them all to be as DRY as possible. We need a function to:
- get a new random word from our array of words
- start a new game, which resets the player scores and selects a new word
- add our guesses to a guesses array
- check the status of the game (if the player has guessed less than 6 incorrect letters the player gets to keep guessing, otherwise the round is over, the CPU wins, and a new round is triggered) and see if the game has ended (if player 1 or the CPU gets 3 points, the game ends)
- check to see if player 1 or CPU has 3 points
- check to see if there have been 6 or more incorrect guesses
- make a new round
You can write the rules to your game and determine when a round ends, how many rounds there are, when the game ends, etc.
Challenge yourself to figure out the logic behind these functions, but we will show two parts that are particular to Ember.
Here are tracked pieces of data. These can be thought of as similar to pieces of state in a React component while the store is like a Redux store.
Here is our getNewWord function. The point of showing this is to demonstrate how we get values out of the store
- const wordsFromStore = this.store.peekAll……
And how to call on tracked values with this
- this.useIndicies
Now we presumably have all the logic we need to make our game work.
How do we call on this controller?
Let’s go back to route play.js
We can call on the controller for play, invoke our getNewWord function to get a new word and then set our randomWord piece of state to the value of that new random word which we stored as newWord.
It is not very obvious when you are new to the set up, but this is essentially how you are pass data between routes and controllers and save it in state.
Helpers
You may have noticed something interesting about our if statements in the play.hbs template, or maybe even the fact that there was an if statement in our HTML to begin with.
These are our helper functions. They keep our HTML clean while also allowing us to compute values and render different parts of our UI based on those values.
{{#each}} is an iterator
For each letter, we are checking some conditional logic
{{#if incorrect-letter is true show the letter}}
Incorrect-letter is our helper
We are passing the helper our randomWord and the letter guessed.
Inside the helper it is checking to see if our randomWord does not include the letter. If it does not, it will return true and display the incorrect guess.
Components
The last part of our app are the components, pieces of our app that we have separated out to keep our code DRY.
In this case we have header, footer, button, modal, and keyboard components.
This are all design-based choices. You do not need to create these.
However, the example has a header and footer, a button that starts the game, and modal that says the game is over and asks if you would like to play again, and a keyboard that displays all letters of the alphabet so you can make your guess.
Here is an example of the button component:
And the keyboard component:
The keyboard also has some logic which is store in a separate keyboard.js file:
Well that’s it!
You have what you need to struggle a bit, but also the fundamentals to make a simple word game.
It took me about 10 hours of study, so find your api and persist!