Customizable Navigation Bar

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!