Customizable Navigation Bar

Saturday, December 28, 2013

Back To Basics: Welcome To Unity

Hey everyone, a little late, but better late than never. I'm starting with the video tutorials again, and I am starting with the very basics of Unity.

In this video I go over what each of the default windows does and how to use them.


Friday, December 13, 2013

Recommended Tools: Sfxr and Bfxr Sound Generators

While developing I like to create small temporary sound effects and implement them in code, this way all I need to do is replace the asset with the real sound effect, and I don't have to change my code at a later date. This saves me time, and also allows me to see where sound effects are needed very early on so I can add them to the asset list. Coming up with these sound effects can be somewhat of a pain if you don't know where to start. Do you find free sound effects on the internet? Do you find a sound effect generator? Do you make fart noises with your mouth?

I ended up going with the sound effect generator method (though making fart noises was a close second), and came across two programs that were closely related to each other. Sfxr, and Bfxr. Both of these programs are really good for creating short random tempory audio files, or creating 8 bit and 16 bit audio files for your games requiring that retro feel.

I came across Sfxr a few years ago while I was in school. It is actually what I used for the sound effects in my old tutorials on how to create a game in Unity. Sfxr is a free tool created by someone who goes by DrPetter, and it was created back in 2007 for the Ludum Dare challenge so people could create basic sound effects for the games they needed to complete in 48 hours. Sfxr has it's source code available for anyone to fiddle with, and you can use any sound effects you make completely free.

The interface is very basic looking, but if you are creating basic sound effects you don't need anything flashy. Here is an example of what the program looks like:


If you are looking for something extremely basic, Sfxr is the way to go. You can grab it here: http://www.drpetter.se/project_sfxr.html

Bfxr is something I just came across recently while doing my usual random internet searches. It is an extremely heavily modified version of Sfxr. It added a number of new options and values to tweak, which for some may be too much to handle at first glance. In addition Bfxr saves old mixes and sounds in a list for you to reference at any point which is a huge improvement over Sfxr, which requires you to save it to the disc if you ever want to load up the sound again. Bfxr is great if you want to have more variety and more control than what Sfxr gives you, and you aren't afraid of an interface with a large number of sliders and buttons. Here is what the interface looks like.


Bfxr is also free to use and it's source code is also hosted on GitHub so anyone can make a pull request and fiddle around with it. You can grab it here: http://www.bfxr.net/

So whether you are looking for placeholders or are looking for some retro sounding effects, either of these tools will be very useful to you. Both offer a ton of options and are free to use. Anyways, I'm off for now, and if you know anyone that is looking for sound generators, you know where to point them.

Friday, December 6, 2013

Masking In Unity

While working on a GUI system for Unity, one of the issues I came across was how to mask objects on the screen. Unity didn't have a default way of handling this, so after looking around I came across something called a "Depth Mask" shader.

Basically this depth mask works by just hiding everything behind it, so while it works great, there are still a few small issues with it. By hiding everything behind it, you need to fiddle around with render queues or different camera set ups if you only want it to use it on certain objects.

The shader for the depth mask is really really simple:

Shader "Depth Mask" {
    SubShader {
//This Queue call tells the graphics card that this should be drawn before any of the geometry. This is what give the shader its ability. It gets drawn before anything else and any thing drawn behind it gets clipped
        Tags {"Queue" = "Geometry-10" }    
        Lighting Off
        ZTest LEqual
        ZWrite On
        ColorMask 0
        Pass {}
    }
}

The easiest way to stop objects from being masked by the shader is to manipulate the render queue of the material. If you set the render queue to a lower value than the depth mask, it will show up as if the mask wasn't there at all. This allows you to have full control over which objects are masked and which aren't.

Here is an example of the depth mask at work. You can see the two construction workers getting clipped away by this depth mask shader. The construction worker in the back has a special shader that has a lower render queue than the depth mask, so it is completely unaffected by it.



























Hopefully you guys found this tutorial useful. If you want to fiddle around with the project viewed above you can find it here: https://db.tt/OcviQM5n

Friday, November 29, 2013

Micro Transactions And Our Approval Of Inadequacy



I've been a gamer for most of my life. As a matter of fact I have a picture of myself in diapers playing Duck Hunt on the NES, so I could possibly even say my whole life. As I have aged, I have seen the gaming industry go through a number of transitions, not just with platforms, visual styles, or mechanically, but also with monetization techniques.

When I first started playing video games, what you paid for was what you got. You would go out to a retail outlet, grab a cartridge or a disc, pay up front, and you got (in most cases), a complete experience. At this point in time it was extremely difficult to update games, and it was extremely difficult to to add additional content. These are the NES, PlayStation 1 days, where you couldn't update console games at all, and when everyone and their grandmas were on AOL dial up internet, where PC patches could be a few megabytes at most in size( I almost miss the sound dial up internet used to make, but then I hear dub-step and I am instantly reminded of the horrors). Now don't get me wrong, there were plenty of games up to this point that lacked overall quality and polish (E.T. I'm looking at you), but at the time, nostalgia glasses or not, the games we considered great, were in fact, great games. You paid for an experience and you received a complete one, and I miss that.

As I got older I got into PC gaming, and started noticing that expansion packs were becoming more and more common. For me this was great in the beginning. I could get additional content for a game I loved for a small price. The great thing about these expansions is that they added entire campaigns or characters onto what we originally considered complete, and we went out and bought them because we wanted even more. As I started moving away from PC gaming though, I started to notice that expansions were becoming more of a cash grab than an addition to the game. I think we all know a few games that tried to cash in on expansions *cough* The Sims *cough*.

Moving back into console gaming, the first time we saw DLC was with the Sega Dreamcast (GameLine and Sega Channel offered downloadable games before, but these were complete titles not additions). Even though slow internet and memory limits kept it from catching on, the concept was still a huge advancement in the industry. The Xbox then brought DLC back into the spotlight when titles like Halo 2 or Splinter Cell offered additional content. This DLC was usually free, which I've gotta say, wasn't too shabby at all.

When the next generation of consoles were released, we saw that DLC was going to become a much more prominent focus for developers. Free DLC became much less common, and what was free turned into small things such as a skin for a character, or a mediocre weapon in a game.

Now I am just going to say this right now, I do not have a problem with paid DLC. It has it's purpose, just like the expansion packs did for PC games. It costs money to develop these things, and game development is a business, so you have to make a profit to be successful. The problem I started to have with DLC wasn't the DLC itself or its price tag, it was a pattern I was starting to see with developers. Eventually we started to see something known as "Day One" DLC, or content that you could purchase as soon as you got home. A lot of people hated this. They assumed that if a story arch or content was available for download it meant that they cut it out on purpose, and they were scamming the people purchasing the game. Now in some cases, this could have been true, but most consumers don't understand the timelines of development, or the fact that post-production can take up the 3 months for AAA games. This chart I found actually sums up everything nicely.



Now I personally didn't have an issue with the concept of day one DLC. What my main problem was when you just paid $60 dollars at a retail outlet for a game, this day one DLC was already on the disc, and you were required to pay extra for a downloadable key that would unlock it. At this point it no longer felt like we were getting a complete game. We were now paying for part of a game, and were getting nickel and dimed for a few small portions of what was already there. While this was happening, we also started seeing DLC that would drastically improve your characters in things like sports games. You could pay to take out some of the grind and level up your characters stats on your NHL or NFL teams. These gave you a completely different feeling. You knew that the developers intended on making the game into a grind fest, and were wanting to grab extra cash for you to enjoy yourself.

Now we start to get into the time frame where I personally started developing games. The mobile market was taking off, Facebook games were extremely popular, it seemed like a good time to get into it.

Here was the issue:

Games had changed.

The entire structure of Facebook games was completely different than what we had before, and it was starting to become prevalent in the mobile industry as well. Free-To-Play? Micro transactions? These games were now about giving the user 5-10 minutes of playing time at once, and asking for money to progress. The only thought going into these games was how to make the most money, and hide it behind what was basically an excuse for what we used to consider a game. And do you know what the worst part about it is? It works. Developers shifted their focus to a casual audience with a short attention span and plenty of breathing room on their credit cards. With the free-to-play model, there is no pay-wall. Anyone can download it, get hooked, and toss 10 bucks into a game that they will play for an hour, and they don't even think about it.

As time progressed, more and more free-to-play games were released, and they became more frank with how they approached making people pay. Pay-to-win was becoming the norm, and the only real creativity gamers were seeing were the new ways they would attract people to buy into things. The only thing that I can say that I was fine with was the introductory price. These games are free, so of course, there has to be some sort of way to make money within the game.

Micro transactions are becoming a thing, and not just for free to play games. Dead Space 3 had micro transactions, Black Ops 2 for the Xbox 360 started with basic micro transactions, and judging by E3 this year, you are going to be seeing them a lot more. It is no longer going to be free to play, pay to win for some of the games being released, we are going to be paying 60 dollars at retail, and we will be bombarded with micro transactions. Ryse, Crimson Dragon, and Grand Turismo 6 are just a few of the games that are going to be featuring micro transactions in the future. We are no longer paying for additional content. The only thing that we are going to be getting is the opportunity to tinker with things like in game currency and experience earning rates, and unlock content that is already there.

Now some people may enjoy micro transactions, and for them, that is great, but this is becoming a black hole that is sucking up the experience that we used to have with games. The only thing buying into these micro transactions does is show the developers that we are perfectly fine with inadequacy. If you are like me, and you want this to stop, we need to stop paying into it. The only thing buying games that support this type of economic model does is show the developers that this is what we want, and they will continue to do so.

Also before you guys give me a list of the games you think are super sweet and go against what I have just said, yes there are games that don't follow this model, and still give us all hope for the industry. Skyrim, Borderlands etc. I know. I am just pointing out a pattern that I am seeing, and it is becoming more and more common as time passed by.

Anyways that's my rant. Hopefully it was enjoyable, or at least made you guys think a little bit about it.

Friday, November 22, 2013

New Video With Protobuf Tutorial

Hey guys, the other day I decided to do a video tutorial to go alongside the ProtoBuf tutorial I made a few weeks ago. You can check it out at in the original blog post, or you can check it out right here.

Friday, November 8, 2013

Recommended Tools: Lightmapping Extended In Unity

When developing, I like to have the ability to tinker with and manipulate every single property of an object. It doesn't matter if I am changing something about a cube or if I am fiddling with light map settings, if I want to fiddle, I like to have the ability to.

While I was working on CuBlitz, I found that the default light mapping settings just didn't have enough there for me. They were great for getting really quick test results, but when I wanted to finalize everything and tinker with settings, there just wasn't anything there for me. Unity did let you export an XML file that the Beast light mapper would look at, but that seemed like a slightly archaic way to do things. I felt like there could have been a better way to approach it than manually edit an XML file.

While browsing the net, looking for better ways to do things, and what everything in the XML file meant, I came across a tool called Lightmapping Extended. This completely free tool created an editor that made tinkering with the beast settings extremely easy, and it even exposed some settings that were not documented by Unity.

One thing to keep in mind is that some of these settings require Unity Pro, such as the global illumination settings, so if you are using Unity Free, this may help with some settings, but not everything will be usable for you.

Lightmapping Extended made changing basic Beast settings and baking extremely convenient, and some of the previously unexposed settings are really nice to have.


The settings window of Lightmapping extended brings up a ton of additional settings for the general usage of Beast, like how to handle shadows, geometry, anti-aliasing, and it even gives you the option to leave a thread open so beast doesn't take all of your system's resources baking a light map. This was actually a problem I had while working with the default light mapper. The low powered laptop I was using to bake lights was also the same low powered laptop I was using to develop in Unity, and when I was baking lights it made my computer so unusable that I just had to sit and wait for 2 hours until the light maps were done baking.


Lightmapping Extended also brings up a bunch of settings for global illumination and how light bounces. In this window you also find a previously unexposed setting to use the Monte Carlo algorithm for light mapping. The Monte Carlo algorithm is much slower, but it is also the most accurate.

Here are examples of a scene using the different algorithms that are exposed with Lightmapping Extended
This uses the default algorithm called FinalGather
This image shows a mixture of the FinalGather algorithm and the PathTracer algorithm. Using similar settings as the first image we see that the light is much brighter, adn the light spread is a little bit difference
Here is the Monte Carlo algorithm. It provides a nice balance between the two previous images, and the light spreadis much more realistic

The last image is for environmental lighting. This contains settings for adding a skylight for softer lighting throughout the scene, but it also gives you an option for something known as Image Based Lighting (IBL). With IBL if you have a cube map texture (Example Here) that is an EXR or HDR format you can use it to bake lights as if the scene was in that environment. So you can create a cube map of the sky and everything else at a sunset, and instead of fiddling around with environment lights, you can pass the cube map into Lightmapping Extended and bake the image lighting into the scene. 


I highly recommend grabbing Lightmapping Extended from the Asset Store, and if you are worried about having to pay for a tool like this, worry no more, because it is absolutely free. 

Anyways that is all for this week, I hope you guys enjoyed the post, and give the tool a shot, it is extremely useful.

Friday, November 1, 2013

Using Handles In The Unity Editor

The Handles class in Unity is extremely useful when it comes to custom editor functionality. Just by default they are used to move, rotate and scale object within the scene, and with enough creativity they can be used to manipulate object in a large variety of ways. In the documentation it says that Handles are for custom 3D GUI controls and drawing within the scene view, but it fails to mention that it can be used in editor scripts as well within the OnGUI commands.

This tutorial isn't going to go in depth with what handles are, or what they can be used for, but instead will show you how experimenting with different parts of an engine can get you unexpected yet useful results.

What we are going to create is a simple editor window that takes a mesh filter, and displays all of the information about the mesh, as well as draw all of the UVs for it using the Handles class.

So what we want to do is create a new C# class called ViewMeshUVInfo and place it in your Editor folder within your project. 

using UnityEngine;
using UnityEditor;
using System.Collections;

//This is going to be an EditorWindow so we need to make sure that we extend from the EditorWindow class
public class ViewMeshUVInfo :  EditorWindow
{
//We are going to be getting all of the displayed data from a MeshFilter, so lets store it here
  private MeshFilter m_viewedMesh;
//We also want the window to be scrollable is there is a lot of data that is being displayed
  private Vector2 m_scrollPosition;
  //Since we are displaying mesh data, we can also show the last triangle that the user clicked on, that way we can show them the vertex indices if they need them, so we would store the displayed string here
private string lastSelectedTri = "";
//We also want to limit the maximum size of the handles being drawn, so we will store a float here for the maximum size and then set that value when the window is initialized
private static float m_maxHandlesSize;
//The UVs will also be drawn to the right of the data being displayed, so we need to have a base offset in the X direction
  private static float m_handlesXOffset;

//Lastly since we are displaying all of the mesh data, lets store it in a string here
  string meshInfoString = "";

//To access this lets create a function called Init() and give it a MenuItem attribute
  [MenuItem("Mesh Info/View UV info")]
static void Init()
  {
//Now to make things easier with drawing etc, lets grab the window and make sure that it can't be scaled
    ViewMeshUVInfo m_window = EditorWindow.GetWindow<ViewMeshUVInfo>();
    //setting the min and max size of the window will make it so that scaling the window will have no effect
    m_window.minSize = new Vector2(1180, 700);
    m_window.maxSize = new Vector2(1181, 701);
    //Now we set those offset values since we have initialized the window
    m_maxHandlesSize = m_window.maxSize.y - 30;
    m_handlesXOffset = m_window.maxSize.x * 0.418f;
}
//During OnGUI there will be a point where we check to see if the mouse is within one of the triangles displayed in the UVs. This function will return true if it is and false if it isn't. This is just a basic triangle point test.
bool isMousePointWithinTriangle(Vector3 p1, Vector3 p2, Vector3 p3)
{
    Vector3 vect1 = p2 - p1, vect2 = p3 - p1;
    Vector3 mouseFromP1 = (Vector3 )Event.current.mousePosition - p1;
    float u = (Vector3.Dot(vect2, vect2) * Vector3 Dot(mouseFromP1, vect1) - Vector3 Dot(vect2, vect1) * Vector3.Dot(mouseFromP1, vect2)) / (Vector3.Dot(vect1, vect1) * Vector3 Dot(vect2, vect2) - Vector3.Dot(vect1, vect2) * Vector3.Dot(vect2, vect1));

  float v = (Vector3.Dot(vect1, vect1) * Vector3 Dot(mouseFromP1, vect2) - Vector3 Dot(vect1, vect2) * Vector3.Dot(mouseFromP1, vect1)) / (Vector3.Dot(vect1, vect1) * Vector3 Dot(vect2, vect2) - Vector3.Dot(vect1, vect2) * Vector3.Dot(vect2, vect1));
    return(u >= 0) && (v >= 0) && (u + v < 1);
  }

//Now everything else we do is in the OnGUI function. 
void OnGUI()
{
//Lets start a check to see if anything changed
    EditorGUI.BeginChangeCheck();
    m_viewedMesh = EditorGUILayout.ObjectField("Mesh: ", m_viewedMesh, typeof(MeshFilter), true) as MeshFilter;

    //if the mesh changed we set up the information string to display all of the triangles, vertices and UVs
    if(EditorGUI.EndChangeCheck())
    {
      if(m_viewedMesh != null)
      {
        meshInfoString = "Triangles: \n";
        for(int i = 0; i < m_viewedMesh.sharedMesh.triangles.Length; i+= 3)
        {
          meshInfoString += "\n\nTriangle" + i / 3 + ": \n";
          meshInfoString += "Vertices: (" + m_viewedMesh.sharedMesh.vertices[m_viewedMesh.sharedMesh.triangles[i]].x + " , " + m_viewedMesh.sharedMesh.vertices[m_viewedMesh.sharedMesh.triangles[i]].y + "), (" +
m_viewedMesh.sharedMesh.vertices[m_viewedMesh.sharedMesh.triangles[i + 1]].x + " , " + m_viewedMesh.sharedMesh.vertices[m_viewedMesh.sharedMesh.triangles[i + 1]].y + "), (" +
m_viewedMesh.sharedMesh.vertices[m_viewedMesh.sharedMesh.triangles[i + 2]].x + " , " + m_viewedMesh.sharedMesh.vertices[m_viewedMesh.sharedMesh.triangles[i + 2]].y + ")\n";
meshInfoString += "UVs: (" + m_viewedMesh.sharedMesh.uv[m_viewedMesh.sharedMesh.triangles[i]].x + " , " + m_viewedMesh.sharedMesh.uv[m_viewedMesh.sharedMesh.triangles[i]].y + "), (" +
m_viewedMesh.sharedMesh.uv[m_viewedMesh.sharedMesh.triangles[i + 1]].x + " , " + m_viewedMesh.sharedMesh.uv[m_viewedMesh.sharedMesh.triangles[i + 1]].y + "), (" +
m_viewedMesh.sharedMesh.uv[m_viewedMesh.sharedMesh.triangles[i + 2]].x + " , " + m_viewedMesh.sharedMesh.uv[m_viewedMesh.sharedMesh.triangles[i + 2]].y + ")";

        }
      }
    }
    //if the mesh attached to this editor isn't null we display all of the data
    if(m_viewedMesh != null)
    {
      m_scrollPosition = EditorGUILayout.BeginScrollView(m_scrollPosition);
    GUILayout.Label("The Mesh has: ");
    GUILayout.Label(m_viewedMesh.sharedMesh.vertexCount + " vertices");

    GUILayout.Label(m_viewedMesh.sharedMesh.uv.Length + " UVs");

    GUILayout.Label((m_viewedMesh.sharedMesh.triangles.Length / 3) + " triangles\n");

      GUILayout.Label("Legend: Blue = First Vertice, Red = Second Vertice, Yellow = Last Vertice\n");
      if(lastSelectedTri != "")
      {
        GUILayout.Label(lastSelectedTri + "\n");
      }
    GUILayout.Label(meshInfoString, GUILayout.ExpandHeight(true));
      //The first thing that we are going to draw is a grid where we want to display the UVs
      Handles.color = Color.gray;
      for(int i = 1; i < 16; i++)
      {
        Handles.DrawLine(new Vector3 (m_handlesXOffset + m_maxHandlesSize * (i / 16f), m_scrollPosition.y), new  Vector3 (m_handlesXOffset + m_maxHandlesSize * (i / 16f), m_scrollPosition.y + m_maxHandlesSize));
        Handles.DrawLine(new Vector3 (m_handlesXOffset, m_scrollPosition.y + m_maxHandlesSize * (i / 16f)), new  Vector3 (m_handlesXOffset + m_maxHandlesSize, m_scrollPosition.y + m_maxHandlesSize * (i / 16f)));

      }
      bool clickedTri = false;

      //Next we will use handles to draw UV triangle
      for(int i = 0; i < m_viewedMesh.sharedMesh.triangles.Length; i+= 3)
      {
      Vector2 vert1= new Vector2 (m_viewedMesh.sharedMesh.uv[m_viewedMesh.sharedMesh.triangles[i]].x * m_maxHandlesSize + m_handlesXOffset, (1 - m_viewedMesh.sharedMesh.uv[m_viewedMesh.sharedMesh.triangles[i]].y) * m_maxHandlesSize + m_scrollPosition.y); 
      Vector2 vert2 = new Vector2 (m_viewedMesh.sharedMesh.uv[m_viewedMesh.sharedMesh.triangles[i + 1]].x * m_maxHandlesSize + m_handlesXOffset, (1 - m_viewedMesh.sharedMesh.uv[m_viewedMesh.sharedMesh.triangles[i + 1]].y) * m_maxHandlesSize + m_scrollPosition.y); 
      Vector2 vert3 = new Vector2 (m_viewedMesh.sharedMesh.uv[m_viewedMesh.sharedMesh.triangles[i + 2]].x * m_maxHandlesSize + m_handlesXOffset, (1 - m_viewedMesh.sharedMesh.uv[m_viewedMesh.sharedMesh.triangles[i + 2]].y) * m_maxHandlesSize + m_scrollPosition.y);
      //while we are drawing it we will also check to see where the mouse is, and if the mouse is inside the displayed triangle
      bool thisTri = isMousePointWithinTriangle(vert1, vert2, vert3);

      if(thisTri)
     
        //if the mouse was clicked, lets show the user the vertex indices of the triangle that was clicked on
        if(Event.current.type == EventType.mouseDown)
        {
          clickedTri = true;
          lastSelectedTri = "Vert indexes are: " + m_viewedMesh.sharedMesh.triangles[i] + ", " + m_viewedMesh.sharedMesh.triangles[i + 1] + ", " + m_viewedMesh.sharedMesh.triangles[i + 2];
        }

        //to show that the mouse is hovering over this triangle lets turn it green and highlight the vertices
        Handles.color = Color.green;
//To draw the triangle, we simply call Handles.DrawPolyLine, which draws a line from one point to another in the order that they are passed
        Handles.DrawPolyLine(vert1, vert2, vert3, vert1);
        Handles.color = Color.blue;
//To highlight the vertices of the selected triangle, what we are going to do is draw a very small line using a similar function as before, but this time we will use Handles.DrawAAPolyLine to allow us to set a width for the line
      Handles.DrawAAPolyLine(10.0f, new Vector3 m_viewedMesh.sharedMesh.uv[m_viewedMesh.sharedMesh.triangles[i]].x * m_maxHandlesSize + (m_handlesXOffset * 0.99f), (1.0f - m_viewedMesh.sharedMesh.uv[m_viewedMesh.sharedMesh.triangles[i]].y) * m_maxHandlesSize + m_scrollPosition.y), new Vector3 m_viewedMesh.sharedMesh.uv[m_viewedMesh.sharedMesh.triangles[i]].x * m_maxHandlesSize + (m_handlesXOffset * 1.01f), (1.0f - m_viewedMesh.sharedMesh.uv[m_viewedMesh.sharedMesh.triangles[i]].y) * m_maxHandlesSize + m_scrollPosition.y));
        Handles.color = Color.red;
        Handles.DrawAAPolyLine(10.0f, new Vector3 m_viewedMesh.sharedMesh.uv[m_viewedMesh.sharedMesh.triangles[i + 1]].x * m_maxHandlesSize + (m_handlesXOffset * 0.99f), (1.0f - m_viewedMesh.sharedMesh.uv[m_viewedMesh.sharedMesh.triangles[i + 1]].y) * m_maxHandlesSize + m_scrollPosition.y), new Vector3 m_viewedMesh.sharedMesh.uv[m_viewedMesh.sharedMesh.triangles[i + 1]].x * m_maxHandlesSize + (m_handlesXOffset * 1.01f), (1.0f - m_viewedMesh.sharedMesh.uv[m_viewedMesh.sharedMesh.triangles[i + 1]].y) * m_maxHandlesSize + m_scrollPosition.y));
        Handles.color = Color.yellow;
        Handles.DrawAAPolyLine(10.0f, new Vector3 m_viewedMesh.sharedMesh.uv[m_viewedMesh.sharedMesh.triangles[i + 2]].x * m_maxHandlesSize + (m_handlesXOffset * 0.99f), (1.0f - m_viewedMesh.sharedMesh.uv[m_viewedMesh.sharedMesh.triangles[i + 2]].y) * m_maxHandlesSize + m_scrollPosition.y), new Vector3 m_viewedMesh.sharedMesh.uv[m_viewedMesh.sharedMesh.triangles[i + 2]].x * m_maxHandlesSize + (m_handlesXOffset * 1.01f), (1.0f - m_viewedMesh.sharedMesh.uv[m_viewedMesh.sharedMesh.triangles[i + 2]].y) * m_maxHandlesSize + m_scrollPosition.y));
        }
      else
      {
      //otherwise just draw the triangle in white
        Handles.color = Color.white;
        Handles.DrawPolyLine(vert1, vert2, vert3, vert1);
      }
    }
    if(Event.current.type == EventType.mouseDown && !clickedTri)
    {
      lastSelectedTri = "";
    }
    //Lastly we will draw a square outline around the UVs just to be fancy
  Handles.color = Color.white;
    Handles.DrawAAPolyLine(4.0f, new Vector3(m_handlesXOffset, m_scrollPosition.y),
new Vector3(m_handlesXOffset + m_maxHandlesSize, m_scrollPosition.y),
new Vector3 m_handlesXOffset + m_maxHandlesSize, m_scrollPosition.y + m_maxHandlesSize),
new Vector3(m_handlesXOffset, m_scrollPosition.y + m_maxHandlesSize),
new Vector3(m_handlesXOffset, m_scrollPosition.y));

    GUILayout.EndScrollView();
    Repaint();
    }
}
}

Once you are done and have the window open, when you drag a mesh filter into the object field you will get something that looks like this:


Its pretty simple, and everything is laid out in front of you. There is definitely room for improvement on this as well, this script was originally something I threw together to figure out vertex indices in our first version of President3D. Anyways that is all for this week!

Friday, October 25, 2013

Unity Editor Tools And XML To Save Time

As you develop you will find more and more circumstances where hard coding data into your game becomes a huge pain. Having to recompile your whole game just to change the price of an item, or change a spelling mistake in the description of a trophy will get old really fast, which is where soft coding and dynamic loading comes into play.

With Unity's editor being so extensible, soft coding is a very attractive option for a lot of the data you will need for your game. Within minutes you can have data classes to store your values, and create editor scripts to make data creation extremely simple and user friendly. Today you are going to see a very basic implementation of this.

What we are going to be doing is we are going to create a data class for an in game item, an editor class that will allow you to create and store many items, and a class that will load the data and display it in a log. All of the data is going to be stored as XML files in this tutorial since it is built into .NET.

So the first thing that we want to do is create our data class, so create a new C# script in Unity and call it ItemData.

public class ItemData
{
//Lets make two string variables that will hold the name and description of the trophy
public string name = string.Empty;
public string description = string.Empty;
//Lets say that the item is also purchased from a store in your game, so we can set a price for it as well
public int price = 10;
/*
* This would be as simple as it gets. You could also add in extra detail such as the name 
* of the icon for this item that would be loaded from resources
*/
}

This is a very basic implementation of item data. In your game you may want to put more information in such as the icon name, texture path, and possibly even more. It all depends on what your uses are going to be.


So now that we have the data class, let's create an Editor Window to edit, create and remove data. The editor window is very useful, it can be docked just like your Scene and GameView windows, and it is very customizable. So what we want to do is create a new C# script in Unity called ItemsEditor, and this time we want to put it in the Editor folder of your project. If you don't have one all you need to do is create a new folder called Editor.

using UnityEngine;

//This is going to be an editor window script, so we need to include UnityEditor
using UnityEditor;

//We are going to be using a generic list to store the item data so we need to include the System.Collections.Generic library
using System.Collections.Generic;

//And since we are going to be saving to a file and will be serializing to XML, we need to include those libraries as well
using System.IO;
using System.Xml.Serialization;

//This is an editor window class so we are going to want to make sure that the class extends from EditorWindow
public class ItemsEditor : EditorWindow
{
//first lets create a string variable that will store the file path of the xml file. Lets make it readonly so we know that no one will mess with it int he code, and make it static so it can be used in static functions
private static readonly string s_filePath = Application.dataPath + "/Resources/Items/XML/";
private static readonly string s_fileName = "items.xml";
//Next we need to create the list that will store all of the item data
private static List<ItemData> s_items;
//Thirdly we need to make another list, but this time with boolean values. We are going to make the editor window collapsable, and we need to know which items are currently being viewed
private static List<bool> s_itemFoldouts;
//Lastly we want our editor window to be scrollable if the list gets somewhat large, so we need to store a scroll position for the editor's scroll bar
private Vector2 m_scrollPosition;
//Our first function is going to be an initalization function called init. Here we will create a new ItemsEditor window, and load the XML file. 
//There is also the MenuItem attribute, and we use this to create a menu item within the Unity editor that we can click on
//Notice that this is also a static function
[MenuItem("Game Data/Item Editor")]
static void init ()
{
EditorWindow.GetWindow<ItemsEditor> ();
loadXMLFile ();
}
//Here we will create a static function called loadXMLFile so that it can be used during initialization
private static void loadXMLFile ()
{
//Here we will make sure to initalize the items and item foldouts list
s_items = new List<ItemData> ();
s_itemFoldouts = new List<bool> ();
//if the file exists we load it, otherwise we dont do anything
if (File.Exists (s_filePath + s_fileName)) {
//lets create our XMLSerializer to handle the item data
XmlSerializer serializer = new XmlSerializer (typeof(List<ItemData>));
//Next we create a new FileStream with our file path. Notice that we have the using statement. 
//This allows us to do whatever we want with the Filestream and know that it will close itself automatically
using (FileStream file = new FileStream(s_filePath + s_fileName, FileMode.Open)) {
try {
//Lets try to load the data into the items list and set up the foldouts list as well
s_items = serializer.Deserialize (file) as List<ItemData>;
s_itemFoldouts = new List<bool> (s_items.Count);
for (int i = 0; i < s_items.Count; i++) {
s_itemFoldouts.Add (false);
}
} catch (System.Exception e) {
// if anything weird happens we will let you know here
Debug.LogError (e.Message);
}
}
}
}
//Next us our function to save the data to the disc
private void saveXMLFile ()
{
//First lets check to see if the directory to the file exists, and if it doesn't we create it
if (!Directory.Exists (s_filePath)) {
Directory.CreateDirectory (s_filePath);
}
//Then we serialize the list of items into the XML file and refresh the AssetDatabase
using (FileStream file = new FileStream(s_filePath + s_fileName,  FileMode.Create)) {
XmlSerializer serializer = new XmlSerializer (typeof(List<ItemData>));
serializer.Serialize (file, s_items);
AssetDatabase.Refresh ();
}
}
//Now we need to display all of the item editing stuff, so we need to create an OnGUI function
private void OnGUI ()
{
//First lets create a button that will save all of the item data
if (GUILayout.Button (new GUIContent ("Save Items List"))) {
saveXMLFile ();
}
//Then lets create a button that will add a brand new ItemData to the list and add a toggle to the foldout list
if (GUILayout.Button (new GUIContent ("Add New Item"))) {
s_items.Add (new ItemData ());
s_itemFoldouts.Add (false);
}
//Next lets create the scroll view so that we can scroll the window if the list gets large
m_scrollPosition = GUILayout.BeginScrollView (m_scrollPosition);
//Now what we want to do is go through each item and if the foldout toggle is set to true, display GUI that will let the user edit that specific item
for (int i = 0; i < s_items.Count; i++) {
//This will let the user change the toggle for the current item
s_itemFoldouts [i] = EditorGUILayout.Foldout (s_itemFoldouts [i], new GUIContent (s_items [i].name + " Info"));
//if the toggle is on we let the user edit the item
if (s_itemFoldouts [i] == true) {
s_items [i].name = EditorGUILayout.TextField (new GUIContent ("Item Name"), s_items [i].name);
s_items [i].description = EditorGUILayout.TextField (new GUIContent ("Item Description"), s_items [i].description);
s_items [i].price = EditorGUILayout.IntField (new GUIContent ("Cost"), s_items [i].price);
//We should also allow the user to remove the selected item so lets give them that option here
if (GUILayout.Button (new GUIContent ("Remove Item"), GUILayout.Width (position.width * 0.2f))) {
s_items.RemoveAt (i);
s_itemFoldouts.RemoveAt (i);
i--;
}
}
}
//Lastly we end the scroll view
GUILayout.EndScrollView ();
}
}

And that is it for the Editor script. This should provide you with a simple but useful tool to edit your item data for your game.

Now that we have the item data class and the item editor class, we need a way to use this data in our game at run time. The next script is a very basic class that will load up your item data and display it in the Unity Console. Now let's create a new C# script called LogCustomData.



using UnityEngine;

//We need to load the XML file, make the xml file readable, and put it into a list so we need to include the libraries to do that
using System.Xml.Serialization;
using System.Collections.Generic;
using System.IO;

public class LogCustomData : MonoBehaviour
{
//The XML file will be loaded as a Text asset since it ends with .xml. We are making it public so that we can set it within the editor if we want to
public TextAsset itemXMLFile;
//And lets make the list that will store all of the items
List<ItemData> m_items;
//Now lets create our function to load all of the items
private void loadItems ()
{
//We create our XMLSerializer like normal
XmlSerializer serializer = new XmlSerializer (typeof(List<ItemData>));
//Here we use a StringReader. This puts the string from the TextAsset into a format that can be deserialized using the XMLSerializer
using (StringReader reader = new StringReader(itemXMLFile.text)) {
//Then we can just assign the items list from here
m_items = serializer.Deserialize (reader) as List<ItemData>;
}
}
void Start ()
{
//If we didn't set the xml file in the editor we will load one from a default position, this is where we saved it in the Editor
if (itemXMLFile == null) {
itemXMLFile = Resources.Load ("Items/XML/items", typeof(TextAsset)) as TextAsset;
}
//Call our loading function
loadItems ();
//Log all of the item data so that we can see that it worked
for (int i = 0; i < m_items.Count; i++) {
Debug.Log (m_items [i].name + " is " + m_items [i].description + " and it costs " + m_items [i].price.ToString ());
}
}
}

And that is it. Now you have a very basic implementation of a class to store data, an editor to manipulate that data, and a script that can load that data for you to use within your game. 

That is all for now! If you enjoyed the post or found it useful hit those share buttons for Facebook, Twitter and Google+!