Electron Adventures: Episode 77: Cookie Clicker Game
Tags: javascript, electron, jquery
Published: 2021-10-08 12:22:46

The series has been going for a while now, and somehow I never got to the key subject of packaging. The main appeal of Electron apps is that they can be packaged and distributed, so the users can run them without having to install any dependencies. Even something as seemingly simple as "install Java" invariably leads to endless tech support issues.

I want to try two scenarios, and then try to package them. First, a purely static app. And then an app with compiled SPA backend like Svelte or React.

So before we get to packaging, let's build a simple static app - cookie clicker game. To have a few different types of assets to package we'll use:

* [cookie picture from Wikipedia](https://en.wikipedia.org/wiki/Cookie#/media/File:2ChocolateChipCookies.jpg)
* [coin sound from freesounds](https://freesound.org/people/ProjectsU012/sounds/341695/)
* jQuery from npm package

The game will be totally trivial. Click the cookie, it plays sound and increases score.

### Setup

```
$ npm install --save-dev electron jquery
```

### `package.json`

```javascript
{
  "devDependencies": {
    "electron": "^15.1.1",
    "jquery": "^3.6.0"
  },
  "scripts": {
    "start": "electron ."
  }
}
```

### `index.js`

We just need to open `index.html`. I left empty `preload.js` just in case we need it for something.

```javascript
let { app, BrowserWindow } = require("electron")

function createWindow() {
  let win = new BrowserWindow({
    webPreferences: {
      preload: `${__dirname}/preload.js`,
    },
  })
  win.loadFile("index.html")
}

app.on("ready", createWindow)

app.on("window-all-closed", () => {
  app.quit()
})
```

### `index.html`

The cookie will be in the `body`, and `#score` will display the score. That's the whole game!

```html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="app.css">
    <title>Cookie Clicker</title>
  </head>
  <body>
    <div id="score">Score: 0</div>
    <script src="./node_modules/jquery/dist/jquery.js"></script>
    <script src="./app.js"></script>
  </body>
</html>
```

### `app.css`

To prevent some complications depending on where exactly the user clicks, we need to tell the browser we don't want the score to be clickable (`pointer-events: none`) or selectable (`user-select: none`).

```css
body {
  margin: 0;
  padding: 0;
  overflow: hidden;
  background-image: url("cookie.jpg");
  background-size: cover;
  background-repeat: no-repeat;
  height: 100vh;
  width: 100vw;
}

#score {
  pointer-events: none;
  user-select: none;
  font-size: 36px;
  font-family: fantasy;
}
```

### `app.js`

And finally the game logic. The only non-obvious thing is that we need to set `audio.currentTime = 0`. If user clicks while the sound is playing, we want it to start the sound from the beginning. Having just `audio.play()` without rewinding there would ignore the call, and that's a much worse experience.

Alternatively we could play multiple sounds at once, but that could be quite jarring if someone clicks really fast.

```javascript
let score = 0

let audio = new Audio("coin.wav")

$("body").on("click", (e) => {
  e.preventDefault()
  score += 1
  $("#score").text(`Score: ${score}`)
  audio.currentTime = 0
  audio.play()
})
```

### Results

Here's the results:

![Episode 77 Screenshot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qrjpnyoxpwpelon6ulpg.png)

Now that we have a simple static app, in the next episode we'll try to package it into something users can just download and run without installing any dependencies.

As usual, [all the code for the episode is here](https://github.com/taw/electron-adventures/tree/master/episode-77-cookie-clicker-game).