Sunday, 15 February 2015

Unity3D Shaders

<< Previous                                                                                          Next>>

So, I hope, prior to reading this tutorial you have read my previous post laying down some fundamental ideas we sort of need before we start to look at creating shaders. If you haven't, then please, hop back and have a read of it here, or simply click the << Previous links at the top and bottom of this post.

Ill repeat my caveat here, I am no shader or Unity expert, these posts are based on what I have found through my own exploration of shaders in Unity, but I hope what you find here gives you some pointers and ideas for your own shaders and adventures creating shaders :)

Unity gives us a few shader types that we can write, surface shaders, as well as vertex and fragment shaders.

If you are coming from XNA/DX vertex shaders are the same as DX9 vertex shaders and fragment shaders are the analogue of pixel shaders. In XNA there is no analogue with surface shaders.

If you have no experience of shaders at all, then I had best describe to you the difference of each of these shaders.

Vertex Shader

A vertex shader is a function that runs on the GPU, it takes a single vertex (as described in the last post) and places it on the screen, that is to say if we have  a vertex position of 0,0,0 it will be drawn in the centre of out mesh, if the mesh then has a position of 0,0,10 the vertex will be drawn at that position in the game world. This function returns this position data, as well as other data back to the graphics pipeline and this data is then passed, after some manipulation, to the pixel shader, or in the case of Unity, it may be passed to a surface shader, depending how we have written it.

A vertex shaders calculations are done on each vertex, so in the case of our quad from earlier, this would be executed 6 times, once for each point of the two triangles the quad is made up of.

Pixel Shader

The pixel shader is given each and every pixel that lies with in each of the triangles in the rendered mesh and returns a colour. As you can imagine, depending on how much of the screen your mesh takes up, this could be called once for every pixel on your screen!! Needless to say pixel shaders are more expensive that vertex shaders.

Surface Shaders

These are a strange halfway house between the vertex and pixel shader. You do not need to create a vertex shader with a surface shader as Unity will use it’s default one, but you can if you need one, we will cover that later. It comes with a set of predefined elements that will automatically use the Unity lighting model. You can write you own lighting calculations too which is quite cool, but, like anything else, you don’t get something for nothing, they will have an overhead, but if I am honest, I have not had too many issues with them.

I think the first shader we should look at is the Unity Surface shader. These shaders are a great way to start as they do a lot of work for you, you don’t have to worry about all the lighting calculations, if forward rendering or deferred rendering is being used, all we have to do is worry about the colour out put.

Create our first Surface Shader

From within your Assets folder, create a few new folders called Shaders, Materials and Scripts.

In the Shaders folder, we will create out first surface shader, right click in or on the shaders folder, select Create, then Shader

image

Call this first shader SSOne. Lets take a look at what we get just by creating this shader file.

Shader "Custom/SSOne" 
{
Properties
{
_MainTex ("Base (RGB)", 2D) = "white" {}
}

SubShader
{
Tags { "RenderType"="Opaque" }
LOD 200

CGPROGRAM
#pragma surface surf Lambert

sampler2D _MainTex;

struct Input
{
float2 uv_MainTex;
};

void surf (Input IN, inout SurfaceOutput o)
{
half4 c = tex2D (_MainTex, IN.uv_MainTex);
o.Albedo = c.rgb;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}

First things first, I removed the silly java style brackets, the ones that have the opening ‘{‘ bracket on the same line as the condition or definition, they should always be on the next line in my opinion ;)


So, we have a few things going on in this file already, we will look at them in turn moving down through the file.


Shader Name


At the top we have the Shader name in quotes, with this field we are also able to change how unity displays it in the list of shaders when we go to add it to a material.


Lets create a material to add this new shader to, in the Material folder, right click on or in it, select create then Material like this


image


Name this material SSOneMaterial, we can now add our new shader to it. Click the shader combo box, our shader is in Custom select that option and you will be able to see the shader in the list


image


Lets change the name and location of our shader, so change the header from


Shader "Custom/SSOne" 
{

To


Shader "Randomchaos/Tutorial/SSOne" 
{

If we go to add it now, it looks like this


image


Shader Properties


The properties section defines any variables we want to pass to the shader. At the moment, in the file created by unity, we only have one variable and it’s a texture to be used in this shader. There are a few different types of parameters that can be passed. Before we look at the types, lest look at the definition of the parameter we currently have.


		_MainTex ("Base (RGB)", 2D) = "white" {}

I guess the “signature” of these parameters is as follows


<param name> (“UI Description”, type) = <default value>


So, for our current parameter it has the name _MainTex, the description that will be shown in the UI is “Base (RGB)” and the type is a 2D texture, it’s default value is white, lets look at that in the UI.


image


We have a few options when it comes to parameters































Property Type


Description

Range(min,max)Defines a float property, represented as a slider from min to max in the inspector.
ColorDefines a color property. (r,g,b,a)
2DDefines a 2D texture property.
3DDefines a 3D texture property.
RectangleDefines a rectangle (non power of 2) texture property.
CubemapDefines a cubemap texture property.
FloatDefines a float property.
VectorDefines a four-component vector property.

SubShader


The next bit of this file is where all the work is done.


The first thing we see is the Tag, we have a few elements to this part of the Unity Shader file, we can control quite a few things from here


At the moment it looks like this


		Tags { "RenderType"="Opaque" }

So, as you can see we are using one tag type in there called RenderType and it’s set to Opaque, so no transparency.


So what tag types are there?



















Tag Type


Description


Queue
With this tag type you can set what order your objects are drawn in.
RenderTypeWe can use this to put our shader into different render groups that help Unity render them in the right way.
ForceNoShadowCastingIf you use this and set it to true then your object will not cast any shadows, this is great if you have a transparent object.
IgnoreProjectorIf used and set to true, this will ignore Projectors, now until I decided to write this tutorial I have never heard of these, but they do look useful :D

Lets look at the available values that can be used for Queue and RenderType


*Descriptions ripped from the Unity docs ;)


We wont use the queue tag, but it’s nice to know how we can use them, you never know, later on, a few posts down the line we might use it.






















Queue Value


Description

BackgroundThis render queue is rendered before any others. It is used for skyboxes and the like.
Geometry (default)This is used for most objects. Opaque geometry uses this queue.
AlphaTest!lpha tested geometry uses this queue. It’s a separate queue from Geometry one since it’s more efficient to render alpha-tested objects after all solid ones are drawn.
TransparentThis render queue is rendered after Geometry and AlphaTest, in back-to-front order. Anything alpha-blended (i.e. shaders that don’t write to depth buffer) should go here (glass, particle effects).
OverlayThis render queue is meant for overlay effects. Anything rendered last should go here (e.g. lens flares).

Again, at the moment we are not too concerned with these tags, but it’s good to be aware of them.





































RenderType Value


Description

OpaqueMost of the shaders (Normal, Self Illuminated, Reflective, terrain shaders).
TransparentMost semitransparent shaders (Transparent, Particle, Font, terrain additive pass shaders).
TransparentCutoutMasked transparency shaders (Transparent Cutout, two pass vegetation shaders)
BackgroundSkybox shaders
OverlayGUITexture, Halo, Flare shaders
TreeOpaqueTerrain engine tree bark
TreeTransparentCutoutTerrain engine tree leaves.
TreeBillboardTerrain engine billboarded trees
GrassTerrain engine grass.
GrassBillboardTerrain engine billboarded grass.

 


LOD


Our shader currently has the value 200, this is used when you want to restrict your shaders, so when deploying to certain platforms you may want to disable shaders > LOD 200. You can check out the the settings that the default shaders come with here. Again, this just for information, we won’t be playing with this value, in fact, we could probably remove it.


CGPROGRAM


This is where our shader code starts.


#pragama


The pragma is telling the unity compiler what shaders we are using. In this pre generated shader, this is a surface shader, it is then followed by the function name for the shader, in this case surf and if a surface shader the followed by the type of lighting algorithm to use, in this case Lambert. There are a few lighting algorithms, in hlsl I have written a few, Unity comes withe Lambert and BlinnPhong. What I do like about surface shaders is we can write our own lighting algorithms too, and we will come to that later.


Shader Variable Declarations


We have a parameter defined at the top, but we then need to create a variable for in inside the CGPROGRAM section, and parameters set that we want to use in the shader need to be duplicated here. We can also declare variables here that are not passed as parameters if we want to too. In this shader we have just the one


		sampler2D _MainTex;

Shader Structures


This is where we define the structures to be used that describe the vertex data we are passing in and the data we are passing to other shaders. In this surface shader we are just getting data for the pixels inside each triangle, like a pixel shader, so Unity will have already ran a vertex shader for us and then it will pass the data we require as laid out in the structures defined here.


Defined here is a structure called Input


		struct Input 
{
float2 uv_MainTex;
};

It is going to pass us the texture coord for the given pixel so we can then use that to get a texel (not pixel) off the texture passed in for the given coordinate.


How on earth does it do that and what is a texel!?!?!?!


OK, this bit is a bit funky :) Remember we set up those texCoords in our earlier runtime quad code


        // Set up text coords
texCoords.Add(new Vector2(0, 1));
texCoords.Add(new Vector2(0, 0));
texCoords.Add(new Vector2(1, 0));
texCoords.Add(new Vector2(1, 1));

We said that the top left corner was 0,0 and the top right was 1,0, well when this information is given to the surface or pixel shader it is interpolated, that is to say, when we get given the pixel(s) between the top left corner and top right corner they will be in the range of 0,0 and 1,0. So if the pixel being sent to the surface shader is slap in the middle and at the very top of the mesh, it would have the uv_MainTex value od .5,0. If it was the pixel in the very centre of our rendered quad then uv_MainTex value would be .5,.5. So by using this mapping we can get the right texel from the texture passed in.


Texel = TEXt ELement, the GPU can’t work on a pixel to pixel mapping, the texture you pass could be 32x32 pixels and the area your mesh covers could be, well, the whole screen or 16x16, so the GPU needs to use the texture coordinates to pull out the colour at that point. To do that on a pixel by pixel basis, just would not work…


Surf


And now, the part you have all been waiting for, the actual shader it’s self…


		void surf (Input IN, inout SurfaceOutput o) 
{
half4 c = tex2D (_MainTex, IN.uv_MainTex);
o.Albedo = c.rgb;
o.Alpha = c.a;
}

This is being call for each and every pixel that your mesh is showing to the camera. The function is being passed the Input structure, as I have explained above this will have the interpolated data for the given pixel with regards to the mesh. There is also an inout parameter, SurfaceOutput o. This structure will be populated by this function then handed onto the rest of the Unity surface pipeline to have the lighting applied to it.


The SurfaceOutput structure is pre defined in Unity and looks like this


struct SurfaceOutput {
half3 Albedo;
half3 Normal;
half3 Emission;
half Specular;
half Gloss;
half Alpha;
};

All that is getting populated here is the Albedo and the Alpha. The Albedo is the colour of the surface to be returned for this particular pixel and the Alpha is the corresponding alpha.


ENDCG


Denotes the end of your shader code


Fallback


This is the default shader to use should this shader be unable to run on the hardware.


Play Time


So, that was a lot of waffle, lets look at altering this shader so we can see how some of it works. First we need to use our new material on our rendered object, now you can use our runtimequad or add a new model to the scene and set it’s material to our new SSOneMaterial.


Once you have assigned the new material, give it a texture.


image


Run this and we can see (or you should) that it runs as it did before with the other shader.


Lets add a new parameter to the shader. In the Properties section add a new property _Tint like this


	Properties 
{
_MainTex ("Base (RGB)", 2D) = "white" {}
_Tint ("Color Tint", Color) = (1,1,1,1)
}

We need to also set up a variable for this, so under sampler2D _MainTex; add a float4 (a colour is a float4)


		sampler2D _MainTex;
float4 _Tint;

We can now use this value to tint the image that we out put like this


		void surf (Input IN, inout SurfaceOutput o) 
{
half4 c = tex2D (_MainTex, IN.uv_MainTex);
o.Albedo = c.rgb * _Tint;
o.Alpha = c.a;
}

Now, go back to Unity, run the scene, select your object, pick the Tint colour picker and you will see the image get tinted at run time, this can be done in the scene screen when not running too.


image


Oh, and just to show you can use these 3D shaders with 2D graphics, here is an image of the sahder being used on both a 3D quad and a sprite at the same time.


image


Naturally, our shader at the moment is not taking into account the alpha for the sprite, but we can sort that out later, for now, just be clear, what ever we render in 3D with shaders we can do in 2D as well, they are the same thing…


As ever comments and critique are more than welcome. The next post we will look at a few more tricks we can do in the surface shader and if I have time take a look at writing out own lighting model for our shader.


<< Previous                                                                                          Next>>

Friday, 13 February 2015

Coming from Shaders in XNA to Shaders in Unity3D


This is the first post in an intended series of tutorials covering shader in Unity3D. Now, I am no expert in this area, this is just my experience of working with shaders in Unity3D. I came to Unity3D shaders pre armed I guess, with knowledge gained from writing DX9 shaders in XNA. I have written a lengthy set of tutorials for that as well as creating my own deferred lighting engine in XNA with a post processing pipeline as well as hardware instanced mesh’s and particle systems, all with accompanying shaders, so as far as the GPU goes I do have some experience and I think a good understanding of HLSL and the graphics pipeline.
So what has got me wanting to write this post, especially as there are loads of tutorials out there on Unity3D shaders as well as the excellent Unity3D Documentation? Well, I remember starting out with shaders in XNA, and, well it’s tough to get the concepts and ideas under your belt at first and from what I have seen (I may not have looked very hard) most of them assume existing knowledge. Also, for a lot of developers all these sources are very 3D driven, and a lot of devs don’t seem to then see that  these shaders can also be used in their 2D projects.
In the past I have heard people say that 3D is much harder than 2D, but what I don’t think a lot of people realize is when you were working in SpriteBatch (XNA) and now Sprites (Unity3D) you are still working in 3D, it’s just that everything is a quad and always facing the camera.
So I am going to start from the very, very beginning. The first thing we will do will be to create a mesh ourselves in code so we can actually understand what gets passed to the shader, we may not even get to look at a shader in this post :S
A friend of mine, Jay from Drop Dead Interactive, sent me a great youtube link to a series of Unity Shader tutorials, you might want to check this out to. I liked it, worth a look if you have time.

The Vertex

Please forgive me if I am teaching you how to suck eggs (showing you something you already know), but if people don’t understand the very root of the pipeline, then it’s easy to get confused. 
 

So what is the Vertex (plural, Vertices)?

OK, the Vertex is a structure that holds information for a given point on a mesh. So at the very least this would be a Vector3 for the point position on the mesh, not in the world, but on the mesh.
For the GPU to draw anything on the screen it needs at least 3 vertices, and to draw a quad (a flat square, billboard or sprite), at least 4 vertices (you could use 6 to draw 3 triangles, with indexing the GPU sort of does this anyway). All meshs are made up of triangles, so you can imagine the more curved your mesh is, the more triangles are needed.
image
Each one of the triangles in the image above is built from 3 vertices.
The Vertex also has other information with it, it also has the direction this point is facing, this is also known as the “Normal”, it will also have texture coordinates (textcoord), that describe how a texture would be applied to it. For now, we will focus on these there elements, position, normal and texcoord. The texcoord are also referred to as UV, I am sure you have heard artists talk about UV mapping in modeling tools and this is the process of setting up the vertices so that the right bits of the textures are mapped to the right parts of the mesh. I am terrible at UV mapping, it’s a real skill and I just don’t have the patients…

Unity is Left Handed – XNA was Right Handed

So, why does this matter? Well, you can get your self in a bit of a pickle if you are not aware of it, and I get in a pickle all the time as I am so use to working right handed. But what does it mean for a graphics system to be left or right handed? Well, it’s about how the coordinate system works, I could describe it here, but found a great link explaining handedness here.

RuntimeQuadScript.cs

To help me show you the sort of data that  gets sent to the shader we are going to create a script that will generate a Quad for us at run time. Now, for those of you that don’t like working in 3D, see this quad as a sprite, not as 3D geometry, the sprites and GUI.Image elements you have been working with, even the 3D text are all quads, so think of this as a sprite, ill even show you how we can use our shaders on sprites and even text in our games.
What do we need then, we need a list of position data, Vector3, 4 in total, an index list used to draw the positions in the correct order (winding order) , 6 in total, a list of Vector2’s for texture coordinates, again 4 in total as well as a list of Vector3’s for the normals, again, 4 in total. We also need a Mesh to put it all in and we can apply a material and so in turn a shader to.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
[ExecuteInEditMode]
public class RuntimeQuadScript : MonoBehaviour 
{
    /// <summary>
    /// List to store all our vertex positions
    /// </summary>
    List<Vector3> positions = new List<Vector3>();

    /// <summary>
    /// List to store the order we want the positions rendered in.
    /// </summary>
    List<int> index = new List<int>();

    /// <summary>
    /// List to hold the text coorinates we want for the mesh.
    /// </summary>
    List<Vector2> texCoords = new List<Vector2>();

    /// <summary>
    /// List to hold the normals we wish to create.
    /// </summary>
    List<Vector3> normals = new List<Vector3>();

    /// <summary>
    /// The mesh that our variables will create.
    /// </summary>
    Mesh thisMesh;

Now we can use these elements create our quad. First thing we will do is initialize our mesh and load up the vertex positions we need.

 // Use this for initialization
    void Start()
    {
        // Initialize the mesh object
        thisMesh = new Mesh();

        // Set up position data.
        positions.Add(new Vector3(-.5f, .5f, 0));           // Top left corner
        positions.Add(new Vector3(-.5f, -.5f, 0));          // Bottom left corner
        positions.Add(new Vector3(.5f, -.5f, 0));           // Bottom right corner
        positions.Add(new Vector3(.5f, .5f, 0));            // Top right corner

We can then set the draw order of these positions with a list of indicies, so each value in this next list corresponds to a Vector3 in out position list, so 0 would be the first Vector3 and 3 would be the last.

        // Set up the draw index
        index.Add(0);           // Draw from top left corner                 
        index.Add(3);           // to bottom left
        index.Add(2);           // then to bottom right

        // Next triangle
        index.Add(2);           // Draw from bottom right
        index.Add(1);           // to top right
        index.Add(0);           // then to top left

We can then give these values to the mesh and set it in the filter like this, remember we are rendering the mesh to face our camera at 0,0,-10.

        // Now give our mesh this data
        thisMesh.vertices = positions.ToArray();
        thisMesh.triangles = index.ToArray();
        
        // Now put this in the mesh filter so the renderer apply a material to it.
        GetComponent<MeshFilter>().sharedMesh = thisMesh;

We can now create an empty game object, rename it RuntimeQuad and add our script to it like this

image

The quad

As we had the required attributes at the top of our class, the MeshFilter and MeshRenderer have been added automatically for us. You will also see that I have set the MeshRenderer to use the Default-Diffuse material, before you do that you will see your quad rendered as a magenta square like this

image

Once you have set the material it will look like this

image

You can see that it’s being shaded in an odd way with that shadow on the bottom, this is because we have not set up the normals, so the default shader does not know which direction the mesh is facing, we can set the normals in a couple of ways, first we will do it by hand

        // Create our own normals
        normals.Add(Vector3.back);
        normals.Add(Vector3.back);
        normals.Add(Vector3.back);
        normals.Add(Vector3.back);
        
        // Now give our mesh this data
        thisMesh.vertices = positions.ToArray();
        thisMesh.triangles = index.ToArray();
        thisMesh.normals = normals.ToArray();

So I am setting the normals to Vector3.back, so they will be 0,0,-1 , so pointing in the direction of the camera, the quad now renders like this

image

Unity3D’s Mesh has a lovely intrinsic method called RecalculateNormals, so, we can do away with the normals list, but I had it in here just to illustrate how they look and what they are referring to.

We can do that like this

        // Now give our mesh this data
        thisMesh.vertices = positions.ToArray();
        thisMesh.triangles = index.ToArray();
        //thisMesh.normals = normals.ToArray();

        // Thankfully, Unity provides a method to calculate the normals of the mesh
        thisMesh.RecalculateNormals();

        // Now put this in the mesh filter so the renderer apply a material to it.
        GetComponent<MeshFilter>().sharedMesh = thisMesh;

OK, so lets now set up a new material, call it IntrinsicDiffuse, as we are going to use the Diffuse shader provided by Unity like this

image

So, now we can set MeshRenderer to the new material, change the color, say to red and it will render red, thanks to the material.

image

But, what happens if we pass it a texture?

Lets give it my handsome face to render

image

As you can see, it’s not rendered it right, it’s because we have not set the texture coordinates, so before we can set them we sort of need to know how they work, how does the texture coordinate relate to the texture that gets passed in.

The texture coordinate system is a Vector2, the top left corner of the image is 0,0, the bottom right is 1,1, making the top right 1,0 and the bottom left 0,1 ergo, the centre of the texture would be .5f,.5f

BUT Unity pulls a few tricks, as you can read here depending on what framework it is using for the render, the above applies to Direct3D, so keep in mind that this can get flipped..

I think due to the  way the default shader is working, it’s using OpenGL as it’s flipping the texture ccords, so with the texture coordinates set the class looks like this

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

[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
[ExecuteInEditMode]
public class RuntimeQuadScript : MonoBehaviour 
{
    /// <summary>
    /// List to store all our vertex positions
    /// </summary>
    List<Vector3> positions = new List<Vector3>();

    /// <summary>
    /// List to store the order we want the positions rendered in.
    /// </summary>
    List<int> index = new List<int>();

    /// <summary>
    /// List to hold the text coorinates we want for the mesh.
    /// </summary>
    List<Vector2> texCoords = new List<Vector2>();

    /// <summary>
    /// List to hold the normals we wish to create.
    /// </summary>
    List<Vector3> normals = new List<Vector3>();

    /// <summary>
    /// The mesh that our variables will create.
    /// </summary>
    Mesh thisMesh;

 // Use this for initialization
    void Start()
    {
        // Initialize the mesh object
        thisMesh = new Mesh();

        // Set up position data.
        positions.Add(new Vector3(-.5f, .5f, 0));           // Top left corner
        positions.Add(new Vector3(-.5f, -.5f, 0));          // Bottom left corner
        positions.Add(new Vector3(.5f, -.5f, 0));           // Bottom right corner
        positions.Add(new Vector3(.5f, .5f, 0));            // Top right corner

        // Set up the draw index
        index.Add(0);           // Draw from top left corner                 
        index.Add(3);           // to bottom left
        index.Add(2);           // then to bottom right

        // Next triangle
        index.Add(2);           // Draw from bottom right
        index.Add(1);           // to top right
        index.Add(0);           // then to top left

        // Set up text coords
        texCoords.Add(new Vector2(0, 1));
        texCoords.Add(new Vector2(0, 0));
        texCoords.Add(new Vector2(1, 0));
        texCoords.Add(new Vector2(1, 1));

        // Create our own normals
        normals.Add(Vector3.back);
        normals.Add(Vector3.back);
        normals.Add(Vector3.back);
        normals.Add(Vector3.back);
        
        // Now give our mesh this data
        thisMesh.vertices = positions.ToArray();
        thisMesh.triangles = index.ToArray();
        thisMesh.uv = texCoords.ToArray();
        //thisMesh.normals = normals.ToArray();

        // Thankfully, Unity provides a method to calculate the normals of the mesh
        thisMesh.RecalculateNormals();

        // Now put this in the mesh filter so the renderer apply a material to it.
        GetComponent<MeshFilter>().sharedMesh = thisMesh;
    }
 
 // Update is called once per frame
 void Update () 
    {
 
 }
}

And it now renders like this

image

I know, I know, you are wondering when we are going to start looking at actually writing a shader, and we will, but first, PLEASE spend some time to understand the values used to create the mesh we just created. Have a play around with the values, set one of the textcoords to .5f,.5f or one of the vertex positions to 1,2,0 or go back to manual normals and set one to Vector3.forward, so you have a clear idea of what all these elements are doing, because if you don’t get these fundamentals clear in your mind, shaders are going to cause you nothing but pain.

As ever if you spot anything in my post(s) that is incorrect or misleading, then please let me know, just post a comment bellow and Ill sort it out, same with any questions you might have, feel free to fire off a comment below.

In the next post we are going to look at creating our first shader, honest :P








Sunday, 8 February 2015

A Inventory System for Unity

So, ages a go, well before Xmas I think (2014) I spotted a fellow indie developer, and now MS Evangelist Dave Voyles post about an Inventory system he had written for a SMUP he was working on, and thought I would have a go at creating an Inventory  system in Unity of my own. By the time I got around to doing this Unity 4.6 was released, so all the code snippets are from that version of Unity, so it’s using the new Unity GUI, which I have to say is a huge improvement.

So, the first thing I did was write a simple shooter, so, you have a ship and some asteroids, so we can get damaged by hitting asteroids, destroying asteroids yields gold and silver coins, both of which you can collect. So, we need to pick up coins, first aid kits, and ammo, and that’s where the inventory system comes in.

image

As you can see in the screen shot, we are storing the inventory items along the bottom of the screen. So, what do these inventory items look like in code?

First thing we need to do is set up some rules, a way to define the different types of items so we know what to do with them, we can also then bunch like types together in the system. I have done this with an Enum

InventoryItemTypesEnum

public enum InventoryItemTypesEnum : int
{
DeadSpace = 0,
Bullet,
MissileSeeker,
GoldCoins,
SilverCoins,
MediPack,
}





In this Enum we have DeadSpace, not used, but wanted to have something like this in case I need to hold blank spaces. The other types are pretty self descriptive I think.


InventoryItemScript


Using the above Enum I can now create a script that can be used to create each and every inventory item. Using this script I can then create prefabs for each of the different types and have them used in both the game and the inventory system.


using UnityEngine;
using System.Collections;

public class InventoryItemScript : MonoBehaviour
{
public string ItemName;
public int Quantity = 0;
public InventoryItemTypesEnum InventoryItemType = InventoryItemTypesEnum.DeadSpace;

public int ScoreModifier = 0;

// Use this for initialization
void Start ()
{

}

// Update is called once per frame
void Update ()
{

}

void OnTriggerEnter2D(Collider2D collider)
{
if (collider.gameObject.tag == "Player")
{
// Add it to the Inventory..
InventoryScript Inventory = collider.gameObject.GetComponent<InventoryScript>();
collider.gameObject.GetComponent<ShipScript>().Score += ScoreModifier;
Inventory.AddItemToInventory(this);

Destroy(gameObject);
}
}
}

In here we have the name of the item, a quantity for it and it’s type dictated by the Enum, set initially to DeadSpace as well as if the item has a score modifier, again you could add other properties in here that are pertinent to you game.


I am using a trigger because I don’t want the collection of the object to impact the craft, when the “Player” collides with the inventory item we get the InventoryScript, this script has the actual inventory system in it, we apply the score modifier and then add this item to the inventory system before we then destroy it.


We can now create prefabs for each of the inventory types:-


Bullet


image


MissileSeeker


image


MediPack


image


GoldCoins


image


SilverCoins


image


InventoryScript


Here is where all the magic happens :) First thing I do is set up three public GameObjects. InventoryItem is the part of the HUD that will be used to display the inventory items in, a UI.Image


image


The InventoryItemPrefab is a prefab used to instance images in the InventoryItem GamObject


image


 


We then have the Selector GameObject, again this is an object in the HUD and I use that to indicate which inventory is currently selected.


image


We then have a Dictionary of InventoryItemScript with a string key for the name of the item that is stored in this location of the inventory. There is also a list of GameObjects called ItemUI, these are used to render the representation of the inventory item in the HUD and given the relative name for the inventory item.


We then have a variable for the spacer, for padding the UI, a count for the number of items types in our system, and finally a variable to store the index of the current selected item in the system.


    public GameObject InventoryDisplay;
public GameObject InventoryItemPrefab;
public GameObject Selector;

Dictionary<string,InventoryItemScript> Items = new Dictionary<string,InventoryItemScript>();

List<GameObject> ItemUI = new List<GameObject>();

float spacer = 16;

int ItemTypesCount = 0;

int SelectedIndex = -1;










Lets start with the method that adds items to the inventory system, the same method we saw earlier in the InventoryItemScript, AddItemToInventory


public void AddItemToInventory(InventoryItemScript item)


    public void AddItemToInventory(InventoryItemScript item)
{
if (!Items.ContainsKey(item.ItemName))
{
Items.Add(item.ItemName, item);
GameObject ii = (GameObject)Instantiate(InventoryItemPrefab);

ii.name = item.ItemName;
ii.transform.parent = InventoryDisplay.transform;

SetUIItemText(item, ii);

ii.GetComponent<Image>().sprite = item.GetComponent<SpriteRenderer>().sprite;

RectTransform srt = InventoryItemPrefab.GetComponent<RectTransform>();
RectTransform trt = ii.GetComponent<RectTransform>();

int x = (int)(srt.anchoredPosition.x + ((srt.sizeDelta.x + spacer) * ItemTypesCount));
trt.anchoredPosition = new Vector2(x, srt.anchoredPosition.y);

ItemTypesCount = Items.Keys.Count;
ItemUI.Add(ii);
}
else
{
Items[item.ItemName].Quantity += item.Quantity;

GameObject ii = ItemUI.SingleOrDefault(uii => uii.name == item.ItemName);

if (ii != null)
SetUIItemText(Items[item.ItemName], ii);
}

}

The parameter for this method is the InventoryItemScript item to add to the system. First thing we do is check if we already have an item of this type, if we do, we simply find it in the system and increment it’s quantity, then update the UI text for this item. If we don’t then we add it to our Dictionary then create it’s UI counterpart to go in the list by instancing a new InventoryItemPrefab, we set it’s name, make it a child of InventoryDisplay, set it’s text value, then pull out the sprite so we can then position it in the UI correctly then add it to out ItemsUI list.


void Update()


Using the left and right arrow keys, the user can select the inventory item they want to use, and by pressing Enter, use it. This is all managed in Update, in here we also manage the SeelctedItemIndex. The Selector is rendered by getting the RectTransfer of the item we want it to appear over and setting it’s anchor position to the RectTransform anchor position. I did this with a new Vector2, but this should be a regular one for one swap.


    void Update()
{
if (ItemTypesCount == 0)
Selector.SetActive(false);
else
{
if(!Selector.activeInHierarchy)
{
SelectedIndex = 0;
Selector.SetActive(true);
}

if (Input.GetKeyDown(KeyCode.RightArrow))
{
SelectedIndex++;
if (SelectedIndex > ItemUI.Count - 1)
SelectedIndex = 0;
}

if (Input.GetKeyDown(KeyCode.LeftArrow))
{
SelectedIndex--;
if (SelectedIndex < 0)
SelectedIndex = ItemUI.Count - 1;
}

RectTransform trt = ItemUI[SelectedIndex].GetComponent<RectTransform>();
Selector.GetComponent<RectTransform>().anchoredPosition = new Vector2(trt.anchoredPosition.x, trt.anchoredPosition.y);

if (Input.GetKeyDown(KeyCode.Return))
UseItem(Items[ItemUI[SelectedIndex].name]);
}
}

public void UseItem(InventoryItemScript item)


When the player hits Enter, they then “Use” the selected item. This method is a simple switch statement, in here put what ever you want your items to to to or for the player, in this sample  I am only doing this for MediPack types, and increasing the players health. This in turn calls RemoveItemFromInventory.


    public void UseItem(InventoryItemScript item)
{
switch (item.InventoryItemType)
{
case InventoryItemTypesEnum.MediPack:
GetComponent<ShipScript>().Health += .1f;

RemoveItemFromInventory(item.ItemName, 1);
break;
default:
break;
}

if (SelectedIndex > ItemUI.Count - 1)
SelectedIndex = ItemUI.Count - 1;
}

public void RemoveItemFromInventory(string ItemName, int qty)


This will only actually remove an item from the system if it’s quantity is less than or equal to zero, otherwise it just subtracts the given quantity from the inventory items quantity and update the UI text for it. If it removed the item from the system it has to then shuffle all the other items in the UI back so there is no gap.




    public void RemoveItemFromInventory(string ItemName, int qty)
{
if (Items.ContainsKey(ItemName))
{
Items[ItemName].Quantity -= qty;

GameObject ii = ItemUI.SingleOrDefault(uii => uii.name == ItemName);

if (Items[ItemName].Quantity <= 0)
{
RectTransform srt = ii.GetComponent<RectTransform>();
// Move them all back one from this one on..
foreach (GameObject goi in ItemUI)
{
RectTransform trt = goi.GetComponent<RectTransform>();
if (trt.anchoredPosition.x > srt.anchoredPosition.x)
trt.anchoredPosition = new Vector2(trt.anchoredPosition.x - (srt.sizeDelta.x + spacer), trt.anchoredPosition.y);
}

ItemUI.Remove(ii);
Destroy(ii);
Items.Remove(ItemName);
ItemTypesCount = Items.Keys.Count;


}
else
SetUIItemText(Items[ItemName], ii);
}
}

And well, that’s about it, quite simple really, and I hope you can see how easy it is to extend :)


If you want to play with the whole project, then the lovely Dave Voyles as it on his sky drive. If however you find this link is broken, then please let me know and I can host the code from my server. Grab a copy here :)


As ever, if you have any questions or suggestions on this post, or any of my posts, please feel free to post here and let me know what you think.

Friday, 12 December 2014

Object Pooling–Unity3D

I know, I know, there are already lots of solutions out there for this in Unity3D, and you have probably already got your own mechanism in place to handle this, but I thought I would post how I have object pooling in my current game project.
Ill start with an apology, I have anew laptop, have not blogged in a while and don’t seem to be able to find the Windows Live Plugin I use to use for pasting code from Visual Studio.
So, what is object pooling, well the usual application of this is for things like bullets, I am also using it for bombs, missiles as well as blast fragments.
As you can imagine you could end up having to create a lot of these sorts of items on the fly using the Unity3D Intrinsic “Instantiate” which will create a totally new object when called. So, a way around this is to have a group of pre instantiated objects, a pool of objects :)

Object Pooler

Lest look at my pool class, we will start with the variables we are going to use. It’s derived from MonoBehavior so we can attach it to an empty game object in the editor.
    public int StartingPoolSize = 25;

    public GameObject ObjectType;

    List<GameObject> Queue = new List<GameObject>();
    List<GameObject> Live = new List<GameObject>();

    public int TotalObjects = 0;
    public int QueuedObjects = 0;
    public int LiveObjects = 0;

So, we have a starting pool size, I have a default of 25 for this, but in the editor you can set this to be what ever you like.

We then have an ObjectType, this is the GameObject that is going to be pooled.

I then have two lists, one is the list of items that are not yet in use, the Queue list and a list of those in use, the Live list.

I then have a few counters, these are just so I can see what’s going on while I am debugging the pool.




void Start()


Now, the Start method looks like this:

    void Start()
    {
        for (int o = 0; o < StartingPoolSize; o++)
            AddObject();
    }

So, all we are doing here is initializing the Queue list to the size of our default Queue size, so lets look at what the AddObject method is doing.




void AddObject()


    public void AddObject()
    {
        Queue.Add((GameObject)Instantiate(ObjectType));
        Queue[Queue.Count - 1].transform.parent = transform;
        Queue[Queue.Count - 1].gameObject.SetActive(false);
        TotalObjects++;
    }

All that this method is doing is instantiating an object and adding it to the Queue list, for now making it a child of this game object, and ensuring it is not active. I then increment the total objects count.




GameObject InstanciateObject()


So, now we need a method to get a new object from the Queue and put it in the game world, this is where this method comes in.

    public GameObject InstanciateObject()
    {
        if (Queue.Count == 0)
        {
            // Create 3 more...
            for (int i = 0; i < 3; i++)
                AddObject();
        }

        AddLive(Queue[Queue.Count - 1]);

        Queue.RemoveAt(Queue.Count - 1);

        return Live[Live.Count - 1];
    }

The first thing I do is see if there are any object left in the Queue list, the list is reduced each time we take an object and put it in the game world, so if they are all used, we need to pad the list out a little, so if it is empty I create another 3 objects. I guess I could add another public property for growth, so rather than a hard coded 3 the list will grow by this property as it’s set in the editor.

I then call my AddLive method, this moved the object over to the Live list, makes sure it’s ready for the world and then is activated. I then remove this object from the Queue and return the new live object.




void AddLive(GameObject o)


    void AddLive(GameObject o)
    {
        Live.Add(o);

        if (Live[Live.Count - 1].GetComponent<GameObjectDeath>() != null)
        {
            Live[Live.Count - 1].GetComponent<GameObjectDeath>().ReSet();
            Live[Live.Count - 1].GetComponent<GameObjectDeath>().IsPooled = true;
        }        

        Live[Live.Count - 1].gameObject.SetActive(true);
    }

As you can see, it adds the object to the Live list, then there is a bit of code that makes sure that if this object is being used for the nth time, by that I mean, it’s not the first time it’s been used, that I reset my object. I have a GameObjectDeath script, this script will “Destroy” an object if it collides with another object, or it can be given a life span, this bit of code just makes sure that this gets set.

Finally it makes the object active.




void DestroyObject(GameObject o)


    public void DestroyObject(GameObject o)
    {
        o.SetActive(false);
        Queue.Add(o);
        Live.Remove(o);
    }

And so, when an object  is destroyed, rather than calling the intrinsic Unity3D method, we use this method. It deactivates the object and moves it from the Live list back into the Queue.

To use this now, we can create an empty game object in the editor and attach the script, we can then set these variables in the editor like this:

image

As you can see this pool is managing bullets. The bullet object is a prefabricated game object I have already created.








OK, so now we can pool an object, but wouldn't it be great if we could do this for lots of types of object?




ObjectPoolManager


And that’s where this bit of code comes in :D

All we need in here are two variables

    public static ObjectPoolManager thisObjectPoolManager;

    List<ObjectPooler> pools;

I have a static so I can get at the class and it’s methods from any other script and a list of ObjectPoller objects. These will be child game objects held in this game object.




void Start()


 void Start () 
    {
        thisObjectPoolManager = this;

        pools = GetComponentsInChildren<ObjectPooler>().ToList();
    }


In the Start method we set the static to this, then get all the child ObjectPooler game objects.




GameObject InstanciateObject(GameObject gameObj)


    public GameObject InstanciateObject(GameObject gameObj)
    {
        ObjectPooler pl = pools.First(p => p.ObjectType.name == gameObj.name);
        if (pl != null)
            return pl.InstanciateObject();
        else
        {
            print("Can't find pool for " + gameObj.name);
            return null;
        }        
    }

So, now when another script want’s to instantiate a new game object, it will call the manager, the manger in turn then gets the pool related to the object they want to instantiate, by comparing the pool’s ObjectType.name property with the name property of the object to be instantiated, if found it then calls the pools InstanciateObject method and returns the world ready object to the caller.

If it can’t find it (and this will be because you have not set up a pool for the required object) then it will return null.




GameObject InstanciateObject(GameObject gameObj, Vector3 Position, Quaternion rotation)


Sometimes you want p instantiate an object at a position, with a rotation, and this overloaded method will do just that.

    public GameObject InstanciateObject(GameObject gameObj, Vector3 Position, Quaternion rotation)
    {
        GameObject go = InstanciateObject(gameObj);
        go.transform.position = Position;
        go.transform.rotation = rotation;

        return go;
    }





void DestroyObject(GameObject gameObj)


    public void DestroyObject(GameObject gameObj)
    {
        pools.First(p => p.ObjectType.name+"(Clone)" == gameObj.name).DestroyObject(gameObj);
    }

Again, when we want to destroy an object, we call this method, like the InstanciateObject method(s) it finds the required pool, this time it post fixes the ObjectType.name property with “(Clone)” as when you instance an object it has this at the end. I guess you could replace this with a Contains, rather than getting an exact match. Upon finding it, it calls the pool sDestroyObject method passing in the object to be destroyed.





So, in the editor, you can create an empty game object add the ObjectPoolManager script to it, then put all your pool game objects in it like this.

image

Well, that’s my current approach to object pooling, and for the limited way I am using it it’s working out quite well. If you have any questions or suggestions, then please feel free to post here.

I am also a member of the Unity Indie Devs on Facebook, if you are not already a member, join up, join the chatter :)

Thursday, 19 June 2014

Ball Shooter Script–Unity3D

This blog is becoming more and more Unity3D focused, the XB1 program is so quiet I have not had anything to post about, maybe I should just recycle the ID game releases that are happening….
So, was catching up with events on FaceBook and I spotted a post in a group that I am an admin for, asking if anyone knew how to script shooting a ball, as the code they had written was not working as they expected. So, being the kind of person that likes to help people out, I wrote this.
using UnityEngine;
using System.Collections;

public class BallShooter : MonoBehaviour
{

    bool mousehold = false;
    bool shoot = false;

    public float PowerBuild = .1f;

    public float MaxVelocity = 2;

    public float power = 0;

    public GameObject ball;
   
    // Update is called once per frame
    void Update ()
    {
        // Player has clicked the left mouse button...
        if (Input.GetMouseButtonDown(0))
        {
            mousehold = true;
            shoot = false;           
        }

        // Player has released the left mouse button..
        if (Input.GetMouseButtonUp(0))
        {
            if (mousehold)
                shoot = true;

            mousehold = false;
        }

        // While the player has the left mouse button pressed power up the shot..
        if (mousehold && power < 1)
        {
            power += PowerBuild;
            if (power > 1)
                power = 1;
        }

        // Shoot the ball!!!
        if (shoot)
        {
            shoot = false;
           
            // Get mouse pos in the view.
            Vector3 mp = Camera.main.ScreenToViewportPoint(Input.mousePosition);

            // (.5,.5) is center, so we can elevate and pan the shot angle based on this while creating the velocity.
            Vector3 velocity = new Vector3(MaxVelocity * (mp.x - .5f), MaxVelocity * (mp.y - .5f), MaxVelocity * power);

            // Create the ball.
            GameObject shot = (GameObject)Instantiate(ball, Camera.main.transform.position + Vector3.forward, Quaternion.identity);

            // Give it some velocity.
            shot.rigidbody.velocity = velocity;

            // Reset the power ready for the next shot.
            power = 0;
        }
    }
}
As you can see, it’s a pretty simple script, check if the player has the left mouse button pressed, if they do then set the hold and shoot variables, if the player releases the left mouse button, then set the shoot flag and un set the mouse hold flag.
While the left mouse button is down, build up power for the shot. Once released, set the shoot flag.
If the shoot flag is set, calculate the velocity, create an instance of the ball and apply the velocity to it, and that’s about it…
QuickPic
If you want to get the whole unity scene, then you can download it off my server here.