Session IV

Typing Game

24. Nov. 2021, 14:00-17:00

Artful Coding 1: web-based games development

dieAngewandte

the concept

html

the scaffold


              <!DOCTYPE html>
              <html lang="en" dir="ltr">
                <head>
                  
                  
                  The Hitchhikers Guide to the Typing Machine
                </head>
                <body>
                  

The Hitchhikers Guide
to the Typing Machine

A digital drawing of a typewriter.
</body> </html>

the content


              

— Hit the start button to get the first quote —

Completed quotes:

  • ...
footer content goes here

css

body and header


              body div.container {
                width: 800px;
                margin: auto;
              }


              /* === The Header Section === */
              header {
                display: flex;
              }
              header div:first-child {
                width: 600px;
              }
              header div:last-child {
                width: 200px;
              }
              header img {
                width: 100%;
              }
              header h1 {
                font-size: 42px;
              }
            

content and stats


              /* === The Content Section === */
              div.content {
                display: flex;
              }
              div.content div {
                width: 600px;
              }
              div.content aside {
                width: 200px;
              }

              footer {
                text-align: center;
                border-top: 1px dotted gray;
                padding-top: 1em;
                margin-top: 2em;
              }


              /* === The Stats Section === */
              #stats {
                border: 1px dotted gray;
                border-radius: 3%;
                margin: 0.8em;
                padding: 0.5em;
              }
            

main game


              /* === The Main Game Section === */
              #main-game {
                text-align: center;
                margin-bottom: 4em;
              }
              #current-quote {
                font-size: 1.2em;
              }
              #input {
                width: 90%;
                border-radius: 10px;
                padding: .7em;
                font-size: 1.2em;
              }
              #main-game div.action-button-container {
                margin-top: 1em;
              }
              #main-game div.action-button-container button {
                font-size: 1.5em;
                padding: .3em;
                margin: 0 .4em;
              }

              .correct {
                background-color: #afa;
              }
              .incorrect {
                background-color: #faa;
              }
            

javascript

quotes


              const quotes = [
                "Don't panic!",
                "Time is an illusion. Lunchtime doubly so.",
                "Would it save you a lot of time if I just gave up and went mad now?",
                "The ships hung in the sky in much the same way that bricks don't.",
                "I'd far rather be happy than right any day.",
                "Space is big. You just won't believe how vastly, hugely, mind-bogglingly big it is.",
                "I mean, you may think it's a long way down the road to the chemist's, but that's just peanuts to space.",
                "For a moment, nothing happened. Then, after a second or so, nothing continued to happen.",
                "Ford... you're turning into a penguin. Stop it.",
                "A towel is about the most massively useful thing an interstellar hitchhiker can have.",
                "The Answer to the Great Question... Of Life, the Universe and Everything... Is... Forty-two",
                "So long, and thanks for all the fish.",
                "Anyone who is capable of getting themselves made President should on no account be allowed to do the job.",
                "We demand rigidly defined areas of doubt and uncertainty!",
                "That's just perfectly normal paranoia. Everyone in the Universe has that.",
                "If I asked you where the hell we were, would I regret it?",
              ]
            

the stats


              const stats = {
                words: 0,
                characters: 0,
                time: 0,
                fastest: {
                  quote: '',
                  time: 0,
                },
                achievements: {
                  ftl: {
                    label: '',
                    explanation: '',
                    unlocked: false
                  },
                  dontpanic: {
                    label: '',
                    explanation: '',
                    unlocked: false
                  },
                  fourtytwo: {
                    label: '',
                    explanation: '',
                    unlocked: false
                  },
                },
                reset: function () {
                  this.words = 0
                  this.characters = 0
                  this.time = 0
                  this.fastest.quote = ''
                  for (const key in this.achievements) {
                    this.achievements[key].unlocked = false
                  }
                }
              }
            

globals and init functions


              let uncompleted = []
              let timeStart
              let typingErrors

              // little helper function to get a random integer
              function randInt(max) {
                return Math.floor(Math.random() * max);
              }

              function resetQuotes () {
                let quotePool = [...quotes]
                // use the following for debugging, to get a quick test sentence first
                //uncompleted.push('Test sentence.')
                while (quotePool.length > 0) {
                  let i = randInt(quotePool.length)
                  let [quote] = quotePool.splice(i, 1)
                  uncompleted.push(quote)
                }
              }

              function resetCompletedQuotes () {
                $( '#completed ul' ).children().remove()
              }

              function resetGame () {
                resetCompletedQuotes()
                resetQuotes()
                stats.reset()
                $( '#input' )
                  .removeClass('correct')
                  .removeClass('incorrect')
                  .attr('disabled', 'true')
                  .val('')
                $( '#current-quote' ).html('— Hit the start button to get the first quote —')
              }
            

setting up next quote


              function nextQuote () {
                $( '#success' ).text('')
                $( '#current-quote' ).text(uncompleted[0])
                $( '#input' )
                  .removeClass('correct')
                  .removeClass('incorrect')
                  .val('')
                  .removeAttr('disabled')
                  .focus()
                timeStart = Date.now()
                typingErrors = 0
              }
            

processing input


              function processInput () {
                $input = $( '#input' )
                quote = uncompleted[0]
                value = $input.val()
                if ( quote.startsWith( value ) ) {
                  $input.addClass('correct')
                  $input.removeClass('incorrect')
                } else {
                  // only count a typing error if the sentence was not already incorrect
                  if (! $input.hasClass('incorrect')) {
                    typingErrors++
                  }
                  $input.addClass('incorrect')
                  $input.removeClass('correct')
                }

                if ( quote === value ) {
                  let timeEnd = Date.now()
                  seconds = ( timeEnd - timeStart ) / 1000
                  $input.attr('disabled', 'true')
                  $( '#success' ).text('Wonderful! You completed this quote in '+seconds+' seconds with '+typingErrors+' typing errors.')
                  $( '#completed ul' ).append( $( '
  • '+quote+'
  • ' ) ) uncompleted.splice(0, 1) } // now check if this was the last quote if ( uncompleted.length === 0 ) { $( '#start' ).remove() $( '#reset' ).remove() $( '#game-completed' ).show( 'slow' ) } }

    get everything going

    
                  $( document ).ready(function () {
                    resetGame()
                    $( '#reset' ).on('click', resetGame)
                    $( '#start' ).on('click', nextQuote)
                    $( '#input' ).on('input', processInput).val('')
                  })
                

    The final prototype

    The Hitchhikers Guide to the Typing Machine!

    What up next?

    You could:

    • Use a different story / framework for quotes
    • Improve the styling, to make the game visually appealing
    • Use effects / animations / sounds on success or errors
    • Implement the statistics widget functionality

    Minimal effort for this exercise: some styling

    If you want to go for substantial extensions and changes, this can already count towards your final project.