Saturday, 23 December 2017

Jetman

The Idea

The source of my inspiration for this project was a reddit post on /r/gamedev:

Is it a bad idea to just remake an existing game in order to develop Programming and Gamedev skills?

I liked this idea and the first game that came to mind was Jetpac on the ZX Spectrum which I played a lot when I was a kid. I wasn't looking for the complete retro look and feel, just a similar game mechanic, removing the main obstacle from writing a game, Getting Started.

  

TL;DR

Here is the playable result on itch.io. Let me know what you think:


The Scope

I'm normally not available to participate in game jams but I set myself the same criteria of getting a project done in 48 hours. This is a great way to focus you on what is and isn't important. It also means there is an end to the project, when the time is up.

Again, I chose Unity as my game engine of choice. C# is actually my day job and I love it so that takes the learning out of the language out of the equation and I can focus on stuff I want to learn, which is writing games.

I also wanted this to be completely open source (MIT) so I had to chose assets that fit with this license, i.e. no commercial assets. The full source code is available on GitHub.

The Graphics

I didn't want to spend my time creating artwork so I went to my go-to site kenney.nl and found his Space Shooter Extension asset pack which had pretty much everything I needed:


The original ZX Spectrum game started out by assembling parts of your rocket. This asset pack had rocket parts, perfect:
     
It also had an alien that had a couple of frames for walk and fly. Not a Jetman but it was in the spirit of what I was trying to do and I liked the idea of using a single asset pack so I went with it:
  
Finally, I needed the ground and platforms, a meteor, an explosion effect and a fuel pickup. Kenney, as usual, did not disappoint:
  

Tilemaps

A new feature was added to Unity 2017.2, Tilemaps. I knew it was overkill for what I needed to do but as this was a learning exercise I thought I'd dive in and create the level as a tilemap.


It's a pretty nice workflow and I was able to setup the familiar 3 staggered platforms, the ground and all collisions in a matter of minutes, after watching this tutorial:


Physics2D Colliders

To get the player to land on the ground and the platforms and move smoothly I had to add colliders to the player graphic. I created a Capsule2D collider that has a rounded top and bottom, which prevents snagging on corners according to the Unity forums.


The same collider is used to determine if a rocket part or fuel is bring picked up, or if a the player hits a meteor. The meteor was originally a Circle2D but I changed it to a Polygon2D collider to make the collisions more accurate:


Physics2D Layers

As well as specifying the physics shapes that should register collisions it was important to identify which objects could collide against which other objects. For this the you go to Edit->Project Settings->Physics2D and check the boxes in the Layer Collision Matrix that are needed:


I split my layers into Player, Enemy, Rocket, Ground and Collectable and set the checkboxes accordingly. For example, this allows the player to collide with collectables (fuel, rocket parts) but not the enemy.

Physics2D Forces

Adding a RigidBody2D component to the player allows for easy movement by calling AddForce. This Unity tutorial was very informative for getting the basic Jetman movement working.

using UnityEngine;
using System.Collections;

public class CompletePlayerController : MonoBehaviour {

    public float speed;             //Floating point variable to store the player's movement speed.

    private Rigidbody2D rb2d;       //Store a reference to the Rigidbody2D component required to use 2D Physics.

    // Use this for initialization
    void Start() {
        //Get and store a reference to the Rigidbody2D component so that we can access it.
        rb2d = GetComponent<Rigidbody2D>();
    }

    //FixedUpdate is called at a fixed interval and is independent of frame rate. Put physics code here.
    void FixedUpdate() {
        //Store the current horizontal input in the float moveHorizontal.
        float moveHorizontal = Input.GetAxis("Horizontal");

        //Store the current vertical input in the float moveVertical.
        float moveVertical = Input.GetAxis("Vertical");

        //Use the two store floats to create a new Vector2 variable movement.
        Vector2 movement = new Vector2(moveHorizontal, moveVertical);

        //Call the AddForce function of our Rigidbody2D rb2d supplying movement multiplied by speed to move our player.
        rb2d.AddForce(movement * speed);
    }
}

The final code was slightly different but that's because I wanted walking to be slower than flying so I needed to slow the movement down when walking on the ground or a platform.

Particle Systems

When the rocket takes off and the player's jetpac fires I wanted an effect that was more like rocket plumes than just simple sprites being enabled and disabled. Unity's particle system is fully featured and is capable of doing everything I was looking for, and more.


The key parts that I used were the Color over Time and Size over Time features of the particle system. Also the particle itself is the explosion effect png from Kenney's assets. The color over time comes from a gradient which blends from white to red to yellow and finally a grey smoke:


For size over time I just reduce the sprite size using the following curve:


Finally I enable collisions with the ground using a GroundPlane visual which just allow the rocket jet particles to bounce off the ground when taking off or landing.

Once I had this worked out for the rocket I copied the particle system to the player's jetpac and also to leave an icy trail behind the meteors (see the blue to black gradient at the foot of the Gradient Editor Window above).

The last touch was to add a burst particle effect when the player first starts their jetpac that creates 30 particles at time 0 and no more over time. The effect also doesn't loop:

Wrap Around Edges

The original game allowed the player to move off the sides of the screen and appear on the other side of the screen. The same thing also happened for enemies (in this case meteors). After doing a series of calculations on a FixedUpdate() to determine whether the sprite was off the screen to the left or the right I realized there was a much simpler way. I could just place two BoxCollider2D objects just off screen to the sides and then in the OnTriggerEnter2D():


Here is the complete code for handling the wrap around for the player and meteors. The screen is 45 units wide which is where the 45 comes from:

void OnTriggerEnter2D(Collider2D collider) {
    var xd = transform.position.< 0 ? 45 : -45;
    collider.transform.position += new Vector3(xd, 00);
}

Drop Zone

The original game automatically dropped the rocket parts and the fuel when the player is over the rocket base. To implement this I created another BoxCollider2D which covered the screen area above the rocket base as shown here:


When the player enters the zone the OnTriggerEnter2D callback is called and we check whether it's the DropZone and then if were carrying anything we drop it at that point. We also add 100 points to our score which is maintained by a central GameController object. Here is the code:

private void OnTriggerEnter2D(Collider2D collider) {
    if (collider.tag == "DropZone" && carrying != null) {
        gameController.Score(100);
        Dropoff(collider);
    }
}

User Interface

All I really needed was a Start Game button so I didn't create anything else. For the graphic I used another Kenney Asset, the UI Pack, specifically the Adventure pack:


I also needed to show the current score, the high score and the number of lives left. Kenney provided an excellent Space Font asset which does the job perfectly:

DOTween

In a previous project I used LeanTween and so this time I thought I'd try a different tweening package called DOTween. DOTween's unique selling point is that it is fast and doesn't create garbage for the garbage collector unnecessarily.

It uses a fluent style syntax which allows for composition of animations with properties in a readable way:

sprite.DOFade(00.3f)
    .OnComplete(() => GameObject.Destroy(enemy));

At this point I'm undecided about which I prefer. The LeanTween syntax seems more consistent but DOTween seems to have more functionality overall.

Sound Effects

I had determined a shortlist of sound effects on my Trello board for this project:


The Pickup, Dropoff, Player Die and End Game sounds came from the Kenney's audio packs.

The Jetpac sound was a bit more tricky since I wanted it to loop as the player holds down the thrust jetpac key. Creating a looping sounds was harder than I thought. No matter how I trimmed the sounds I could find in  Kenney's audio files I could never get it to sound like one continuous loop. I had to go to freesound.org and found the perfect loop there instead by a creator called qubodup:



For the rocket launch itself I found that NASA has put many of its audio and visual resources into the public domain with a non-commercial license. What better than the sound of a real rocket launching:


Background Image

A black background was a bit boring so given the recent experience I had with NASA sounds I thought I'd delve into their image archive too. Again, I was not disappointed:

This image covers a portion of a large galaxy census called the Great Observatories Origins Deep Survey (GOODS).
Credits: NASA, ESA, the GOODS Team, and M. Giavalisco (University of Massachusetts, Amherst)

WebGL Template

I had a small amount of time left on the last day and I wanted this game to be uploaded to itch.io with a slightly different look to before, including an Arlorean logo and image that I'd designed in MagicaVoxel:

Source Code

From the outset I wanted to publish the source code for this project, partly so I could find it again at a later date and party so I could provide it as an example for anyone else who was interested.

Final Thoughts

Recreating a game already written has a lot of advantages. The design paralysis that I normally get when starting a new project was almost non-existent. I already had the finished game that I could play to see how the mechanics worked. I didn't have time to implement all the features of the original but I managed to do enough to give a flavor of the game and one play tester said "It's Jetpac" before I told him how to play.

Wednesday, 9 August 2017

MagicaVoxel Thumbnails

MagicaVoxel is a fun editor to use for creating voxel based art. I wanted to do a game based on voxel artwork but first I thought I'd try to develop a library that could read (maybe write) the .vox file format that MagicaVoxel produces, and render thumbnails for them in Windows Explorer.

TL;DR


Here is a screenshot of the thumbnails being shown in Windows Explorer for the mmmm set of voxel artwork on github:

The whole project is open source (MIT license) and available at github.com/Arlorean/Voxels.

Unity

Ultimately I want to use the library in Unity at run-time so it needed to be C#, but not too new even though Unity 2017 is now out and kind of has support for C# 6.0.

SkiaSharp

To test that I could read the files in correctly I thought it would be useful to render them to PNGs and also SVGs. That's where Xamarin's SkiaSharp wrapper for Google's Skia cross platform 2D rendering engine would come in handy. It's like Windows GDI done right and also has a backend for rendering directly to SVG files using the same draw commands. Perfect.

SharpShell

I realized that if I could render a PNG file I could also render a thumbnail easily and I knew of the SharpShell open source project that enables Windows Explorer Shell Extensions to be written in C#.

This seemed to be a perfect weekend sized project that would give me a milestone to hit before moving on to the end game of making something voxel based in Unity.

Rendering Quads

The thumbnails style I wanted was Isometric projection. This also makes the math easier, although not by much. SkiaSharp has an SKMatrix44 class for performing transformations of 3D coordinates but the SKCanvas interface for drawing only expects 2D points so translations all have to be done outside of the actual rendering code.

There is no z-buffer when rendering in 2D using as there is in 3D so we have to render the quads in the correct order, back to front, bottom to top.


The three quads for each voxel need to have their color adjusted slightly to give the impression of light coming from a particular direction. I just multiplied the face color by 1.0, 0.9 and 0.8 to get the look I was after. Notice that the quads have a line around the edge. This is due to antialiasing in SkiaSharp rendering. The same problem happens for SVG:
Antialiasing can be disabled for bitmaps/PNG output but not for SVGs currently. Here is the simple lighting with no antialiasing issues:


With the addition of a transparent background the initial rendering was done.

Ambient Occlusion

Although the lighting gives some impression of depth it can be made more realistic with some simple vertex coloring, as is done in games like Minecraft. I found this excellent algorithm on how do this. Here is the graphic that explains the 4 cases of local occlusion that need to be handled:

Adding this to the image gives a much better impression of depth to the images:

To get this we have switch from Quads to Triangles so we can interpolate the color values between all three points in each triangle. Thankfully SKCanvas has a DrawVertices method that does exactly this. However this isn't implemented for SVG so this is the point where the implementations diverge slightly and it also meant I couldn't get ambient occlusion working in SVG for now. Here was the error I got:

skcanvas DrawVertices unsupported operation: drawVertices()

Windows Installer (WiX)

I wanted the project to be as open source as possible but I also wanted users to be able to easily download an installer and it just work. Windows installers are a black art but there is one solution WiX which promises to make this easy and open.

I found it to be very open but definitely not easy. The rendering to PNG and SVG took roughly 2 days on and off but the installer took another 3 days of frustrating fails before the final success.

Creating an MSI was relatively painless and I was able to release v1.0.0.2 (don't ask) which worked on two machines I tested it on so I thought I was done.

Then I tested on a third machine a couple of days later and found it didn't work, as in I didn't see any thumbnails. Debugging shell extensions is notoriously difficult, compounded by the fact that the machine I was deploying to didn't have Visual Studio on it so was building on one machine and transferring the installer to the other with more and more diagnostics. This was very painful and I explored lots of potential problems that were red herrings.

RTFM

I nearly gave up but then I went back to basics and Read The "Friendly" Manual for SkiaSharp and there it was on the front page, in italics:



Developers' machines will almost always have this installed already which is why testing should be always be done on non-dev machines (ideally completely fresh), especially installers.

Windows Installer Bootstrapper (WiX)

How hard can this be. It must have been done 1000 times and almost be a built in feature of WiX. How wrong could I be. It used to be easy when it was all about merge modules but Microsoft changed the way the Visual C++ libraries should be redistributed. Where would we be without StackOverflow?

A kind internet citizen put up a gist on github that handled all of the downloading from the internet and installing the vcredist files in x86 and x64 flavors. I humbly copied the arcane mantra into a new WiX Bundle project and with a bit of tweaking, and some option paralysis over which icon to use for the installer, I had a working Voxels.setup.exe (v1.1) file that installed the correct dependencies on my non-dev test machine:


Conclusion

I had fun putting this together and I hope others find it useful when finding their own .vox files on their machine.



Tuesday, 11 April 2017

Sum Fun - Day 2

Day 2

Having a working game on day 1, I thought I'd do a bit more than add sound on day 2. I was confident I'd have time to fit more in.

Adding Juice

Kenney.nl has an system website pixeland.io which has a great list of videos for budding indie game developers to consume to help improve their games. This video is just a must see and is all about Tweening:


This lead me to a great free Unity3D asset for tweening called LeanTween. It sells itself as being the fastest tweening library but the real joy as a developer is the lightweight, fluent syntax:

LeanTween.moveX(go, 1f, 2f).setEase(LeanTweenType.easeInQuad).setDelay(1f).setOnComplete( someMethod );
Understanding all the tweening easing functions wasn't obvious until I stumbled across easings.net. It has interactive graphics for all the standard easing functions and they match up with the LeanTween ones pretty well:


I set about juicing up my graphics, adding small animations to the following:
  • Slide start menu off-screen (and back again at the end)
  • Scale in and out the score and timer when they change value
  • Bounce the tiles in the grid into place at the start
  • Elastic the selected tiles into the left and right tile slots of the sum
  • Shake the whole sum when you make an incorrect guess
  • Pop out the adjacent tiles for the second choice in the sum
These are small but simple changes that don't affect the game mechanic, or code flow, in any way at all, but the change to the feel of the game it just outstanding. I'm convinced it's as essential a step as the sound or the graphics themselves.

Sounds

I didn't venture beyond Kenney.nl for my sound assets and ended up using the female voice from the voice-over pack, one of the switch sounds from the ui-audio pack and the tone1 (pong) sound from the digital-audio pack.


For the music I went back to opengameart.org and found the ideal BossaNova tune. All my audio clips were now in place and wired up to the various states of the game. Easy-peasy.

Background and Splash Screen

My previous game had no splash screen and I felt that was missing when the app started, especially on a phone where the screen just went black for a few seconds. I headed to Google in search of free (to reuse) images and found freeimages.co.uk.


I wanted the background and splashscreen to look like a chalk board that had sums on them. I was not dissappointed. A bit of WordArt in Microsoft Word ,with Google's Oswald font which is included in TextMeshPro, and I had a splash screen:

Game Over

I wanted to add a small amount of persistence to this game to see how it works. The High Score was the obvious choice and it turns out it's really easy to do. Unity's PlayerPrefs class has it all and it's very simple and intuitive to use.

public class ExampleClass : MonoBehaviour {
    void Example() {
        PlayerPrefs.SetInt("High Score", 10);
    }
}
This allowed me to easily add in a sliding panel, with graphics from Kenney.nl, that shows the score and the high score. To top it off if the score was a new high score I bounced some text that says New High Score at the bottom of the pane. LeanTween'ing all the way. 


End of Day 2

This time there is no day 3. I got it all done in 2 days from conception to production. The end product feels a lot more polished as well and I can see how it could be enhanced to add extra tile types and different sum types (=, -, /, *, etc.). For now though I'm done...


Get it on Google Play


Sum Fun - Day 1

My first attempt to write a game nearly put me off but I decided to have another go. Again, giving myself just two days to write a game from scratch and publish it to the Google Play Store and Itch.io.

Again for the impatient, and a slight spolier, here is the finished game on both platforms:
Get it on Google Play

Day 1

Game Idea

Thinking of a game is easy, but pinning down the game mechanic that is going to work is not. I also knew I had to do something that I could get done in just two days so I went with a block style puzzle. I was inspired by games like Bejeweled and Words With Friends, both of which work well on a grid with tiles and are fun to play.

Graphics Assets

I set about finding some tile graphics that I could move around a board to make sequences and score points and I came across opengameart. Digging deeper I found a popular contributor kenney.nl who has many assets available for free, or you can pay for the assets if you want as well (which I will once this post is done).

Clearly the puzzle pack was first on my asset shopping list:


I dug out my go to Unity, asset SVG Importer, since Kenney includes all the svg vectors as well (what a star!), and I manually arranged a grid of squares to see what it would look like. I then stopped as I realized I hadn't thought out the game mechanic and I didn't know where to go next.

Game Mechanic

I started thinking about numbers instead of shapes, focusing on the Minimum Viable Product philosophy. Then I had it. A game with a grid of numbers where you have to click on adjacent numbers to solve a sum. I grabbed my graph pad and sketched this out:


I got to work creating grid and a start button based on my sketch with the ui-pack from Kenney, using the squares in the middle left of this image;


For the text I decided to use the new TextMeshPro asset which was recently acquired by Unity and made available for free. It uses Signed Distance Fields to allow fonts to be displayed nicely at any size with a vector look instead of a pixelated look. It also allows for extra effects like outlining:


End of Day 1

It didn't take long to get a working prototype with random number tiles and a random sum. I didn't have the score working yet and it looked basic but the game was working. One day is enough to get something working I'm finding. Unfortunately I didn't take a screenshot at the end of the day, so there's no tad-dah moment yet.