Honeycomb Engine: Dev Blog 4 ~ Plans for the Holidays

Term 1 is now over. While I still have some coursework due in at the start of next term, for the most part, I’m done with work. That means I’ll have tons of time free to get a good chunk of Honeycomb and Honeycode out of the way! I’ll just be outlining the most important plans in this post, so it’ll be a fairly short one; I wanted to get something out since I’ve been quiet for the past few weeks.

Honeycode

First off the bat is Honeycode, the scripting language that will accompany the engine. I’ve made a little progress with Honeycode, but perhaps not as much as I’d liked, so the first task for the holidays will be to finish a working version of Honeycode and its compiler. I think the fun part of creating the language will be testing it out to see what actually works or not – I have so many potential concepts I want to try out and I’m not sure where to even start. The core feature, as always, will be ease-of-use.

Saving and loading mechanisms

This bit might not be quite as interesting to most people, but a weird programmer type like me should find this fun – organising save data on disk. I’ll likely use JSON to save files, both in-game and in-editor. In tools like Unity, it’s often the case that the built-in saving mechanisms aren’t as robust as you’d like (for example, Unity PlayerPrefs aren’t designed for saving all game data, so you need to build a custom solution), so for Honeycomb I want to make sure a good saving system for game data ships with the engine. The in-editor saving system will only need to make sure that scene files and assets are saved properly, so I can use roughly the same sort of system for both use cases.

The Editor

This is the largest task left. The editor will be the main window in which users create games, so it’s arguably the most important remaining feature too. This task encompasses countless other small tasks, so it’s going to take a while. It’s the task I planned mostly for term 2, so any progress I make on it during the holidays is sort of a bonus; however, I think it will be crucial to get as far through the development of the editor as possible to give myself some slack during term 2 in case any major setback occurs. At the very least, I’d like to make the skeleton of the editor by the end of the holidays.

The renderer

While the renderer is somewhat functional, I want to improve it in a few ways. First of all, it can only render one object at a time currently; this is due to my relative inexperience with Vulkan, the graphics API I am using. When I figure out how to order my requests to the GPU properly, and hence get more than one model on screen, the next task is to work on the lighting engine since Honeycomb currently only supports a very broken diffuse lighting shader. The sooner I can work on fancy shaders, the better!

Honeycomb Engine: Dev Blog 2 ~ More Vulkan and Honeycode

Since last week, I had planned to shift my focus mainly onto Honeycode, but I’ve mostly been working on the renderer some more. Yesterday I did a bit of work on the Honeycode parser, but it’s nowhere near complete yet. However, I have thought a little more about how the language will work conceptually, such as the syntax it will use and the features it will support. The idea is to make a programming language for non-programmers or beginners to programming, so I want it to be super-intuitive. I’ll detail a few of my ideas below, although it’s currently just me throwing everything at the wall and seeing what sticks.

Vulkan

On the plus side, I’ve finished the set of Vulkan tutorials I was using now, resulting in a really cool rendering of a model of a chalet found on Sketchfab. Now that I have a better understanding of how Vulkan operates, the next step is to get multiple different models loaded. Once I achieve that, the next step is to think up a level data format that allows me to save and load level data from disk. And once I’ve done that, I’ll need to set up a proper component-based architecture for objects. By using the Component programming pattern, it’ll allow users of Honeycomb to write their own behaviour scripts and attach them freely to game objects while keeping those sets of behaviour nicely encapsulated and decoupled from each other.

vulkan_model

This hut is almost worth the couple of weeks spent trawling through tutorials.

I’ve been reading through Bob Nystrom’s brilliant book, Game Programming Patterns, which details many different ways of organising code for all sorts of situations; I’ll be using some of the patterns used in this book in spades. For example, I currently have an input class that’s using the Singleton pattern – you have a publicly accessible static member of a class – purely because it’s the quickest way of making something globally visible (well, that and making all of the member functions and variables of a class static). I wanted to quickly add functionality to rotate the model and move the viewport, so please don’t judge me.

As pretty much every source on programming patterns will tell you, Singleton is awful for almost every case, so I will replace the input system with one that uses the Command pattern, which replaces hard-coded function calls for a given input with a bunch of different encoded behaviours – called commands – assigned to variables for each input, which will be executed using some execute() function.

Honeycode

Since the idea behind Honeycode is to be beginner-friendly, I want to minimise the number of scary features in the language as possible. You know the sort of stuff I mean, like requiring the user to write a million lines of boilerplate code before anything actually happens. At the same time, I want it to be expressive and I need it to be easily translatable to equivalent C++ code so I can easily compile it into an executable together with the engine.

There are a few broad ideas I currently have – some may be useful, some may be scrapped later on:

  • When a user creates a new script, the code in that script is automatically inside a class that inherits Component (the base class for the Component programming pattern), but this information is hidden from the user. They just write functions and variables in the script and attach it to game objects in the editor and let the engine worry about types and stuff.
  • There are some event functions that automatically fire and are ignored by scripts that don’t bother to implement them. Those events include a start() function that gets called after everything gets set up, but it is the first user-created code that is called, an update() function called every frame, an exit() function called when the level switches and a quit() function called when the game is closed. All the user needs to know is that they exist and roughly when they are called.
  • There should be simple one-function APIs for doing simple tasks and there should be minimal #includes or imports (or, get rid of them entirely and do it behind the scenes), then those simple functions will get translated to the appropriate C++ code during compilation. For example, if a user wants to save data (as a string) to a file, they should be able to write something like:
write(myString, myFileName.dat);
  • I might only have one floating point data type and one integer data type. For new users, I think it might be too confusing to immediately have to distinguish between all sorts of number types, like float, int, long, signed int, unsigned short int, char, wchar_t and who the hell knows what else is lurking in C++. At that rate, I’m surprised they didn’t throw in short long int to make everyone blink twice. I think including only float and int should suffice. In some instances during compilation, I can replace a type with a more sensible one anyway – array indexing and iteration would always use unsigned integers, for example. I’ll also keep char hanging around, because at least it’s clear what char is doing to a new programmer.
  • Memory management should be as simple and automatic as possible because C++ is confusing enough as it is without having to worry about destructors and all that jazz. I should be able to do all that behind the scenes.

To make things clear, my language doesn’t exist to radically change the syntax of C++, nor is it intending to provide any fancy optimisations. It’s essentially just a metric ton of syntactic sugar to make C++ more palatable to newbies. Since I’m not aiming to squeeze the absolute most out of the hardware, I can be a bit more lax on the performance side of things as long as games are efficient enough. I have a few more ideas, but most of them are just things I’d remove from C++ rather than add.

As for the progress I’ve made regarding the lexer/parser, I’m currently at the stage where I can recognise some keywords from an input file and convert them into tokens, although it needs a lot more work before it’s finished. The next step after that is to add all those tokens into a parse tree, then I’ll need to look through that tree to make sure the syntax of the input file is valid. I’ve also settled on the file extension .hny for Honeycode files (I’ve clearly got my priorities straight when it comes to fulfilling features).

So far on my schedule, I’m supposed to have written my specification (which is complete), learned the tools I’m using (including Vulkan, although I’ve left myself an additional week for that) and started working on Honeycode (which is why I’ve been brainstorming ideas). This week, I’m supposed to have learned all the Vulkan I need to know and started on the end-of-term progress report; as I’ve finished the Vulkan tutorial ahead of time, I will wait until early December when my copy of the Vulkan Programming Guide is scheduled to get to me before I do much more Vulkan and probably work mainly on Honeycode instead.

I’m Making a Game Engine

It’s sure been a while since I last posted, well, anything. Part of that was me getting reacquainted with uni life, part of it was me adjusting to a real-person sleep cycle and part of it was me thinking about the game engine this post will be about. But most of it was just me being lazy because my last post was in early July, about three months ago. That’s my longest disappearance yet. Oops.

However, since I was last here, a lot has happened! As part of my third year at uni (I’m already halfway through, where does the time go?!), I have to do a big project about something to do with computer science; I’ve decided to make a game engine, which has resulted in some people thinking I’m a tad insane. I’m inclined to disagree – doing it will make me insane. Without further ado, introducing my concept: the Honeycomb Game Engine!

honeycomb_logo

At some point I will vectorise this image.

The basic idea is that Honeycomb will be geared towards people who don’t have all that much experience in game design or programming (or both!). The way I will achieve that is by turning the idea of a game engine on its head. Some game engines try to give the developer tons of tools for any imaginable situation, but I think this is overwhelming for a new user – that’s how I felt way back when I started using Unity, anyway. Instead of following in those footsteps, I’m going to try and condense my game engine down to easy-to-use key features and avoid adding anything that’s unnecessary. Essentially it will lie somewhere between Unity and Game Maker.

In my opinion, a beginner-friendly game engine should have most of the following features:

  • A clean interface with easy-to-understand buttons and menus for common tasks;
  • A way to add behaviour to game objects that is intuitive and doesn’t require writing tons of boilerplate code (a simple scripting language, for example);
  • A room-building tool that lets you add game objects to a room and snap them to a grid easily;
  • Support for common 3D modelling packages, such as Blender or Maya. I think supporting .fbx files is sufficient for this;
  • A big, red button in the corner of the editor that donates an energy drink to an exhausted game engine developer somewhere in the world;
  • One-button exports to the platforms the engine supports. Users shouldn’t have to sift through mile-long lists of options for their exports;
  • A UI designer toolkit that lets users place buttons, text elements and sliders on a virtual ‘screen’ that then gets overlaid onto the running game;
  • A ‘play’ button that lets users run their game directly in the editor, or at least build the game quickly and provide debugging feedback to the user. This is one of the most difficult things I will try to implement (it’s a stretch goal);
  • A material editor that lets users plug in values and textures for various parameters. Then users can drag those materials onto models in their game;
  • An animation toolkit that lets users control how models are animated and how different animations work together;
  • Coroutines. Holy hell, they are so useful in Unity while writing behaviour.
  • Many many more things that I’ve inevitably missed out!

Some of these features obviously require more work than others. For example, I plan to create a scripting language (called Honeycode, because I’m an awful person) that will get compiled to C++. The advantage of creating my own scripting language is that I can abstract some of the less beginner-friendly features of C++ and ignore some less useful ones entirely, while making assumptions about what Honeycomb provides. This way, I can bake engine integration directly into the language, similar to how the Unity API augments C# to provide Unity’s features.

Essentially, my motivation for the engine is to create something that new users can just pick up and start making things with, without having to spend hours with setup and tutorials. A user should be able to drag in a default character controller and immediately have working character input and movement, the whole shebang. They should then be able to easily add behaviour to objects in the scene in a way that feels natural – telling a sheep to jump 17 feet in the air when the player approaches should be a simple line or two of code. Obviously sheep don’t jump that high though, it’d be terrifying if they did. Or baaaaad.

So that’s my approach. I’m going to add in the absolute basic features that a new user will want or need and let them build everything else on top of that framework. To aid that, I’ll also try and write a bunch of tutorials and sample code to guide users into writing the more complex and weird stuff that I don’t think needs to be baked into the engine itself. That way, it’s not as if I completely neglect the existence of the more useful features, but I don’t just provide them for the sake of making my engine do your tax returns and make toast for you while you’re working.

One of the more exciting things about my project is that I’m going to try and use Vulkan, the shiny new graphics API by the Khronos Group. It’s sorta like OpenGL++, but not really. Khronos basically took the remnants of AMD’s Mantle API and created a cross-platform graphics API for the modern age, which allowed them to make different design decisions to the ones made during OpenGL’s development. As a result, the API provides much lower-level access to hardware, but this makes everything so much more verbose; it’ll be a challenge to implement Vulkan support, but I’m confident I can get it working with a little elbow grease. By that, I mean a lot of coding all-nighters. And hey, if it doesn’t work, I can always fall back to OpenGL.

I’ll be returning to this blog every now and then to document my progress, and when the time comes, upload working downloads for people to try out the engine. That’s a very far way off currently though! I hope this whirlwind tour of my plans make sense, although I’ve probably missed some stuff out, so let me know if something doesn’t make sense. It’d actually be hugely useful for me to know what people’s most requested features or major gripes about their choice of game engine or development tool are, so feel free to bellyache and rant in the comments section about something your game engine does that you think could be improved!

ShaderLab Programming #1 – Sepia Blend Shader

Now that exams are over, I’ve had time to actually breathe and, more importantly, do game dev stuff. I’ve rarely touched computer graphics in the past, but it’s an area I’ve always wanted to explore in detail. This summer, I plan to mostly spend my time learning the intricacies of computer graphics, and that’s partially where Unity’s ShaderLab steps in.

ShaderLab is a graphics language in its own right, but it also encompasses Cg, a high-level shader language by Nvidia, and HLSL, a Microsoft shader language for use with DirectX, both of which were developed together. We don’t need to know too much about the structure of ShaderLab programs for what we’re doing, so I’m largely going to ignore it for now. I needed to create a post-processing effect similar to Unity’s built-in Sepia Tone, which is an on/off effect, with a tweak that allows it to fade in and out instead. It’s for a game I’m working on in which you can turn back time – more on that in the coming days when I’ve put together something a bit more concrete hopefully! Let’s deconstruct this super-simple program and explore what a sepia effect actually is. Unfortunately, Unity’s Sepia Tone shader seems to use some sort of maths wizardry for its fragment shader that I don’t understand, so I’ll also be writing mine mostly from scratch. Here’s the number bullshit right here:

fixed4 frag (v2f_img i) : SV_Target
{ 
    fixed4 original = tex2D(_MainTex, i.uv);
 
    // get intensity value (Y part of YIQ color space)
    fixed Y = dot (fixed3(0.299, 0.587, 0.114), original.rgb);

    // Convert to Sepia Tone by adding constant
    fixed4 sepiaConvert = float4 (0.191, -0.054, -0.221, 0.0);
    fixed4 output = sepiaConvert + Y;
    output.a = original.a;
 
    return output;
}

The infinite wisdom of the Internet tells us that to convert a source image to a sepia-tone version, we just define a function of the input colours as follows:

new red = min(in red * 0.393 + in green * 0.769 + in blue * 0.189, 255)
new green = min(in red * 0.349 + in green * 0.686 + in blue * 0.168, 255)
new blue = min(in red * 0.272 + in green * 0.534 + in blue * 0.131, 255)

This formula represents 100% sepia; that is, the source image completely turned into a sepia tone. But we don’t always want a completely sepia image – we need to incorporate some sort of progress measure. Using this formula, we can just interpolate between the input colour and the full sepia tone and use a separate script to control the ‘progress’ of the interpolation. I’ve talked about interpolation before, so if this really big word is confusing, it just means we’re picking a colour on an imaginary line between ‘original colour’ and ‘sepia colour’, with a parameter between 0 and 1. We can now create another function to get our final ‘blended’ sepia colour:

out red = parameter * new red + (1 - parameter) * in red
out green = parameter * new green + (1 - parameter) * in green
out blue = parameter * new blue + (1 - parameter) * blue

With the theory out of the way, we can now create the shader and the script that will control it. We’ll be utilising the post-processing effects provided by Unity, so make sure you import them from the Standard Assets using Assets->Import Package->Effects from the menu bar. We’ll start with the controller script.

There are two main ways to keep track of the progress, so I’ll cover both. The first way is to define a method such that another script can just pass in a float to act as the parameter.

using UnityEngine;

namespace UnityStandardAssets.ImageEffects
{
    [ExecuteInEditMode]
    [AddComponentMenu("Image Effects/Color Adjustments/Sepia Blend")]
    public class SepiaBlend : ImageEffectBase
    {
        private float progress = 0f;
        private bool active = false;

        private void SetProgress(float progress)
        {
            this.progress = progress;
            active = (progress == 0f);
        }

        // Called by camera to apply image effect.
        void OnRenderImage(RenderTexture source, RenderTexture destination)
        {
            if(active)
            {
                material.SetFloat("_Progress", progress);
                Graphics.Blit(source, destination, material);
            }
        }
    }
}

OnRenderImage() is the method called when we want to render a post-processing image. We set the ‘progress’ parameter of the material attached to this project – we’ll see how this works with that material’s shader shortly – and use Graphics.Blit() to apply the texture created by the shader to the screen. The second way to control the progress parameter is to allow external scripts to set the ‘active’ boolean and use a time-based interpolation to decide what the progress should be. The guts of the program will look more like this:

private float progress = 0f;
private bool active = false;

private void SetActive(bool active)
{
    this.active = active;
}

private void Update()
{
    progress = Mathf.Lerp(progress, active ? 1f : 0f, Time.deltaTime
        * 5f);
}

// Called by camera to apply image effect.
void OnRenderImage(RenderTexture source, RenderTexture destination)
{
    material.SetFloat("_Progress", progress);
    Graphics.Blit(source, destination, material);
}

Now for the actual shader! I’ll explain very quickly what the fragment shader is doing and ignore the vertex shader since it’s doing nothing in this example; I may do another post in the future explaining the details of how the shader is constructed, but I’m glossing over a lot for now. Don’t even worry about it yet.

Shader "Hidden/SepiaBlendEffect"
{
    Properties
    {
        _MainTex ("Base (RGB)", 2D) = "white" {}
        _Progress ("Progress", Float) = 0
    }
    SubShader
    {
        Pass
        {
            ZTest Always Cull Off ZWrite Off

            CGPROGRAM
            #pragma vertex vert_img
            #pragma fragment frag
 
            #include "UnityCG.cginc"

            uniform sampler2D _MainTex;
            uniform float _Progress;

            fixed4 frag(v2f_img i) : SV_Target
            {
                fixed4 original = tex2D(_MainTex, i.uv);
 
                half3x3 vals = half3x3
                (
                    0.393, 0.349, 0.272, // Values for input red.
                    0.769, 0.686, 0.534, // Values for input green.
                    0.189, 0.168, 0.131  // Values for input blue.
                );

                half3 input = half3(original.rgb);

                half progress = half(_Progress);

                half3 intermed = (progress * mul(input, vals)) + 
                    ((1 - progress) * input);

                fixed4 output = half4(intermed, original.a);

                return output;
            }
            ENDCG
        }
    }
    Fallback Off
}

We’re interested in the stuff between ‘CGPROGRAM’ and ‘ENDCG’ – this is written in Nvidia’s Cg. All we need to know about the structure of shaders for now is that the fragment shader is run on every pixel of a processed image. I’ll also ignore all the types of variables for now and cover those in another post at a later date. Jumping straight to the frag() method, which constitutes the fragment shader, we’ll see a 3×3 table of numbers, vals, that looks strikingly like the one defined for our first function; the table is the transpose of a matrix formed by those functions’s numbers. Our shader performs a matrix multiplication on a vector made of the original rgb values, input, and our magical sepia number matrix vals (which is why it had to be transposed), then we do our interpolation to get intermed. Afterwards, we put together the final output by adding the original colour’s alpha onto intermed, and boom! We have our Sepia Blend shader. Now all that remains is to attach the SepiaBlend script to the main camera and assign the SepiaBlendEffect shader to the script, then we’re good to go.

I hope this has been a helpful introduction to the world of computer graphics. I’ve uploaded the three scripts to avoid you having to copy everything out (both variants of SepiaBlend.cs are included; pick your preferred version). Let me know if everything turns into a bugfest when you attempt to run any of the examples and I’ll try to diagnose the problem.

Shifting Dungeons ~ Post-LD35 Update 1

One thing I’ve become exceedingly bad at is updating games once I’ve thrown them onto the Internet for the first time. The last time I did such a thing was probably over a year ago. But, starting today, I am a changed man! For I have vowed to complete Shifting Dungeons to a standard that I’m happy to put my name to and watch it run off into the wider world, playable and somewhat consistent. Ahh, games, they grow up so fast. I’ve been very preoccupied lately with ruining my sleep schedule by doing coursework right up until deadlines (and beyond…), but that didn’t stop me tweaking Shifting Dungeons a bit.

Without further ado, it’s time to list what’s changed! That’s what change-lists are for, after all.

giphy

Character Customisation

There’s a handful of new character customisation options, bringing the total of skin and clothing colours available to 8 each. That may increase in the future, but for now I’ve stuck with 16 total options because the UI feels clean and not overwhelming with choice, while providing a relatively broad number of outfit combinations.
The whole character customisation scene has a background too – I’ve decided to make it look like the player is getting changed in their bedroom. It’s woefully incomplete currently, but it’s a start.

promo-dev-06

Options Menu

The bare basics of an options menu are also now in the game. Most importantly, this menu has an exit button – something I’m very good at forgetting to add. Now you don’t have to Alt+F4 out of the game or use Task Manager! There are sliders for adjusting music and SFX volume and for changing text speed, but they don’t do anything right now (especially since there’s no music and next to no text). However, the sliders’ values are accurately stored, so it’s a start! I’ll probably have them fully implemented by next update.

promo-dev-04

Intro Cutscene

I’ve also started work on a cutscene for the start of the game. It’ll be rather short and serve only to introduce the concepts and backstory of the game in a better way than the Ludum Dare entry version handled it – a wall of text. Instead, short sentences accompanied by pretty pixel art will probably work better. Similar cutscenes will appear during major story arcs, but since there’s no story right now, this is the only cutscene implemented.

promo-dev-05

Controller Support

Any controller that supports X-Input should work with the game. I say should; I’ve been testing the game using a Wii U pro controller and an adapter that allows it to mimic an Xbox 360 controller (which uses X-Input), so hopefully it also works with other X-Input devices, although I can’t promise anything will work perfectly. The controls are fairly simple and you shouldn’t have any trouble getting to grips with them. However, there are no in-game instructions for controllers, so here is an image detailing how the controls work (which I probably could have just included in the game anyway):

promo-dev-02

Enemy Lock-on

To make it easier to take down baddies, you can now lock onto them. On a controller, aim in the general direction of the enemy and press the left button; using a mouse, press the right mouse button. It’s the same button to de-lock (lock off?), but make sure you’re not aiming at an enemy when you do it or it’ll just lock onto the new enemy. Unless that’s what you wanted to do, then great, that’s how you do that. When locked onto an enemy, their health will appear next to them and decrease in realtime, plus your bullets will fire straight at them, so you can see why it’s a handy feature. Plus, when you kill a locked-on enemy, it’ll automatically lock onto any nearby enemies. To aid your aiming, there’s a second cursor – the orange one is for locking on while the white one is the mouse’s actual position. I’ve yet to implement the white cursor for controller input, but it’ll be in the next update for sure. Oh, and the cursor sprite and animation is a lot fancier, too.

promo-dev-03

Mechanical Changes

The biggest gameplay change is possibly the addition of the Energy bar. There is a distinction between powerup energy and general energy, hence there two energy bars; the leftmost one, with the thunderbolt icon, will decrease when you fire bullets or slow down time and replenish when you move. The one on the right, with the arrow icon, starts off full when you pick up a powerup (try saying that five times fast), then slowly falls as you move until it reaches zero and the powerup expires. Health replenishes as you move as before, but at a slower rate, plus the UI is more reactive; being hit makes the health bar shake, and having low energy makes the energy bar shake more, the lower energy you have. Staying stationary also no longer stops time completely, but it slows it down a lot.

Shooting mechanics have had a bit of a mix-up too. Your bullets and enemy bullets don’t collide any more, as it provided an easy way to get rid of enemy attacks and there was no incentive to use the time-slowing mechanic to dodge bullets. However, you can now hold down the shoot button to start a hailstorm of bullets and wipe enemies off the map without me being liable for loads of repetitive strain injury lawsuits! To balance the increased shooting speed and the ability to lock on to enemies, your bullets do half as much damage, although in the next update I hope to add some system such as different bullet types that’ll let the player (and enemies) do more damage.

A few other changes are there, namely that rooms are much larger and the camera is zoomed out so the player can see further. It makes it slightly less confusing when you can hear you’re being shot at, since you can more easily see where it’s coming from by virtue of the threat actually being on-screen or only just off-screen, not a million miles away.

giphy1

Yay low-quality GIFs! My computer is just bad at everything…

Bug Fixes

You know that game-breaking bug I wrote about in the last blog post? The one that means you couldn’t get past the first dungeon because you’re unable to move on its final floor? That’s been squished. There were also a couple oversights where the game would sometimes skip to the final floor when there was supposed to be another standard floor before it, but now the floors act like they should.

Bugs Implemented

There’s only one that I’ve actually found and can remember, and it’s not hugely important: on the character select screen, the player’s face appears blank. That’s because technically he’s looking upwards, and due the the fact the player’s at an angle in 3D space, the game doesn’t recognise the mouse position correctly and doesn’t face it. If you press the right stick on a controller, the player will face the correct way, but unfortunately the right stick’s rest position has the player looking upwards anyway… Swings and roundabouts, huh?

promo-dev-07

Meet the very introverted and shy hero of the game.

Next Update’s Priorities

Most of all, I hope to implement more enemy types. Right now, there’s only one type, and they share the same sprites as one of the character customisation options. They all share the same terrible AI too, so I’m going to at least attempt to work on pathfinding and give some enemies different attacking styles. I’ll also try to make more dungeon types and give more variety to the dungeons themselves – different sizes, shapes and maybe obstacles inside the rooms. Plus, I’ll try to finish the powerups that were originally planned for the Ludum Dare version and implement new ones – the ‘shapeshifting’ aspect of the game is a little bare currently. Finally, I still need to balance the floors’ difficulties and spawning rates of enemies and powerups, since it’s still very imbalanced.

ld35_u1_download_banner

Game Design Tips #16 – [Unity + C#] Linear Interpolation

It’s been an awfully long time since my last post – blame coursework! I have a few weeks to get a couple of posts in before I have more coursework and then exams, so enjoy me while I’m here.

If you’ve coded at all with Unity, you’ve probably noticed its API has a lot of methods called ‘lerp’. Mathf.Lerp(), Vector3.Lerp(), Color.Lerp(); all of these are very helpful methods. But what exactly do they do, and how should we be using them properly? First of all, I’m gonna go ahead and show you how they’re meant to be used, then I’m gonna break them horribly to show you cheap ways of doing cool stuff.

How to use Lerp without being hacky

‘Linear Interpolation’ is a lot of syllables to get your head around, so first of all, let me explain what it means. Let’s say we have a thing. We want the thing to change into another thing at a constant (linear) rate. This is what linear interpolation does – it takes a vector, colour, float, you name it, and changes it into a new one.

tip-16_img01

This is the lerp method for Vector3. We pass in startPos, endPos (both Vector3s) and a float parameter; this parameter should be between 0.0 and 1.0. When time = 0.0, the object’s position will be 100% at startPos and 0% at endPos, and when time = 1.0, it will be placed at 0% startPos and 100% endPos. It’s easiest to demonstrate what lerp is doing when talking about Color.Lerp(), so we can use a pretty diagram:

tip-16_img02

Here, the square represents the RGB colour scale found in Unity’s colour picker (well, flipped horizontally). When we use Color.Lerp() in this way, when the third parameter is 0, the method returns a red colour (#ff0000 in hexadecimal RGB colour representation) and when the parameter is 1, we get full white (#ffffff). At any point in between, we blend between the two linearly – at 0.5, we’ll get a pink-ish colour exactly halfway between red and white on the RGB scale (#ff7f7f roughly) and at 0.75, we get something mostly white but retaining a tiny bit of red (about #ffbfbf).

Once we understand what lerp is doing when we pass in certain numbers, we can pull everything together cleanly into a coroutine.

tip-16_img03

We pass in the sprite renderer whose colour will change, the colour it will change to and how long it will take to change. The coroutine automatically works out all of the needed variables for the user, so we don’t need to pass in the start colour. Every frame, we set the new colour of the renderer based on what percentage the current time is between the start and end times. Simple! The final step is to ensure the colour gets set to the end colour exactly, since the loop might have exited only 99.9% through the lerp (it’s never going to be noticeable to the human eye, but I’m doing this for the sake of completeness and to avoid triggering anyone’s OCD).

How to use Lerp badly

Now that we know how to use lerp properly, it’s time to be a terrible person! I’ll show you one popular way of using lerp badly. Assume, for the following example, that the ‘speed’ variable is set to 0.1f.

tip-16_img04

tip-16_img05

I’ve tried to illustrate what happens on each frame here. At the start (on the first time interval), the sprite colour is at its original colour. At the second time interval (0.1s after starting), we have moved 10% from the original position towards the final position. This is easy to understand – we move 10% of the way between full red and full white (assuming the original colour was red and targetCol is white). On the next interval, we have travelled another 10%. However, the starting point was not the original red – it was 10% towards white. This means the current colour is 10% between the last colour and full white; it is now 19% towards full white. This process continues; rather than moving linearly between red and white, the end result is a curve.

The reason this works is because the time parameter we pass in is always a fraction between 0 and 1, but the start colour is always changing too. It’s not exact, but roughly every 0.1s, the colour will change 10%. The numbers above won’t be precise since the lerp is running every frame, not every 0.1s, but hopefully this gives you an idea of how this blasphemy is working behind the scenes. This isn’t how lerp is intended to be used, but it is a cheap way of moving between vectors, colours or floats on a curve. It’s disgustingly amazing – dismazing, if you will.

It’s also worth noting that if the parameter passed to lerp is set to below 0 or above 1, it will snap up or down to those boundary values. Now you should be a certified lerp expert! I’ve put both versions of the linear interpolation script online for you to download if you’re too lazy to copy them (which is only a problem because I’m too lazy to make them look nice without resorting to taking screenshots. My bad).

Game Design Tips #14 – [Unity + C#] Persistent Data

Today I’m gonna talk about how you can save data to disk and read it back later. Unity has a utility built-in for this – they’re called PlayerPrefs – but for anything more than perhaps options and preferences, you’re going to want a more robust system for saving data between scenes within your game or separate game sessions. This is where I jump in and throw a bunch of fancy C# things at you! Note – this system should work on standalone platforms such as Windows, Mac and Linux and mobile platforms, but it won’t work on Web Player builds or platforms such as Samsung TV. I’m not sure if it works on console platforms since I don’t have the resources to develop for any of them and the internet has been unhelpful in this regard, but oh well. Time to get started!

There is a lot of motivation for wanting to save data to disk; high scores, player progress, and player-customised assets are all types of data we want to make persistent. I’ll be showing you how to achieve this in Unity using C#. To do this, we need to package up the data we’re going to save into its own class.

tip_14-01

We’re going to put this portion of code right below the SaveStuff script, which we’ll be writing next. For the SavableObject class, we’ve made a bunch of variables that we want saving to disk. In this example, imagine there’s a guy named Bob, and that he wants to remember his own name, how many bananas he’s holding, how long he’s been dancing (measured in hours – he’s an active bloke) and whether he’s made of wood. From this, we can only assume the following: he’s forgetful, probably a fan of potassium, potentially flexible, and doesn’t remember if he’s a real boy. But my game doesn’t know that! That’s why I’m going to save all this crucial information to disk.

tip_14-02

THIS is my all-knowing, all-powerful SaveStuff script. Let’s gloss over all the important things this script is doing – I’m sure you’ll be able to fill in the rest. It may get a tad boring, but bear with me, because saving things is actually really fun. Honest.

First of all, you can see a small snippet of the SavableObject class at the bottom of the file to show you where I’d place it. It has a [Serializable] attribute (line 36) – in order to use this, we need to import the System namespace (line 2). In the Start() method, we make our new SavableObject and specify Bob’s name as “John” (turns out he’s really forgetful) and his body’s wood status to “true”. The constructor for SavableObject already specified default values for numberOfBananas and danceTimer, so we won’t have to worry about those. Oh, and System.IO is imported for use of FileStream and File, whereas System.Every.Bloody.Word.In.The.English.Language is used for BinaryFormatter. Now let’s save Bob’s status.

Here’s the part where I attempt to make C# exciting! SaveMyStuff() is now going to do a bunch of fabulous things. We make a fun little BinaryFormatter we’ll be using shortly and then create a wonderful, happy file called “myThings.dat”. One thing to note here – I was dumb when writing this example, so it should actually be “/myThings.dat” to ensure the file goes inside the folder at Application.persistentDataPath. We serialise the data from the SavableObject we made earlier (using rainbows), turning it into a binary string that an ordinary user wouldn’t be able to comprehend if they opened the file manually. We then close the file up and wait a second before calling LoadMyStuff() on our loader object (in practice, this second’s worth of waiting may be replaced by an arbitrary amount of time, perhaps even including closing the game and reopening it). Closing the file is a very important step, since C# places a ‘lock’ on the file while it’s being accessed, and trying to access it from elsewhere at the same time – while it’s locked – would be reeeeally bad. Got all that? Good! I told you C# was fun! Now let’s introduce the LoadStuff class and go over its features.

Oh, by the way, Application.persistentDataPath is a ‘default’ filepath that varies by export platform. Most games that use Unity will probably use this default path plus a bit of extra filename appended to it (as I have here). The filepath also contains the company name and game name, both determined in the PlayerSettings in the Editor (found at Edit/Project Settings/Player).

tip_14-03

This script happens to be pretty similar to SaveStuff, but does things backwards. In LoadMyStuff(), which happened to be called by SaveStuff (it doesn’t matter what called this method in practice, I just did that for convenience), I first check if the file “myThings.dat” exist. If it does, I create all the necessary things, as with SaveMyStuff(), but this time I’m opening the file instead of creating it. That’s why it was necessary to check that the file exists, because trying to open it if it didn’t would make things cry/crash/explode. Now that the file’s open, I can deserialise its contents, un-binary format it and stick it back into a SavableObject. Then all there is to do is grab the variables out of that object, plonk them all into a horrible example of how not to concatenate strings together, and watch the Console output all our data with no errors whatsoever.

tip_14-04

Congratulations, you’ve just saved to disk and loaded up that data back from disk! It’s a very useful feature you’ll find yourself using in a variety of places; from remembering player’s preferred options to keeping track of game progress, the possible uses of saving to disk are endless.