Monthly Archives: November 2019

Jetboard Joust DevLog #106 – Full Steam Ahead

Yes, Jetboard Joust can now be wishlisted on Steam here. Your support is much appreciated, even if you don’t end up buying it each wishlist helps!

I’m getting rather behind on this devlog again and wanted to write something about the process of getting the Steam page up. Even if it’s not strictly ‘development’ per se, it’s an important part of the process and took me some time.

I started off by reading this excellent Reddit post on how to create a kick-ass Steam page. Lots of useful info there and I kept referring back to this throughout the process. I also spent quite some time looking at the pages of other games, especially those that are also in the same general genre (fast-paced pixelart SHMUP) such as Nuclear Throne and Enter The Gungeon.

The bulk of the work, of course, is creating image assets. I decided to do this using the in-game art rather than trying to illustrate the game in some other fashion. This was a decision largely borne out of necessity (it would have taken me ages to produce quality vector illustrations), but I also felt a pixel art approach would more accurately convey the spirit of the game. If I couldn’t get it to work with pixel art I’d try another method, maybe even commission someone else.

I started off working on rough layouts using art cut-and-pasted from the trailer just to see if what I wanted to do was going to be achievable. I knew I’d need to use at least one of the boss sprites as they were the only ones likely to have the necessary impact without being blown up a ridiculous amount. I settled on the ‘stinger’ boss as it seemed to work well within the proportions of the various steam ‘capsules’, the other bosses actually proved to be too large and complex.

When I had a layout I was happy with I built a much cleaner final version using art taken from the original sprite sheets.

A huge part of the game’s personality though is the particle and shader effects and without these my capsule images were looking rather static and boring. As these are all semi-transparent in-game and overlap other elements it was impossible to cut-and-paste them from gameplay footage and would have been extremely laborious to recreate them ‘manually’ in Photoshop. Consequently I was a bit stuck as to how to convey these in a static context.

After much head-scratching I came up with the idea of doing a pure black-and white palette for the game. I could then make only the particle and shader fx visible, capture these as gameplay footage, import them in to Photoshop as an alpha channel, position where I saw fit and apply colors and blending. This method, with a bit of post-editing, worked really well and, I think, enabled me to communicate the feel of the game pretty well in a static context without a lot of laborious Photoshop work. It was also extremely useful when it came to mocking up / embellishing screenshots. For the screenshots I also used a ‘green-screening’ technique whereby everything but key sprites are rendered in green making cut-and-paste from gameplay footage extremely easy.

Annoyingly the ‘angled’ logo I use in-game just didn’t work within the proportions of the Steam Capsule images, particularly the smaller ones, and its proportions meant it was either too big or too small when blown up in the exact multiples necessary to maintain the pixel integrity. Consequently I had to recreate a purely horizontal version of the logo which I did in illustrator and pasted into Photoshop as vectors. I think a ‘pure’ pixelart version would possibly have looked better but I’m not sure it would have justified the amount of time needed to do it, particularly given the differing size requirements.

Then there was also the text to write, a myriad of forms to fill in, emails to write to try and generate some publicity, tags to add and a press page to create. I was pretty much losing the will to live by the end of it (not the first time I’ve said that on this project) but it’s done now. Check out the final result here.

Dev Time: 6 days (including other marketing)
Total Dev Time: approx 306 days

previous | next

mockup_3x
Steam Main Capsule Image (click to enlarge)

mockup_3x
Steam Library Capsule Image (click to enlarge)


Blacked Out Gameplay Footage For Photoshop Alpha Channels

‘Green-Screening’ Makes Composing Screenshots Easier

Lerp Camera Motion Smoothing Tutorial and Example Code

Recently I’ve been revisiting at the way the camera works in Jetboard Joust (wishlist on Steam here!) something that has been a continual thorn in my side throughout the project.

When researching how to make the camera movement better I came across many references to Lerp smoothing but I found few, if any, detailed explanations as to how this works in practice and (particularly) ways to get around its significant limitations. Cue this post, by the end of which we’ll have a class that’ll move an object smoothly towards a target point and ‘brake’ so it reaches it exactly no matter how often and by how much the target is changed.

I’m just concentrating on one axis of movement here for simplicity but this approach can easily be applied to 2D or 3D vectors. For those of you with short attention spans you can just download the final class here.

So… Lerp is a quasi-acronym for ‘linear interpolation’ and used to create smooth movement between two points. It’s often used to smooth out camera movement but can equally be applied to sprites or anything else in 2D or 3D space. The basic equation for Lerp is very simple, it takes a position and target, works out the difference between them and then returns a value a specified amount along that path. Only values >0 and <1 are generally meaningful.

public static float Lerp(float position, float target, float amount)
{
     float d = (value2 - value1) * amount;
     return value1 + d;
}

If you are using this equation to move an object and each frame call it with the object’s current position (keeping the other values the same) the object will move a smaller distance each frame which results in a ‘slowing down’ effect as the objects reaches its target. Here’s an example of this type of motion applied to a sprite. In this case the sprite is moving approx 480 pixels at a frame rate of 60fps with a Lerp value of 0.025.


Basic Lerp Smoothing

Now this looks pretty good already but, as you’ve probably figured out, there are issues. The first one is that using this approach the object will never actually reach its destination – this can result in a slightly jerky looking motion as it reaches the end of its trajectory as well as presenting potential issues if you want to do something when the destination is reached.

One way of resolving this is to implement a minimum amount of movement per frame. This can be anything you want but for many applications it makes sense for this to be one pixel.

Here’s a simple ‘Lerper’ class that implements this – each frame the amount of movement (LerpVelocity) is calculated and, if the absolute value of this is less the minimum velocity we clamp it at the minimum velocity. Of course this means that the object might now be in danger of moving beyond its target point so we check for this at well and make sure it doesn’t.

public static float Lerp(float position, float target, float amount)
public class Lerper
{
    public Lerper()
    {
        Amount = 0.025f;
    }

    // Returns the amount of movement at this stage of the lerp
    private float LerpVelocity(float position, float target)
    {
        return (target - position) * Amount;
    }

    public float Lerp(float position, float target)
    {
        float v = LerpVelocity(position, target);

	// If this is less than the minimum velocity then
        // clamp at minimum velocity
        if ( Math.Abs(v) 0) ? MinVelocity : 0 - MinVelocity;

	position += v;
	// Now account for potential overshoot and clamp to target if necessary
        if ( (v= target))
        {
            position = target;
        }
        return position;
    }

    public float Amount
    {
        get;
        set;
    }

    public float MinVelocity
    {
	get;
	set;
    }
}

Here’s an example of this in action. As you can see it looks much better…


Lerp With Minimum Velocity Applied

Still we have limitations though if we’re looking for really smooth movement. The next glaringly obvious one is that Lerp is ‘ease out’ only, the object will be moving fastest at the start of the sequence which makes it look like it’s being fired from a slingshot rather than smoothly accelerating from rest.

To resolve this I’m going to apply an ‘Acceleration’ property to my Lerper class. This ensures that, if the object is increasing in speed, the increase doesn’t exceed a specified amount. This requires a variable to store the amount of movement each frame.

public class Lerper
{
    private float previous_velocity;

    public Lerper()
    {
        Amount = 0.025f;
        Acceleration = float.MaxValue;
    }

    // Returns the amount of movement at this staget of the lerp
    private float LerpVelocity(float position, float target)
    {
        return (target - position) * Amount;
    }

    // Returns the next position with lerp smoothing
    public float Lerp(float position, float target)
    {
        // get the amount to move
        float v = LerpVelocity(position, target);
        // don't allow increases in velocity beyond the specifed acceleration
        if ( v>0 && previous_velocity>=0 && v-previous_velocity>Acceleration )
        {
            v = previous_velocity + Acceleration;
        }
        else if (v < 0 && previous_velocity  Acceleration)
        {
            v = previous_velocity - Acceleration;
        }
        // If this is less than the minimum velocity then
        // clamp at minimum velocity
        if ( Math.Abs(v) 0) ? MinVelocity : 0 - MinVelocity;
        }
        // Remember the previous velocity
        previous_velocity = v;

        // Adjust the position based on the new velocity
        position += v;
        // Now account for potential overshoot
        if ( (v= target))
        {
            position = target;
        }
        return position;
    }

    public float Amount
    {
        get;
        set;
    }

    public float MinVelocity
    {
        get;
        set;
    }

    public float Acceleration
    {
        get;
        set;
    }
}

Here’s an example of this in action – now we have a nice ‘ease in’ to our Lerp motion. Here I’m using an acceleration value of 0.25f.


Lerp With Maximum Acceleration ‘Ease In’ Applied

There’s one other problem I’m going to address though. This ‘ease in’ effect works nicely if the object is initially at rest or moving in the same direction but if the object had previously been moving in the opposite direction we’re still going to get a nasty jolt. Here’s an example where I’m changing the destination to the opposite side before the previous Lerp has reached the end of its trajectory.


Sudden Changes In Direction Result in A Nasty Jolt

So we’re going to check for this in the code and again apply a maximum amount by which the velocity can change each frame. Remember that because we’re changing direction the absolute value of the current velocity at the point of change is the sum of the absolute value of both the current and previous velocities, ie a change in direction from 10 to -10 would result in a new velocity of -20.

A side-effect of this is that the object will probably end up moving away from the target until it’s gathered enough momentum to change direction. As the code that clamps to the target position assumes we are moving towards the target we have to max out the target value if this happens.

We also have a special case check for our minimum velocity here as we need to make sure that if the minimum velocity is applied its applied in the direction that moves towards the target (otherwise the object could get stuck moving in the wrong direction).

public class Lerper
{
    private float previous_velocity;

    public Lerper()
    {
        Amount = 0.025f;
        Acceleration = float.MaxValue;
        MinVelocity = 0;
    }

    // Returns the amount of movement at this staget of the lerp
    private float LerpVelocity(float position, float target)
    {
        return (target - position) * Amount;
    }

    // Returns the next position with lerp smoothing
    public float Lerp(float position, float target)
    {
        // get the amount to move
        float v = LerpVelocity(position, target);
        // don't allow increases in velocity beyond the specifed acceleration (ease in)
        if ( v>0 && previous_velocity>=0 && v-previous_velocity>Acceleration )
        {
            v = previous_velocity + Acceleration;
        }
        else if  (v  Acceleration )
        {
            v = previous_velocity - Acceleration;
            // we might actually end up moving away from the target
            // here in which case we adjust the target so we don't get
            // clamped to it later
            if (v  0 && previous_velocity  Acceleration )
        {
            v = previous_velocity + Acceleration;
            // we might actually end up moving away from the target
            // here in which case we adjust the target so we don't get
            // clamped to it later
            if (v > 0-MinVelocity)
                v = MinVelocity;
            else
                target = float.MinValue;
        }

        // If this is less than the minimum velocity then
        // clamp at minimum velocity
        if ( Math.Abs(v) 0) ? MinVelocity : 0 - MinVelocity;
        }
        // Remember the previous velocity
        previous_velocity = v;

        // Adjust the position based on the new velocity
        position += v;
        // Now account for potential overshoot and clamp to target if necessary
        if ( (v= target))
        {
            position = target;
        }
        return position;
    }

    public virtual void OnTarget(){}

    public float Amount
    {
        get;
        set;
    }

    public float MinVelocity
    {
        get;
        set;
    }

    public float Acceleration
    {
        get;
        set;
    }
}

Here’s what happens when you suddenly change the Lerp target with this code applied – as you can see we now have a nice smooth movement no matter how often we change the target value.


Lerp With Maximum Acceleration ‘Ease In’ Applied

And that’s pretty much it. You can download the final class file here – in the final version I’ve also added a MaxVelocity property, a delegate to be called when the object reaches its destination, and tidied up the code so its not quite so verbose.

If you are in the process of coding a camera for a 2D game I highly recommend you check out this excellent article.

If you are looking for something to move smoothly between two points over a specified number of frames then you’re probably better off using some kind of tweening rather than Lerp. Check out Robert Penner’s excellent tweening/easing functions or the ‘smoothstep’ algorithm approaches described here.


These articles take a lot of time and effort to put together. If you found this useful and would like to help me create more content like this like you can support me below – I really appreciate it!

Buy Me a Coffee at ko-fi.com

Granny Bait – The Making Of “Skateboard Joust”

Granny Bait: A term used back in the day to describe a game that had virtually no redeeming features but, because it had something ostensibly ‘youth’ in the title (and was cheap), would be bought in droves by clueless older folk as gifts for their disappointed grandchildren.

A while ago I wrote a post about ‘Subterranean Nightmare‘, my first commercial release for the ZX Spectrum. Whereas ‘Subterranean Nightmare‘ was something of a labour of love and represented a genuine attempt to create a decent game, my next title (I am somewhat ashamed to admit) was executed in a rather more mercenary manner. I can’t remember exactly what age I was when I started work on ‘Skateboard Joust’ but I was heading into my late teens. I was losing interest in videogames and starting to become far more interested in guitars, girls and beer. Guitars, girls and beer cost money though – and the best way I knew of to make a quick buck was to churn out another budget Spectrum title.

I never had the slightest interest in skateboarding but tying the game in with something that was relatively fashionable seemed like a good idea. I’d also never played ‘Joust‘, but I’d seen screenshots and knew it was made by the some people that made ‘Defender‘ (which I still rate as one of the finest videogames of all time) so it was bound to be pretty cool.

The central mechanic of the game involves destroying enemies with your skateboard which you can only do if you are mid-jump (not actually riding the board) and I still think this is a pretty sound gameplay concept. It’s not executed very well however and is extremely difficult to get the hang of (‘totally unplayable’ might be a better description). Then there’s the fact that, aside from a few pretty unimaginative powerups, this central mechanic is pretty much all there is to the game making it a fairly tedious experience.

The worst thing about the game though is that what appear to be the level backgrounds are actually in the foreground and serve no purpose other than to obstruct your view of a game that’s hard enough to play as it is. Making gameplay harder by simply obscuring what’s going on must surely be one of the most laughably bad game design ideas ever!

I remember borrowing chunks of code from my brother Tim (of I-Ball fame) who was always a much better coder than me, and recycling some of the graphics from ‘Subterranean Nightmare‘. I also added some of the most embarrassingly ‘wrong’ skate slang between the levels. Not my finest hour but I was paid a £2.5k advance by Silverbird which paid for a lot of beer.

The game was justifiably slated by Crash Magazine at the time, though in recent years some people have been rather kinder to it, notably the vg-junk blog. There’s also some drunk guy on YouTube who plays the game for around five minutes without realising that you can jump off your skateboard!

Bizarrely though the game had some devoted fans despite its awfulness – in the comments for this video there’s someone who seems to take great offence when people suggest that it might be a tad shit! I also ‘met’ the person who did the C64 version in this thread, turns out they got paid considerably more than I did for writing the original!

And no, I have no idea what I was thinking of when I designed those ‘extra’ life icons! They do look like some kind of demented frog!

World Of Spectrum entry here.

30 years later I’m now working on a sequel, ‘Jetboard Joust’, in order to balance out my karma for forcing such a terrible game onto the unsuspecting public. ‘Jetboard Joust’ builds on the central ‘Jetboard of Death’ mechanic and adds a whole lot more besides – you can wishlist it on Steam here and read about the development here.

30 years Later – The Sequel…
Read the instructions you fool!


The C64 Version (With At Least One Devoted Fan)!

cornflower
Recycled Graphics on Skateboards

cornflower
Yes, All That Shit Just Gets In The Way!

cornflower
Attack of The Roast Chickens