Monday, March 19, 2018

Simple Transition



I have worked on a simple Unity asset called Simple Transition, a screen transition add-on for doing screen swipes and swirls.

Here it is for free! If you use this, simply give me a nod and let me know it helped you out :)






If you find it useful, please donate to the development.
 Donate

DOWNLOAD

Tuesday, October 31, 2017

Galactic Metal - 10/17 - Teaser!


Trailer Time!



This month was GCAP and time to get something to show!
So treat yourself to this tasty trailer and rock out!


Introducing the 'Pickup Drone'

A new member to the Galactic Metal family is the Pickup Drone!
This little guy is going to make life just that little more challenging :)

Saturday, September 30, 2017

Galactic Metal - 09/17 - Shields!

Adding to the project this update is some shield effects!

By exposing some options for the shader such as type, distance from ship and HDR colour - this allows for a huge variety of options, all in the same shader!



Also by having these set as exposed properties, we can alter at run-time!
The below video demonstrates one ship protecting others with a generated shield, this shield inherits the colour of the shield generator from the protecting ship.



Pretty cool hey!
Looking forward to creating a bunch of different types!

Monday, August 14, 2017

Galactic Metal Update: Aug/17

So, Galactic Metal is nearing Alpha release - woooooo!!!
The next few weeks will concentrate on getting some art assets into the game to make it feel a bit more than just a prototype :)

Here are some images from the first enemy ship known as the A-Minor.

Concept Art


High Poly Render

Final Render

Art Direction

The aesthetic for the game is for a rounded comical 50's style ships. The art will be very simple, almost cartoony so I decided to use vertex colours rather than a texture map.
The technical art decisions for the enemy ships are as follows...
  • 2000 - 5000 poly budget
  • Vertex colours
  • Emission map 
  • Normal map
  • Specular/Gloss map
  • Metallic map

Custom Gloss/Metallic/Emission Texture

My requirements had 3 input greyscale textures; Gloss, Metal and Emission. To optimize the shader, I decided to create a single texture which combined all this data into each of the RGB channels.
I created what I call the GME (Gloss, Metallic, Emission) texture which helps me remember what the channels are for :) 

To do this, in photoshop I have each channel separated into their own folders. Then for each section which needs some value, for example the cockpit window with emission, I create a solid white layer and mask out just the section I require. I then assign a Opacity value for how much emission I wish this part to have.  In this case, I wanted the cockpit window to emit, however I also wanted the other parts to have a HDR boost, so I lowered the opacity for the window to allow this.
Then, the Emission folder is told to fill only the blue channel (GME -> RGB).
The end result certainly looks 'interesting' and at first glance you would not consider this as any meaningful art asset!

However, the shader knows what to do with this ;) 



While this ship was very flat in terms of it's gloss maps, here is another example from a different ship which looks a whole lot more interesting due to the way the different channels are layered.

Shading

Due to the vertex colours, I wrote a custom shader to do the shading, simply using the vertex colours while applying a gloss, metallic and emission value from the custom texture mentioned above.

Here's the shader which does all the magic...

Shader "Galactic Metal/Enemy Standard" {
    Properties {        
        _RimColor ("Rim Color", Color) = (1,1,1,1)
        _RimPower("Rim Power", Range(0, 10.0)) = 3
        _GMEmap ("Gloss/Metallic/Emission Map", 2D) = "white" {}    
        _Normal ("Normal Map", 2D) = "bump" {}    
        _NormalMultiplier("Normal Multiplier", Range(0.1,5))    = 1
        _Glossiness ("Gloss", Range(0,1)) = 0.5
        _Metallic ("Metallic", Range(0,1)) = 0.0
        _EmissionAmount("Emission Amount", Range(0,20)) = 1
    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 200
        
        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Standard fullforwardshadows

        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0
        
        // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
        // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
        #pragma instancing_options assumeuniformscaling
        UNITY_INSTANCING_CBUFFER_START(Props)
            // put more per-instance properties here
            //UNITY_DEFINE_INSTANCED_PROP(type,var)
            
            
        UNITY_INSTANCING_CBUFFER_END
        sampler2D _GMEmap;
        half _EmissionAmount;
        sampler2D _Normal;
        half _NormalMultiplier;
        float4 _RimColor;
        half _RimPower;
        half _Glossiness;
        half _Metallic;

        struct Input {
            float2 uv_GMEmap;    
            float2 uv_Normal;        
            float3 color : COLOR;
            float3 viewDir;            
        };

        void surf (Input IN, inout SurfaceOutputStandard o) {                                    
            float3 gme = tex2D(_GMEmap, IN.uv_GMEmap);
            o.Normal = UnpackNormal(tex2D(_Normal, IN.uv_Normal));
            o.Normal.z = o.Normal.z / _NormalMultiplier;
            o.Normal = normalize(o.Normal);
            
            half rim = 1-saturate(dot (normalize(IN.viewDir), o.Normal));        
            
            o.Metallic = gme.g * _Metallic;
            o.Smoothness = gme.r * _Glossiness;
            
            o.Emission = ( IN.color * (gme.b * _EmissionAmount) )  +  (_RimColor * pow(rim, _RimPower));
            o.Albedo = IN.color;
        }
        ENDCG
    }
    FallBack "Diffuse"
}



Which nets this cool result here, notice the gloss map has a high specular highlight on the cockpit window and the body of the ship, this ship also has more of a metallic shine while the blue jets have a mat finish, no gloss.

InGame With Shader

 

Conclusion

Everything is in the right direction, now it's just a matter of pumping out some art assets and polishing the UI for the alpha test :) 
I'll post some more artwork as they come.

Sunday, July 16, 2017

SunJam 2017

Jam Time!

Yes, it's that time again - SunJam 2017 has hit the Sunshine Coast, so time to lug the workstation somewhere and punch out a game!

You're What Now?

This time I decided not to enter as a programmer, rather as an artist. I wanted to try my hand at something new and different so this was a great place to give it a shot!

Deep in the Trench

So not only doing art, I decided to do some hand drawn sprite animations! This was a fun experiment, and my hat goes off to those who do this full time!

I also composed a background music loop and other sounds.

Always Something Different

While this wasn't the game I thought I'd be making, it was good to do something a bit out of the norm.
If you want a good laugh, go check it out! https://scrapsgamedev.itch.io/divide

Tuesday, May 2, 2017

What Is Object Pooling And Why Do I Need It?

Why Do I Need Object Pooling?

I think we'll work backwards and talk about why we need it, then talk about what it is...

Let's think of a scenario where you have a shooting game.  Each bullet renders on the screen as a GameObject and the player is pretty trigger happy, letting loose four bullets a second for a duration of a three minutes.

Over this time, the player has instantiated 720 game objects!

Now I know what you may be thinking... Surely you destroy the bullet when it has reached it's lifetime so that won't be a problem - there won't be 720 bullets in the scene.
You're right, of course you would do something about the stray bullets - however when it comes to memory management cleanup (see ref 1) and the Garbage Collector, there is going to be some performance cost which can introduce the dreaded micro-stutter!

I have performed a very basic test to prove the theory by replicating the above scenario over 20 seconds of shooting 4 projectiles a second.  The scene was very basic and the projectiles were nothing more than a standard Unity cube. Let's take a look at the asset memory consumption gathered from the profiler shall we!

Without Object Pooling: 402KB
With Object Pooling: 146KB

"Whoa... Steady on cowboy, I'm pretty sure my system can handle a spare 256KB of memory" I hear you say.
True... However, keep in mind the situation... 
  • There is nothing in this scene except basic cube geometry
  • The tests were run for only 20 seconds
This is a 36% increase in memory efficiency!

This is exactly why we need object pooling - performance!
So what is it?

What is Object Pooling

In it's simplest definition, object pooling can be thought of as recycling.

Rather than instantiating a whole bunch of clone GameObjects only to destroy them shortly after, Object Pooling simply disables the object and tucks it away for reuse later on when a new object of that type is needed.

There are likely a stupendous amount of examples for how to create an Object Pooling system - so let us add to the list and I'll demonstrate my implementation below ;) 

Creating An Object Pooling System

Let's build an Object Pooling System!
What do we need? Well let's see, we need to...
  • Set a starting pool size
  • Know what object to pool
  • Handle dishing out the objects in the pool
  • Handle what happens if the pool is empty
  • Know when to recycle the object (normally when it would be destroyed)
Cool - so let's do ourselves a favour and make sure we can easily listen out for the recycle request - we should use an event! I've opted to create a MonoBehaviour class which will be added to any recyclable object...

// IPoolable.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

public class Recyclable : MonoBehaviour
{
    public event Action RecycleEvent;

    private void OnRecycleEvent(GameObject obj)
    {
        Action handler = RecycleEvent;
        if (handler != null)
        {
            handler(obj);
        }
    }
    
    public void Recycle()
    {        
        OnRecycleEvent(gameObject);
    }
}

This class can be added to any object now via an Object Pool Manager.  This manager's responsibilities will be to add this component and listen out for the event when it has called to be recycled.

Below is the entire pool class which comments really speak for themselves, but I'll point out some important notes below...

// ProjectilePool.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

public class ObjectPool
{
    private GameObject objectPrefab;
    private List activePool = new List();
    private List readyPool = new List();
    private const int POOL_SIZE = 5;

    private Transform objectParent;

    public ObjectPool(GameObject poolableObject, Transform parent)
    {
        BuildPool(poolableObject, parent);
    }

    public void BuildPool(GameObject poolableObject, Transform parent)
    {
        objectParent = parent;
        objectPrefab = poolableObject;
        for (int i = 0; i < POOL_SIZE; i++)
        {
            // Instansiate a bunch of objects ready to go
            GameObject obj = GameObject.Instantiate(objectPrefab, objectParent);
            obj.SetActive(false);
            // Check if Recyclable component has been added
            if (obj.GetComponent() == null)
                obj.AddComponent();
            readyPool.Add(obj);
        }
    }

    public GameObject GetFromPool()
    {
        // If there are no ready objects, spawn a new one and add to the list
        if (readyPool.Count == 0)
        {
            // Run out of objects - spawn new one            
            GameObject obj = GameObject.Instantiate(
                objectPrefab, objectParent);
            obj.SetActive(false);
            obj.AddComponent();
            // Subscribe to Recycle Request event    
            obj.SetActive(true);
            obj.GetComponent().RecycleEvent += Recycle;            
            return obj;
        }
        else
        {
            // Pull out first objects from ready list and move into active list
            GameObject obj = readyPool[0];
            readyPool.Remove(obj);
            activePool.Add(obj);
            obj.SetActive(true);

            // Subscribe to Recycle Request event            
            obj.GetComponent().RecycleEvent += Recycle;
            return obj;
        }
    }

    private void Recycle(GameObject obj)
    {
        // unsubscribe from Recycle Request event        
        obj.GetComponent().RecycleEvent -= Recycle;

        // Disable GO ready to be used again, move to ready list
        obj.SetActive(false);
        activePool.Remove(obj);
        readyPool.Add(obj);
    }

    public void PurgePool()
    {
        if (activePool.Count > 0)
            for (int i = 0; i < activePool.Count; i++)
            {
                PurgeGO(activePool[i]);
            }

        if (readyPool.Count > 0)
            for (int i = 0; i < readyPool.Count; i++)
            {
                PurgeGO(readyPool[i]);
            }
    }

    private void PurgeGO(GameObject go)
    {
        activePool.Remove(go);
        GameObject.Destroy(go);
    }

    public bool CheckPrefabMatch(GameObject match)
    {
        return (match == objectPrefab) ? true : false;
    }
}
What a mouth full ;)
Let me explain what is happening here.

The Constructor

The constructor is taking in two parameters, a prefab and a parent location. Pretty straight forward, the constructor loops through a bunch of times and fills up a list of GameObjects ready to be used, also making sure they are set to be disabled.

GetFromPool

This function returns a GameObject from... You guessed it, the object pool!

First it checks if there are any free from the ready list, if not - it will instantiate a new one, growing the list dynamically as required.

Importantly - there is something noteworthy happening here...
It is subscribing the method Recycle to the RecycleEvent (see ref 2 for more info on events).
Also, note that if there isn't any objects available, the pool simply expands by one :)

Recycle

As it states, this nifty little method does the object recycling. It will unsubscribe from the object's recycle event, set it inactive and move it from the active pool into the inactive pool.
Nice and simple.

How To Implement It

This is nice and simple! For this example I created an Object Pool Manager as a singleton to look after all recyclable objects in the scene..

using System.Collections;
using System.Collections.Generic;
using UnityEngine;


public class ObjectPoolManager : MonoBehaviour 
{    
    public static ObjectPoolManager instance;
    public List projectilePool = new List();

    private void Awake()
    {
        if (instance == null)
            instance = this;
        else
            Destroy(this);
    }

    public void BuildPool(GameObject prefab, PoolType type)
    {
        // Check if pool exists
        if(!CheckPoolExists(prefab, type))
        {
            List poolList = GetPool(type);
            ObjectPool newPool = new ObjectPool(prefab, transform);
            poolList.Add(newPool);
        } // else never mind because this projectile already exists
    }

    private bool CheckPoolExists(GameObject prefab, PoolType type)
    {
        bool result = false;

        List poolList = GetPool(type);
        

        for (int i = 0; i < poolList.Count; i++)
        {
            if(poolList[i].CheckPrefabMatch(prefab))
            {
                // match found
                return true;
            }
        }        
        return result;
    }

    public GameObject GetObject(GameObject objectPrefab, PoolType type)
    {
        // find which pool
        List poolList = GetPool(type);
        
        for(int i = 0; i < poolList.Count; i++)
        {
            if (poolList[i].CheckPrefabMatch(objectPrefab))
            {
                return poolList[i].GetFromPool();
            }
        }
        Debug.LogError("Object not found in pool");
        return null;
    }

    private List GetPool(PoolType type)
    {
        switch (type)
        {
            case PoolType.projectile:
                return projectilePool;
            case PoolType.tileset:
                return tilesetPool;
            default:
                Debug.LogError("Pool not found!");
                return null;
        }
    }
}
This script does most of the heavy lifting :)
The Object Pools can be referenced from other classes, such as a weapon system and pull a copy from the pool. But wait... Is that a LIST of pools :o
Yes! So you can see how powerful this manager can be.

This manager checks for a matching prefab type, if one is found then it returns the next available object from it's respective pool!

Conclusion

As mentioned, there are numerous ways to handle Object Pooling - this is just one. You could also build on this - for example my weapon had two modes of fire, so all I had to do was request the projectile prefab, and bam! The next available one was returned for duty.

If anything, you should now have a solid concept of what an Object Pool is and why you should use them!

References

Monday, January 30, 2017

GGJ (Global Game Jam) 2017


Beach Ball Splashdown!

This was my very first ever game jam, so I had very little idea of what to expect! What made it more interesting, I was an organizer! My role was to provide IT support should any issues arise.

Day One 

We all got introduced to the theme - WAVES.

This could be anything! We toyed with ideas from an Endless Summer surfing game through to lighthouses blasting light waves.

Eventually our team decided to make a beach ball game similar to air hockey, however you blast the ground causing shockwaves which propel the ball in a direction.

Day Two

Discovering the coffee shop across the road made the whole weekend just that much better!
After some much needed caffination, we got to work assigning roles and pumping out some results.

We had a very talented up-coming 3D artist make some great looking assets.
I created a mesh which implemented the ripple effect we were wanting and the other programmers nutted out the character controllers and game loop.

We were off to a solid start!

Day Three

Final day and we're pretty much ready to go!
Our audio guy had made a fantastic sound track, along with some cool sounds.
I implemented the audio, added some sandy terrain and some other code tidy ups while the other programmers finished a fully functioning UI system.

Ready to Go!

And here we are, all finished - it's far from perfect - but is fun, not bad for a few days worth of work!