Tag Archives: Vue

Creating a Running Game in VueJS – Part 5 – Gameplay and Graphics

In this, the fifth and final instalment of my series on creating a game using VueJS, we’re going to improve the gameplay a little, and we’re also going to replace our squares and oblongs with graphics.

If you’re new to this series, I’d encourage you to jump back to the first post.

The code for this post is here.

Gameplay and Tidy up

If you’ve played around with the game, you’ll realise there’s quite an easy way to cheat – if you simply press both keys at the same time, it behaves as though you were pressing the keys in quick succession (which, in fact, you are). Let’s stop that by adding a slight delay.

  
onKeyDown(e) {      
            if (this.lastPressed + 50 > Date.now()) {
                return;
            } else {
                this.lastPressed = Date.now();
            }

lastPressed is just added to the data properties.

Next, you may have noticed that we can run past the finish line, and the game continues after it’s finished… which actually means it’s impossible to win, because if you win, once the time gets to zero, you lose.

We can fix this pretty easily by simply stopping the timer once the game is finished; in App.vue, the update function should have the following code where we check when the player passes the finish line:

if (this.playerX > this.finishLine) {
    this.isGameFinished = true;
    this.playerWon = this.isGameFinished && (this.secondsRemaining > 0);
    clearInterval(this.interval);
}
if (this.secondsRemaining <= 0) {
    this.isGameFinished = true;
    this.playerWon = this.isGameFinished && (this.secondsRemaining > 0);
    clearInterval(this.interval);
}

this.interval is set in the init method:

init() {
    this.interval = setInterval(this.update, 10);
    this.startTime = new Date();
    this.startTime.setSeconds(this.startTime.getSeconds() + 20);
},

The next thing we need is to replace our box with some actual graphics.

Graphics

The principle behind animation (any animation, not just in a game) is that you take a series of still picture, and play them rapidly.

I couldn’t find a spritesheet of anyone running, so I created some images of my own; they look absolutely ridiculous, and are essentially made up from using the filled circle and rounded corner rectangle in paint – but then I never claimed to be any good at graphics art. Anyway, for the purpose of this, I’ve dropped them in the assets folder:

It’s a pretty good bet that you (the reader) is better at graphics art than I am, so I would strongly encourage you to not use my graphics if you’re following along. However, they’re in the GitHub repo if you wish to.

To start with, we’ll need to store the names of the images, and the last time we switched the image; so we’ll add a couple of variables to the App.vue script:

const images = [ "daley-1.png", "daley-2.png", "daley-3.png" ];
let lastSwitch = (new Date()).getTime();

We’ll also need a data property to track which image we’re displaying:

    data: function() {                    
        return {
            . . .
            currentImageIdx: 0            
        };
    },

The next step is to slightly change our GameObject such that we now display an image:

<template>
    <div v-bind:style="location">
        <img v-bind:src="image" />
    </div>
</template>
<script>
export default {
  name: 'GameObject',
  props: {
    type: String,
    location: String,
    image: String
  }
}
</script>

In App.vue we’ll need to bind that image:

<GameObject
    v-bind:location="playerLocation"
    type="player"
    v-bind:image="playerImage">
</GameObject>

And a computed property to return it:

playerImage: function() {                        
    return require("./assets/" + images[this.currentImageIdx]);
},

That’s pretty much it; all that remains is to cycle through the images. I’ve done this in the update method, and tried to make it faster as you run faster:

if (this.speed > 0) {
    const refreshSpeed = 1000 - (this.speed * 3);
    if ((new Date()).getTime() > lastSwitch + refreshSpeed) {
        this.currentImageIdx = 
            (this.currentImageIdx < images.length - 1) 
            ? this.currentImageIdx + 1 : 0;
        lastSwitch = new Date().getTime();
    }
}

It’s not perfect, but it roughly looks like he’s running faster as you move him faster.

Summary

This is going to be the last post of my very poor attempt to recreate the amazing Sprectrum game of my youth. As I said at the start, I always find this a useful way to try to learn a new front-end framework – you need to learn about how and when the screen is rendered, and how it deals with interesting things like displaying graphics, updating data, etc.

Creating a Running Game in VueJS – Part 3 – Component Files and Installing Vue

This is the third part in a series on replicating a game similar (in some respects) to the ZX Spectrum game “Daley Thompson’s Decathlon”.

To start from the beginning of the series, go here.

In this particular post, we’ll be continuing our refactor by moving out components into their own files.

If you’d like to see the code from this post then it’s on GitHub here.

Install Vue and Create a New App

The first thing you’ll need to do here is to install Vue:

npm install vue

Once this is done, we’ll just create a brand new templated Vue project:

vue create vue-app

What we’re essentially going to do here is to copy our existing program from part 2 into the new application, but using separate files for components. All we actually have now is a single file (index.html).

Copying Code

Your new app should look broadly like this:

Let’s start by creating a new component called Timer, this will be the successor for our seconds-remaining component:

Now, let’s take the code from our component and paste it in. We’ll start with the template; the current template is:

template: `
    <p>Seconds remaining: {{ seconds }}</p>
`

And that will become:

<template>
    <p>Seconds remaining: {{ seconds }}</p>
</template>

Next we need the props; so the following:

props: ['seconds'],

Will become:

<script>
export default {
  name: 'Timer',
  props: {
    seconds: Number
  }
}
</script>

Since we have no style, that’s done:

Next, we’ll bring across the player component in the same way:

The next stage is to update App.vue component. The template will now look like this:

<template>
  <Player
      v-bind:location="location">
  </Player>
  <Timer 
      v-bind:seconds="secondsRemaining">
  </Timer>            
</template>

Inside the script tag, we’ll bring in the Player and Timer components:

<script>
    import Player from './components/Player.vue'
    import Timer from './components/Timer.vue'

Next, we need to define which components we’re using:

export default {
  name: 'App',
  components: {    
    Player,
    Timer
  },

We then need our data tag, which now needs to be a function:

  data: function() {                    
    return {
      playerX: 100,
      playerY: 100,
      speed: 0,
      toggleSpeed: 1,                    
      startTime: 0,
      timeNow: 0
    };
  },

The rest can come across as is (please see the GitHub repo for these).

Finally, you can remove HelloWorld.vue.

Now that we have the code inside components, in the next part, we’ll add a finish line, and a way for the player to win or lose.

Creating a Running Game in VueJS – Part 2 – Components

This is the second post in a series that started here. If you’d like some context, then please visit the first post. In this post, I’ll be refactoring the small amount of code that we currently have, into Vue Components.

You can find the code for this post here.

Refactoring into Global Components

Let’s start with a very simple component, and that’s the display of “Seconds Remaining”. For the time being, we’ll create this in the same file, so all we’re doing here is shuffling code around. Instead of the following code:

<p>{{ secondsRemaining }}</p>

We’ll add this:

<div id="app">
    <div v-bind:style="location"></div>
    <seconds-remaining 
        v-bind:seconds="secondsRemaining">
    </seconds-remaining>            
</div>

A quick note on this, you may see the following syntax:

<div id="app">
    <div v-bind:style="location"></div>
    <seconds-remaining 
        :seconds="secondsRemaining">
    </seconds-remaining>            
</div>

Essentially, here the v-bind is implicit. Both work.

We can then define this inside the script tag like so:

<script>
    Vue.component('seconds-remaining', {
        props: ['seconds'],
        template: `
            <p>Seconds remaining: {{ seconds }}</p>
        `
    });
    new Vue({

    . . .

You’ll notice the use of the back-tick (`); you need this if the template spans multiple lines (in our case, we could probably get away with a single line – if we had, it would look like this:

<script>
    Vue.component('seconds-remaining', {
        props: ['seconds'],
        template: '<p>Seconds remaining: {{ seconds }}</p>'        
    });
    new Vue({

    . . .

One other important thing to note here, you are not permitted to have uppercase characters in the component name. You won’t get an error as such, it just automatically lower cases all the text, meaning that it won’t find your component (and you won’t know why!)

Let’s move the player into a component, too:

<div id="app">
    <player
        v-bind:location="location">
    </player>
    <seconds-remaining 
        v-bind:seconds="secondsRemaining">
    </seconds-remaining>            
</div>

And the script:

<script>
    Vue.component('seconds-remaining', {
        props: ['seconds'],
        template: `
            <p>Seconds remaining: {{ seconds }}</p>
        `
    });
    Vue.component('player', {
        props: ['location'],
        template: `
            <div v-bind:style="location"></div>
        `
    });

    . . .

In the next post, we’ll move these components out into their own files, which will involve actually installing Vue, rather than just importing the library.

References

https://www.taniarascia.com/getting-started-with-vue/

Vue.js Tutorial From Scratch – e07 – NPM, Webpack & Single File Component