30. December 2018

How to write game with Vue.js – Sokoban – Part 1 – Display level as text

Computer games have been written in nearly every computer technology. In 90' C and C++ were the kings. As we moved to the era of internet the number of available technologies exploed. Clearly, HTML and Javascript opened new horizons thanks to new and far simpler distribution. You just type an URL into a browser instead manual copying of floppy disks.

Let's take a closer look at Vue.js and how it can be used to write computer games. In this series, we will focus on building a clone of a very old game from 80': Sokoban.

Levels in Sokoban are fairly simple. The level consists of walls, boxes, spots where boxes should be moved and one character who is moving the stuff in a warehouse. The character can push just one box and he can't pull anything.

The following text will reference 4th commit on branch article-01 from repository https://github.com/georgik/pf2019/
You can access the version by commands:

git clone git@github.com:georgik/pf2019.git
cd pf2019 
git checkout acce8e7da89

Let's define one level where w stands for wall, o and x stands for objects in the game:

"wwwww",
"w w w",
"w oxw",
"wwwww"

Let's prepare the basic skeleton of an application so that we can display the map on the screen.

First of all, we're going to define references to Vue.js and Vuex libraries in index.html.

<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vuex@3.0.1/dist/vuex.js"></script>

In the second step, we will define a template which will render our map into real HTML code.

<script type="text/x-template" id="playground-template">
    <div>
    <div v-for="(tileRow, rowIndex) in levelMap">
        <span v-for="(tileName, tileIndex) in tileRow">{{ tileName }}</span>
    </div>
    </div>
</script>

The template just iterates ower the levelMap. Vue.js has a construct for rendering lists v-for. The first attribute tileRow will contain one line of the array from levelMap. rowIndex will contain the index of the row which is being rendered. We do not need rowIndex right now, but it will be useful in the future for positioning of tiles.

The second nested v-for is iterating over characters in each array. In this implementation, we're going to display just the character. Later on, we will map it to graphics and that will require some CSS tricks.

Let's finish construction of index.html. We will need a tag where Vue.js will plug the application. It could be achieved by following code in body.

<div id="game">
    <playground></playground>
</div>

Div tag is clear. But playground is definitely not an HTML tag. Here will Vue.js plug the component that we prepare in Javascript.

Last, but not least is include of our js/game.js file where Javascript logic will be stored.

<script type="text/javascript" src="js/game.js"></script>

Now we will move to the second file js/games.js. First of all let's store our levelMap in Vuex.Store state. Just define it for now. We will explore Vuex later on.

const store = new Vuex.Store({
    state: {
        levelMap:  [
            "wwwww",
            "w w w",
            "w oxw",
            "wwwww"]
    }
});

Since we have a map we can define our component playground which we have seen in index.html.

Vue.component('playground', {
        template: '#playground-template',
        store,
        props: {},
        computed: {
            levelMap() {
                return this.$store.state.levelMap;
            }
        }
    });

Here you can see that the definition of playground component is binding together HTML template with id playground-template from index.html with playground HTML tag which will be supplied by attribute levelMap which will be read from Vuex store.

Seems little bit mindbending, take your time to understand the code.

The last missing piece to make this whole thing work is the definition of Vue application itself.

var game = new Vue({
  el: '#game',
  data: {}
});

The result should look like this:

The source code of this article is stored at Github.

In the next article, we will explain how to replace characters from a level map by tiles using CSS.

You can find more HTML5 games at https://georgik.rocks/tag/games

Back to tutorial Sokoban in Vue.js

22. June 2018

How to display build log in Xcode

Xcode has a very minimalistic design when working with build errors. Sometimes it’s necessary to get more information about a failed build and it might not be obvious how to do it.

The answer is simple and it’s one click away.

Click on the last icon (text bubble) in the top left panel.

Now select the build and you’ll see all build information.

13. June 2018

Android Studio NDK could not start mips64el-linux-android-strip

If you’re using Android Studio to build C++ application with NDK you might encounter following error during build:

org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:transformNativeLibsWithStripDebugSymbolForDebug'.
...
Caused by: java.io.IOException: Cannot run program ".../Android/Sdk/ndk-bundle/toolchains/mips64el-linux-android-4.9/prebuilt/linux-x86_64/bin/mips64el-linux-android-strip": 
error=2, No such file or directory

The problem is caused by the upgrade of NDK in Android Studio to NDK v17. This version has a different structure of tools. It’s not compatible with Android Experimental Plugin v0.11.

The directory which should contain binary of tools contains just file NOTICE-MIPS64:

This mips64el-linux-android-4.9 directory exists to make the NDK compatible with the Android
SDK's Gradle plugin, version 3.0.1 and earlier, which expects the NDK
to have a MIPS64 toolchain directory.

The solution is to download NDK v16 from NDK older releases. Extract it and replace former ndk-bundle directory.

Commands for macOS or Linux users:

cd ~/Android/Sdk
unzip ~/Downloads/android-ndk-r16b-linux-x86_64.zip
mv ndk-bundle ndk-bundle-v17
mv android-ndk-r16b ndk-bundle

If you’re Windows user the location of NDK is typically in your profile AppData\Local\Android. Do not forget to unblock the ZIP after downloading (right click, Properties, Unblock, Ok)

Commands for Windows users:

cd ~\AppData\Local\Android\Sdk
unzip ~\Downloads\android-ndk-r16b-windows-x86_64.zip
mv ndk-bundle ndk-bundle-v17
mv android-ndk-r16b ndk-bundle

Start Android Studio. It should prompt you to update NDK. Do not confirm this request, it will replace NDK with v17. You should see the following screen in SDK Manager:

You can find related sample source code at GitHub in sdl2-android-example repository. Further articles about SDL2 and Android are available under the tag SDL2.

10. May 2018

SDL2_gfx for Android – Graphic primitives

In previous article, we were talking about drawing pictures in JPEG format. Let’s look how to draw some graphic primitives like a line. SDL2_gfx is small library which has support for graphic primitives and some surface functions.

The initial steps to add SDL2_gfx to Android project is the same like in case of SDL2_jpeg.

Register library in settings.gradle:

include ':SDL2_gfx'

The library should be stored in SDL2_gfx directory with build.gradle.

Now update our C application.

Here is simple example which draws a line:

thickLineColor(renderer, 0, 300, 300, 300, 20, 0xFF00FFFF);

You can find the source code at GitHub in sdl2-android-example repository. Further articles about SDL2 and android are available under the tag SDL2.

Special thanks for this extension of SDL2 Android example goes to jojomickymack who suggested how to add support for SDL2_gfx to Android project. Thank you.

22. October 2017

SDL2_image for iOS with JPEG image format

Adding SDL2_image with JPEG support for iOS is a little bit different than for Android. In case of Android, it was necessary to add JPEG library in C and build it. iOS has JPEG dependency hidden in another library which is already compiled in frameworks.

If you just add SDL2_image to your project for iOS, you will very likely end up with following linker error:

"_kUTTypeJPEG", referenced from ...
Linker command failed with exit code 1

To resolve this issue, it is sufficient to add two dependencies into your project.

Go to Project and select Build Phases.

In the section Linking add library: ImageIO.framework

Then add the second dependency: MobileCoreServices.framework

Then Clean and Build the project.

These steps should resolve the linker issue, and JPEG should work.