Monday 20 April 2015

Agile Project Management for Small Projects

While Agile development Gurus may not recommend cherry picking features, I suggest the use of mini-stories and iterations to help deliver functionality while working on small projects.

Are we doing good?

The key to good project management is that, often, the client see progress and the developer get compensated.

How often? Many small projects move slowly, right? I would argue that, the smaller the project, the faster we should see improvements.

  • For a SME (small or medium enterprise), 240 to 360 man-hours may cover 4 to 8 stories.
  • For a small project with a single programmer working part time, 4 to 12 hours may cover a single mini story.
Not convinced? Please consider the following:
  • Small projects are... smaller. Features should be simpler and easier to implement.
  • Many small projects build on top of existing functionality (think "asset store"). While changes to existing source are time consuming, more often than not such changes are small and do not (should) not impact existing structures.
  • Small stakeholders shouldn't commit over large amounts. No more than you should gamble your house before your mortgage is paid for.

Is something wrong with our project?

The following clearly indicates that something needs fixing:

  1. The software isn't working. If the software isn't working on the client's box, at least it should work on the developer's (who can demonstrate progress by uploading a video)
  2. The developer do not know what they are supposed to do.
  3. The client do not know what the developer are doing.
  4. The client and the developer disagree about the result.
I'm not suggesting that you micro-manage your project. If the developer get paid regularly, and the client can see visible improvements, you are doing just fine. Otherwise, read on.


How to manage a small project?

I will assume that you are working on a small project if you put 8 to 24 man hours per week into development. In short:

  • The developer and the client must agree on deliverables. Agree on 2 to 6 deliverables per 24 hours period.
  • Describe deliverables using stories. A story is a common-sense description of a feature which adds value to the software.
  • If possible, give a heads up to your client when you have completed a story.
user stories



Problems and solutions

Developer: "I need a framework" 

Read elsewhere about Big Design Upfront.
Although you may feel that a framework 

I don't understand what the developer are doing

Explain to your developer that you pay for visible progress. Refuse to pay for technical stuff that you don't understand.
Irrelevant to perceived usefulness, some features are expensive to implement. This stuff should average itself over time. You can appreciate this on a velocity chart.

Velocity Chart

When in doubt, you can ask advice from another developer; if you feel that work is slow, you can also get another developer onboard. Adding a person to a project is less risky than firing your developer outright. After all, they may be struggling with genuinely tricky stuff.

I don't understand what the client want me to do right now

Some clients have a core vision / general objective in mind but may not know how to achieve their goal, or may feel unsure about where to start.

Don't be uptight. Make your own task list and show it to your client. In most cases, small clients feel happy to see the burden of project management lifted off their shoulders.

The client are unwilling to pay until the software is 'complete'

Explain to your client that you expect a compensation for work done, and give them means to monitor progress. If this doesn't satisfy them, you don't have to work for them.

The client will pay after reviewing the code

Do not agree to this. Agree to small deliverables, so your client can review the code after they pay for it.

90% of the software out there, including software used in ATMs, rockets, the power grid and medical equipment,  isn't "good software". 

Conclusion

In this article I shared my experience working on small projects. I hope that this will be useful to you and wish you success in your endeavours.


Saturday 11 April 2015

Unity Networking: Playing on the server

Having to open two instances whenever testing a networked application is awkward.

Two questions arise when trying to "play on the server":
  1. Can we setup as both client and server within the same instance? The answer is NO. Beyond the negative result, "Client" and "Server" roles are interchangeable for most practical purposes.
  2. Can we RPC from the server to itself? Somewhat surprisingly, the answer is, again NO. More generally it appears that you cannot unicast from a network player to the same network player.
Short of re-implementing all our input interface to invoke server instances locally, what do we do? Reflection will help overcome this hurdle:

private void ClientRequest(string name,params object[] args){

        
if (Network.isServer
            typeof(TargetType).GetMethod(name).Invoke(avatar,args);
        else 
            networkView.RPC (nameupstreamargs);

}

In the above example...
  • TargetType is the type of the object that you wish to invoke.
  • networkView is the network view that you would normally send your RPC from.
  • Remember using System.Reflection.
More powerful than MonoBehaviour.Invoke( name, delay ).

Friday 10 April 2015

Networking for Unity?

While there may be other solutions to work with, Unity, Photon and uLink come to mind.

Surprisingly, a team bothered trying all three, then decided to do a writeup.

Thursday 9 April 2015

Removing Logged out players

Here's a couple of tips to help you kill logged out players and make sure they stay dead.

Destroying network instances

There is a counterpart to Network.Instantiate : Network.Destroy. The simple advice is, whenever possible, use Destroy NOT Network.Destroy

Using Destroy() means that you let a client destroy its local copy of a network object in due time, not in the middle of doing something else.

Do not cache network instances (as a rule, do not cache anything until you are truly desperate. And one more thing: don't optimise). This is a recipe for creating intermittent bugs.

When do we know that a player has disconnected?

Any object can process OnPlayerDisconnected(Network player)



They're coming to get you Barbara!

As soon as you get this to work, you will notice that opening new clients causes logged out players to return from hell. This is all thanks to buffered RPCs. What does it mean for an RPC to be "buffered"? Well, it means that any buffered RPCs will hit every client you open, in play order.

This Q&A explains how you can clear buffered calls to Instantiate.


Wednesday 8 April 2015

Basic inventory system (2D)

Today I will put together a basic 2D inventory system. This session lasted 2 hours (including the writing of this tutorial).

download the unity package.

Resources

First we need artwork. I downloaded a free pack created by 7Soul1.

The inventory will display (or hide) upon pressing the I key. Since I'm only prototyping I'm not very picky about functionality or appearance. All I need to do is display the inventory and perform a default action upon selecting an item.

I will use the Unity UI system.

Inside the editor, I created a canvas object. This is needed to display UI elements.
I notice that graphics cannot be dragged directly on stage. This is an interesting difference between the 3D and 2D workflow.

A simple, clickable button

I created a button and removed the text element. I configure the button.

  • "simple" (not sliced)
  • preserve aspect ratio
  • change the icon. Notice that we need to change the texture type to "sprite" in order to access imported artwork.
I then create a script named "UseItem". This is to test the button we've just created. The script provides a single function, Use:

       public void Use(){
           Debug.Log ("Applying default action.");
      

       }

Via the Button script, we now tie the button's OnClick function to the Use function of the UseItem class. Works.


A row of buttons

We don't know in advance (before runtime, that is) how many items the inventory will contain so I prefab the button as "InventoryItemButton".

I then create a DisplayInventory script. Initially I will attach this to the canvas object. Let's display the same button we just created, but now we're instantiating the button programmatically.

        GameObject e = Instantiate(itemUI,
           Vector3.zero,
              Quaternion.identityas GameObject;

        e.transform.SetParent (transformfalse);


The prefabbed button must be attached to a GameObject field named itemUI for this to work.
Now we can create a row of buttons, like this:

        int spacing = 34;


        for (int i=0i<3i++) {

            GameObject e = Instantiate (itemUI,                                    

              Vector3.zero+Vector3.right*spacing*i,    
                 Quaternion.identityas GameObject;

            e.transform.SetParent (transformfalse);


        }

A data source

In order to populate the inventory with real data, we need a data source. Minimally, the data source can be a list of strings, with each string representing an item. We will then match each string to an icon.

        string[] inventory = new string[]{ "Small healing potion""Sword""Mace" };
     
        for (int i=0i<inventory.Lengthi++) {

            GameObject e = Instantiate (itemUI
                                        Vector3.zero+Vector3.right*spacing*i
                                        Quaternion.identityas GameObject;

            e.GetComponent<Image>().sprite = 
                Resources.Load (inventory[i],typeof(Sprite)) as Sprite;

            e.transform.SetParent (transformfalse);

        }



As you can see, Resources.Load() is used to retrieve the sprites at runtime.

Adding functionality

One problem with the above is that our inventory items don't do anything. As "Strings" they don't have any functionality. What if our inventory items were actual game objects? Then, we would have a simple solution (I will discuss later why it makes sense to model inventory items as game objects)

For now, let's do the following:

  • Create an inventory game object.
  • Add several items (just use empties)
  • To each item, we'll attach a component called Item. In fact I have several subclasses of Item, including Consumable and Equipment.
We then update the function used to create the inventory:

        Transform inventory = GameObject.Find ("Inventory").transform;

        for (int i=0i<inventory.childCounti++) {

            Item item = inventory.GetChild (i).GetComponent<Item>();

            GameObject e = Instantiate (itemUI
                                        Vector3.zero+Vector3.right*spacing*i
                                        Quaternion.identityas GameObject;

            e.GetComponent<Image>().sprite = Resources.Load (item.type,typeof(Sprite)) as Sprite;
            e.GetComponent<UseItem>().item = item;
            e.transform.SetParent (transformfalse);

        }

And the UseItem script is now updated to look like this:

       public class UseItem : MonoBehaviour {

           public Item item;

           public void Use(){ item.Use (); }

       }

Small embellishments.

I reattached the InventoryUI script to a standard UI panel. This takes a little configuring but felt right. 

I also wanted consumable items to disappear after use. This requires rebuilding the UI. Unfortunately, Destroy() does not take effect immediately so that, if we query the UI to rebuild right away, the removed item would still show. I solved this with a coroutine but it felt a bit clunky. A better option is to un-parent the item being destroyed (since we're iterating the children of the Inventory object).

Why do we model inventory items as game objects?

Before they become part of the player's inventory, many items begin their life as game objects.
The question is then, what happens when we collect these objects? We probably want them to disappear from the game world. 
An effective, but inefficient and inelegant solution to the problem is to just move them out of the way, possibly hiding renderable components and disabling colliders. If you use a model/view split in the hierarchy, you can also destroy the view, and all you have left is the "item logic".
Either way, you can preserve the original object, which preserves the functionality of the item.

Monday 6 April 2015

Unity Asset Watch: Control Objects with EyeX!

Tobi's EyeX SDK is an asset allowing you to control 3D objects by just looking at them. I've seen eye pointer tech over the years but don't remember whether it is supposed to be any use.

Saturday 4 April 2015

Multiplayer in Unity: Get connected

Introduction

The goal of this article is very simple; I have two computers in our living room and I want to find out whether I can create a Unity executable that will have these two computers communicate.

Setting up a server

The "server" is the instance of our app that can accept incoming connections.

I created a Server class. I initialise the server using Network.InitializeServer.
Used code as provided in API reference.
Added error handling code.
Seems to work.

Setting up a client

The "client" is the instance that will connect to the server.

I created a Client class. I initialise the client using Network.Connect.
There are endless variants of Network.Connect. The one I choose uses an IP and port (but read on; we're not staying with this)

It works. In fact, it works a bit too well because it still initialises successfully when the network is not initialised. Weird, I know.

How to choose the IP and port
  • The 'port' refers a communication channel. As a rule of the thumb don't use anything under 1000 (other applications and OS services may be using these). Of course the port should match between client and server.
  • 'IP' identifies a computer on the network.
    127.0.0.1 refers the local host. In other words this is connecting to the same machine we are running the client from. Often useful, but we hope to do better than that.
So, how to choose the IP? And why we need a master server

The answer is, let's not do this, as you probably do not have a stable IP address.
Not sure what this means? Don't have stable IP.
Didn't setup your internet connection yourself? Don't have stable IP.

From a functional point of view, the master server is a go-between the client and the server. Works like this:
  1. Server initialises.
  2. Server registers with master server
  3. Client fetches server info from master server
  4. Client connects to the server.
So, where is the master server you ask? Well, it's a service provided by Unity Technologies so I guess it is somewhere inside their bunker.

Note that the Unity master server is provided only for testing purposes. They're not actively preventing you from using it in a live game but they don't warrant uptime either.

IMPORTANT: You cannot setup a client AND setup a server AND access the master server within the same instance. It may be possible to run a client and server via localhost (or using stable IPs) but I haven't tried. To understand why it works like this, read here.

Registering to the master server

MasterServer.RegisterHost takes 3 arguments (API):
  • Game Type - this is a unique identifier for your game. You might use something like com.company.gamename just as a convention that's easy to remember.
  • Game Name - this is what most players think of as "room name". Again use whatever you like (there is probably a way to iterate room names but in practice this is not really necessary).
  • Description - frankly, I think this should be optional. Just put something there.
IMPORTANT: Call MasterServer.UnregisterHost before exiting (for example, inside OnDestroy() )

Client side: Fetching the host data via Master Server

The client uses 3 APIs to connect to the master server and retrieve a host:
I'm not sure about the advantage of polling for the host list. If you implement OnMasterServerEvent you will receive a notification when the host list has been received. A big advantage of doing it this way is that polling will keep busy with itself after an empty list has been received.

Then we connect using Network.Connect( HostData host, string password )


Troubleshooting Tips

Before getting into specific errors I encountered, note that it is useful to have a separate script reporting master server events. Said script will implement the following:
  • void OnFailedToConnectToMasterServer(NetworkConnectionError err)
  • void OnMasterServerEvent(MasterServerEvent e)
Why is this useful? Because these events are broadcast. So if you put them both in your client and your server script, every event will be broadcast twice, which adds to the general confusion.

Other methods that can help troubleshooting:
  • Use separate GameObjects that you attach your client/server script to. This way you can disable the one or the other and see what happens. This also provides a quick way to prepare a "server only" or "client only" build.
Common errors, and why they occur:

Error #1: Already connected to the master server, the server probably hasn't cleaned up because of an abrupt disconnection.

May occur as a result of trying to simultaneously start the client and server inside the same player.

Error #2: The connection request to ###.###.#.###:##### failed. Are you sure the server can be connected to?

May occur while running a client and server in the same app. As far as I could judge, Unity does not allow a client to be its own server (and vice versa).

Error #3The remote system is using a password and has refused our connection because we did not set the correct password.

May occur while running a client and server in separate instances, but the client did not set a password.

Friday 3 April 2015

Testing Parse

Before you read what follows, consider that setting up and testing Parse took only 33 minutes. Not bad.
I probably had a break in the middle of that. Or maybe not. So, Parse is definitely worth a look, not hard to use. Your grandma can't set it up, but your 12 year old nephew will figure it out in no time.

Recently I discovered a web service named Parse, which claim to eliminate the need for a web server.
I decided to give it a shot and downloaded their test project.

Really funny how people advertise "easy to use solutions" then proceed to rubbing in your face a broken setup while providing shiny examples of bad practices in how not to implement error handling (aka don't muddle through, don't fail silently).

Parse have a startup guide that shows you how to connect your application to the game server. Apparently they haven't realised that people will head over to the startup guide first thing, to find out whether their service is working for them. Anyway this is how it went for me.

  • Downloaded the sample project. Since they don't say anything about Unity 5 (probably corrected by the time you read this) went with their 4.x project anyway.
  • Updated to U5 without glitch. Yay.
  • Oops, they say I should configure a scene object that doesn't exist (dang, took me a while to realise that this is because Unity creates an empty scene whenever opening a new project. C'mon guys it's much more logical than opening the only scene that's in there, isn't it?)
  • Oh my, there's a lonely DLL in there, what am I doing?
  • Scanned their forums, found a rather depressing entry which, well, somehow pointed at the simple operations (create a blank project, add the required script; yes, it is because it is simple that it's so weird they leave it broken) needed to repair the template project.
  • Nnh. They're asking me to input a .net key (lord knows what this is for) and app ID (shall I input something random)
  • So, of course it didn't work. The part that's really beyond me is that, it wasn't didn't work as in "pressing that test button" doesn't do anything. The test button simply wasn't there. I had to guess that it wasn't there because I wasn't logged into Parse. What were you guys thinking I would be thinking when trying to press a button that wasn't there? Yes, it crossed my mind that their server may be down. Yes, it crossed my mind that maybe these guys went out of business. Feeling good about Parse.
  • I logged in and they ask way way way too much details about your app, pretty please pray tell me now, why do you even need to know? Of course I don't have an app name, ID, user facing name and so forth. My mind is a white, snowy blank slate I'll have you know since I'm just testing the test - sorry, tech. Correspondingly, I did left most of everything blank which fortunately they allow.
  • By then I had an inkling that the .net key should be associated with the app (Duuuh, I'm so smart now am I?). Got hold of the key and retried. And of course it didn't work.
  • In the meantime, note that navigating back to the test / easy setup page from inside your user account page is somewhat roundabout.
  • Heading back to the settings. OMG they got an App ID in there, not just a .net key. This stuff is looking so amazing and slick I feel dizzy.
  • Input the other key. Press the test button (quickly, before it un-appears again).
Not much else to say. Very creepy how the client / initialisation goes MIA when something doesn't work. How am I ever supposed to know what went wrong, before I even noticed it did?

I will let you know whether I'm having fun with parse.