When to widely display a project?

I’ve struggled to decide when to discuss the latest project publicly. There are a few main concerns. The biggest being:

Will the idea be stolen?

This is the loudest concern. I don’t want someone who is capable of executing on the idea to see it and make it before me and make it better. This perhaps is from a place of jealousy and selfishness. Ideally, having a well executed version of the idea playable sooner is better for the players, but worse for me as I’d miss out on any of the rewards that come with being the creator. They say ideas are a dime a dozen, and it’s true. It’s all about execution and I want first dibs at it.

Not that this idea is entirely novel. I’ve certainly taking inspiration from other games and even… harvested ideas from others (a cheeky way of saying ripped-off). But I have yet to see this gameplay concept be done in a digital medium and I’m afraid that once people see it it’ll be so obvious that many will take a stab at iterating on it. Again, I just want my chance to do so before the field becomes flooded.

Once the project is further along and the finish line is in sight I’m sure I’d feel comfortable broadcasting the project and it’s concepts to a larger audience. For now though, I feel that an established team or a more productive and experienced creator could finish a version of this concept faster than I could.

So much of what I do is experimental either in terms of game play or programming execution, not to mention the large amounts of time just learning the aspects of game development which I haven’t encountered before. This is to say that the time spent working on the project is intense yet not consistently productive. Certainly all the time is productive in a personal growth sense, the time is not being wasted. I just mean to say that, if I knew exactly what the game was to be (mechanically) and exactly how to achieve all aspects of its development (programmatically , visually, audibly and so on) then the process would run much smoother and the project would be finished faster.

I suppose this is obvious, if no experimenting or learning was needed then it can just get banged out effortlessly. Their would probably already be templated version of the game where you just plug in some art and slap it onto the AppStore. It would be another clone of a clone and go unnoticed.

But to add to the concern about the pace of development I have to be honest and admit I do not put many hours per day dedicated to the project. This can be a introspection for another time but to defend myself from myself I should also point out that even though the raw hours dedicated to the project are limited hours are intensely focused and productive (in the larger sense). This time can be quite draining so I am attempting to find ways to get more done while not burning out.

It feels cheesy to speak about the project is such a coveted way, as if it’s so amazing that people would flock to make it their own. I’m proud of it and while I want to say it’s humility that keeps this pride in check, the voice of it seems more demoralizing. It says “How vain of you to think your little idea is so valuable”.

Anyway, point is, there are plenty of daily victories in the project that I’m proud of and what to share. While at the same time being afraid that sharing too much, to too large an audience will result in the idea “being stolen”. The obvious answer then is to not share these victories widely and instead wait until the finish line is in sight before unveiling it to the world.

Summonable Tokens and AI

I have a cool addition to the game: Summonable Tokens. I made a Necromancer token and cards, one of which is Summon Skeleton, it creates a token at one of the grave mounds that are placed around the map. The summoned skeleton token is a “Lesser Token” which doesn’t work like a regular token on your team in that it can’t “play cards”. No no, a Lesser Token only acts at the end of your turn and does a specific action each time. In the skeleton’s case, it’s “Shamble” which is a short distance melee attack.

Summoning lesser tokens can work for the player too, so I’m thinking of making a Beast Master character who can summon different animals which will be Lesser Tokens and have different behaviors such as a Wolf that Lunges, a Hawk can like… dive I guess or a boar can Charge (move in a direction until it hits something.

This morning I got the card action “InvokeLesserToken” working. As in, being able to play a card that forces your Lesser token(s) to do something. For example, the card Hunger Of The Dead: It causes a Lesser Token to do 3 Melee moves. The player doesn’t choose the Lesser Token’s target or aim it’s shot, it simply forces the token to do it’s own thing.

AI Play Evaluation Helper

Over the last 2 days I also implemented a new method on CardActions called SpecialAiEvaluation() which returns a float that the AI uses to evaluate a play. It adds or subtracts from the play’s score, which it turn makes the card more/less likely to be played by the AI. This is useful because sometimes the AI needs help deciding when a card is worth playing. Sometimes the card is just very powerful but hard for the AI to systematically understand why. For example Summon Skeleton; it gets another token on the field but the AI currently doesn’t evaluate that. It only ever looks at paths and targets’ properties. So the Summon Skeleton action’s SpecialAiEvaluation() simply returns a large number, in this case 300, which is a higher score than any standard evaluation the AI does itself ensuring the card is selected to be played.

This SpecialAiEvaluation is in contrast to how the AI in Hearthstone does it’s evaluation. During a talk at GDC years ago the original AI guy on the Hearthstone team said that one goal of his AI was to not use any special, helper methods of evaluating plays. This is great as it means the AI is advanced enough to understand the value of a card’s effects without having to explicitly be told.

While it is possible that I devise such a robust system for my project, it is likely unnecessary with the time/effort required not being worth it, at least not now. In the current form I can be highly specific about how a particular CardAction is evaluated. Later, if a particular action (like summoning a token) proves to be something that happens often the action’s special evaluation can be converted into a standard evaluation step. It’s easy to imagine that the general scoring of adding a new token to your team is usually a good thing, but it’s just not better than performing a game winning attack, or saving a higher value token with a heal.

Kick, Punch, Eat Meat Dev Log #3

Big month in many ways, not just for KPEM but also just general life. First, I got a dog! Meet Bubble, she is a good girl.

Bubble loves walks, wind and belly rubs

Also, Oxygen Not Included came out of Early Access on Steam and I’ve been hooked. The magnitude of my addiction to ONI is unlike that of any game in a long time. Something about it just keeps me building for hours. Klei did a fantastic job with it and I’m eager to see where they take it next. Since it’s so similar to base builders like RimWorld and Dwarf Fortress I’d really like to see some kind of external visitors brought into the mix.

When not walking the dog or creating cooling loops I’ve been plucking away at KPEM. So what’s been happening:

Card Drag UX improvements / Refactor

Needed to do this for a while. Card dragging had become overly complex so I needed to give it an overhaul. Now when you drag cards you get a targeting arrow and when played they have a little hop animation as they go to the discard pile. Basically just trying to get it to work as much like Hearthstone as possible. It also works across PC and touch screens!

Objectives! Purpose!

There are now 4 Objective locations in the world, each one has a mini boss. The idea to these objectives is that if the player defeats the mini-bosses within they not only get a major reward (cards/equipment) but also the final boss will become easier.

There will be thematic details on this stuff later, but mechanically the objectives are added to the world and a powerful enemy is encountered at each one. The rewards and their effect on the final boss still needs to be coded.

Timer Deck!

This is a big new mechanic. There is now a deck of cards called the Timer Deck. It is full of special cards which have an effect on the round. Timer cards are revealed, one at a time, after the player’s Movement phase, some have immediate effects, like starting a combat, while others change some aspect of the round and stay in effect until a new Timer Card is revealed. A Timer card can make you start all combats with an extra card while it’s in play or they can make certain terrain tiles easier or harder to move through. Overall, they add variety to each round.

It’s not called a Timer Deck for nothing. Spread out evenly in the Timer Deck are cards that will increase the difficulty of the enemies you encounter. It will be advantageous for players to complete events which add cards to the Timer Deck and avoid situations that will waste their time because when the Timer Deck is depleted the Final Boss will emerge and the Final Fight will take place!

Play testing with this has been fun and the best part is that it piggy backs off of the existing card logic and code. Meaning the time/effort to add in this feature was minimal compared to the amount of game play options it added to the KPEM.

Phases and the new Prep Phase

Like before, this allows the player to make choices about what cards they want in their deck beyond just the combat purposes of a card.

The flow of the game is now broken up into Phases. The round starts with the Prep(aration) Phase. In the Prep phase, the player is shown 3 cards from their deck, they are given the option to select as many of these 3 cards as they wish to be played for this round. In this phase, the cards in your deck provide Steps (movement points) and sometimes other effects on the round. For example, the card Kick provides many Steps, while Eat Meat reduces steps slightly, costs 1 meat to use but heals the player.

Rough Prep UI. Lots of placeholder stuff. Card Step values are in the blue box. Since I’m at full health I choose not to play Eat Meat this round.

After the player has locked in their Prep cards for the round the Explore Phase begins. In this phase, the player moves their character on the map, spending Steps. When the character lands on a special tile its effects are resolved right away.

When the player runs out of Steps the Explore phase is over and the Timer Phase begins. The Timer Phase is a short phase in which a new Timer Card is revealed, its effects resolve and then a new round begins.

And that is the overall Game Loop!

Enemy Intent

Enemies now display the type of attack and the amount of damage they will do on their turn. This is similar to other deck builder games like Slay the Spire and Guild of Dungeoneering.

This one I’ve avoided doing for a LONG time. In fact I fully intended to not display the enemy intent, instead just having the enemy attack always be somewhat unpredictable. But I must concede that allowing the player to see the enemy intent adds a lot of interesting gameplay and I cannot deny it any longer.

This also opens up a lot in terms of damage mitigation cards so I’m looking forward to adding more cards, equipment and enemy attack patterns with this new mechanic in mind!

Ok that’s everything for this month! Time to walk the dog and see if my Dreckos need sheering!

Convert Unity UI Screen Space position to World position

All credit goes to tosiabunio over on this forum post for this great solution.

Using Unity’s Canvas UI is excellent when you want your UI elements to scale and position correctly across different devices and aspect ratios. Learning to work with the Canvas UI properly is a bit of a nightmare but that’s a different story.

My issue was that while I do want UI elements to reposition across different aspect ratios I also want some GameObjects to have animations that seemingly interact with the UI elements. For instance, I wanted the Deck and Discard piles (UI Elements in Screen Space) to have Cards (Game Objects in World Space) come in/out of them.

GameObject Cards in World Space coming out of UI element Images in Screen Space. Works even as the UI elements move due to aspect ratio changes.

The problem is that you cannot simply have your World Space objects get the transform position of the Screen Space UI objects, the positions will not translate properly and you’ll end up with your World Space objects flying off the screen. This is where Tosiabunio’s solution comes into play when you want to ” Translate anchored overlay UI element to world position. “

var screenToWorldPosition = Camera.main.ScreenToWorldPoint(rectTransform.transform.position);

Basically, all you have to do is use the ScreenToWorldPoint method and pass it the desired UI object’s transform.position. It’s a simple one liner but this solution had evaded me for months where I was doing all kinds of crazy hacks trying to get these two positioning systems to play nice together.

Tosiabunio’s post also mentions a way to convert in the opposite direction, World Space into Screen Space:

Translate game object position from the world to overlay position in order to place UI element near that object.

To which he suggests:

RectTransformUtility.WorldToScreenPoint(Camera.main, obj.transform.position)

I haven’t tried this yet but it might be handy for others. Also, user karma0413 points out that WorldToScreenPoint can be slightly off in some situations and offers a solution which involves performing position calculations off the scale factor. Again, I haven’t tried it yet as the original one liner works perfectly for my purposes.

Let me know if this helps you and if you have any other Unity Canvas issues that you need help resolving. I’ve been working with it a lot lately and perhaps I can help or write more about common issues people face.

Kick, Punch, Eat Meat Dev Log #2

So many big steps made, things are shaping up nicely. There are still lots of mechanics with uncertainties around them and a whole lot of UI/UX improvements needed. But I’m here to celebrate the victories over the last month.

A major help was a day spent brainstorming with a friend of mine, Kevin Zipper. We went to Gumbo in Brooklyn, a shared work space for a gaggle of game devs. While there we used a meeting room for a day and really hashed out some aspects of the game focused on enemy abilities and over-world movement mechanics. It turned out to be a very productive 6 hours of white boarding and fleshing out of ideas.

One of the big things we discussed was how to get the player’s deck to play a larger role in the other aspects of the game. The core idea is that “The Deck is your Character” but the game had become something where the deck was only used in combat. This didn’t sit right with me so we spent half the day exploring ways that the deck could effect the other aspects of the game such as movement and events.

See, one of the issues I've had is that I'm not creative in a bubble (nor am I entertaining when alone, hence why my writing is too bland). I need someone to form ideas with but this game has always been just me. This is a big part of the reason development has been so slow and why the game has taken on so many other forms over the years. One day I'll put together a post showing the many different forms of the game has taken.

Anyway, let’s get into some detail on what’s changed.

Proc-Gen Map

Using proc-gen for map biome placement. Big thanks to another pal, Brian McLendon, the proc-gen wiz, for doing this. He’s able to turn Perlin Noise into a Perlin Symphony (sorry, working on being funny). Specifically, the world now utilizes a seed to generate height maps then uses those to decide which biome to assign to a tile. Previously it was just randomly picking a biome per tile, this has made the maps much more comprehensible.

Event ScriptableObjects

The Game Event system got a major overhaul and now runs off ScriptableObjects rather than an XML doc. This means a nicer way to create and edit events while making the events more customizable. Also, I implemented Choice Requirements, so some choices can be locked off unless the character has a specific card, equipment or whatever (like the blue text choices in FTL).

Equipment ScriptableObjects

Equipment now also utilizes ScriptableObjects, mostly for assigning all the visual and text aspects of the item. The equipment’s effect is still dictated by a specific class for each item, in order to give them unique and powerful effects. One cool thing that equipment can do is add more cards to your deck while the item is equipped, very much like in Card Hunter. So expect to see equipment that has powerful passive effects balanced with adding some bogus cards to your deck. Oh and there is an equipment type called Mutations, but I’ll leave it at that for now.

Movement Phase

This is a big change that mostly came as a result of the big brainstorming session. The player’s deck now plays a role in player movement on the overworld. During the Move Phase, the player is dealt a few cards from their deck. They then get to choose a card to use as their movement card. The card chosen will determine how many spaces they can move and may also provide other effects either in or out of combat. For instance, perhaps during the Move Phase a player chooses to use the Bandage Item card. This card doesn’t provide many move points, but it does heal the player. Or maybe they use Simple Plan, providing a moderate amount of move points while also giving an extra card draw in combat if it’s encountered.

There are still some aspects of this new mechanic that may change as testing continues but it’s a major step towards having a game where “The Deck is your Character”

Side Note: The original idea was to have this movement phase be just like 1 round of combat, using the same UI. But upon implementing this I immediately didn't like it. Despair set in, but I went ahead with a different iteration which I really like and is now what is currently in the game.

Dual Purpose Cards

To go along with the Movement changes, cards have had to change too. Cards have to play 2 roles now, Combat and Movement, so can have distinct abilities in each context. When looking at the cards in your deck or when viewing cards being offered to you, you’ll see the card’s stats and effects for both phases, but when in the combat or movement phase you’ll only see the values and effects that relevant to that phase.

Enemy Controllers

Previously, enemies were entirely defined using ScriptableObjects and their attacks were reusable classes like “DamagePlayer” and “AddCardsToDiscard”. These classes were attached to the enemy’s ScriptableObject via an array, giving them a list of possible attacks from which they would choose 1 to use each turn. This was great for reusability but not great for customization nor did it allow for complex, multi-turn enemy behavior (like charging up an attack to use next turn).

But now that’s all changed and I’ve introduced the EnemyController. With this, enemies get a slew of new potential abilities. Charge-up attacks, fleeing from combat, explode on death and much more.

The Rest

There area also a whole bunch of more minor changes, bug fixes and some changes that aren’t too impressive to talk about but are big code architecture changes that allow for stuff that you’d expect in this type of strategy game. Like spawning new enemies into the current combat. Seems like something that should be easy, but it required a lot of refactoring to get the system able to spawn in enemies all willy-nilly.

Wolf Girl calling in more pups! Those red boxes on that cards are temporary!

So that’s the big stuff. The game is nearing “Feature Complete” and the next few weeks will be focusing on cleaning up the UI/UX mess that has arose from all the rapid prototyping. Looking forward to getting new art and animations from Butzbo soon.

Kick, Punch, Eat Meat Dev Log #1

It is my quest to complete Kick, Punch, Eat Meat and if fortune favors me, turn Robot Monkey Brain into a sustainable venture. Leave a comment if there is any other aspect of this game dev stuff that you are interested in keeping tabs on and I’ll include it in future logs.
Here is what has been happening over the past 4 weeks:

  • Implemented Equipment as playable cards
  • Conducted multiple play tests, gathered a lot of quality feedback (thank you, friends!)
  • Removed Equipment as playable cards
  • Implemented Equipment as items added into Slots on the character. They provide passive effects.
  • Changed the map to a Hex map
  • Implemented Line Of Sight on the map
  • Added Ruins to the map, locations which present the player with special Events
  • Implemented multiple outcomes to events with probabilities used for selecting the outcome of the player’s Choice
  • Recongigering of the Combat UI elements
  • Much balancing of existing Cards, Enemies and abilities
  • Many bug fixes and performance tweaks
  • Progression towards making Robot Monkey Brain into an LLC
  • Researched the Photon plugin for Unity (for future projects)
  • Addressed a performance issue with Instantiating too many cards every time the deck changes
  • Added a number of new Poison card mechanics
An early version of the map with Hexes and their various Biomes. Chests represent Ruins for now and Mountains block movement and line of sight.

Side Quest

Eat all the food in my house before buying new stuff. I’m allowed to buy food that’ll go with something I’ve got an am trying to use up. For example, I have a bunch of granola, so I’m allowed to buy yogurt to eat it with. At this point, I’m getting pretty low on food stuffs and these pickle, salt and coffee ground sandwiches aren’t the best.

Unity Remote 5 not working: Fix

If you are attempting to use Unity Remote 5 on an Android device attached to a PC (and perhaps Mac/Linux) but upon clicking Play in Unity you game goes not show up in Unity Remote then these tips might help:

First, disconnect your Android device from your PC and shut down Unity to ensure you’re starting from a clean slate. This walkthrough also assumes you’ve completed the steps found in Unity’s documentation: https://docs.unity3d.com/Manual/UnityRemote5.html

Enable Developer Mode and USB debugging (or re-enable it)

On your Android Device, enable Developer Mode

  1. Open Settings
  2. Scroll down to and click About <Device> (Mine says About Tablet)
  3. Scroll down to the Build Number
  4. click Build Number many times (after a few times, a message will pop up telling you how many more times to click)

Now that Developer Mode is active

  1. Go to Settings>Developer Options
  2. Ensure Developer Options is toggled On (at the top of the list)
  3. Optional: Enable Stay awake 
  4. Scroll down, under Debugging enable USB Debugging

Now you device should be ready.

  1. Plug in your Android device to your PC.
  2. Open Unity Remote 5 on your Android Device
  3. Open you Unity project
  4. Click Play

You should see you Unity project on your Android device. If not, try shutting down Unity and Unity Remote and restarting each.

Change Unity’s C# Template Code Style

The first thing I used to do every time I’d edit a new C# script in Unity is delete the comments and unused usings which are all included as part of the template. Going through that activity for every new script was bad enough, but on top of that the code style used in the template is pretty far off from what is considered standard for C#. Eventually, I decided it was time to stop my pre-scripting ritual and just make the default template into what I want. So to begin:

Navigate to the ScriptTemplates folder in your Unity install folder.

Route with a typical Windows install: C:\Program Files\Unity\Editor\Data\Resources\ScriptTemplates

Open 81-C# Script-NewBehaviourScript.cs.txt in your text editor of choice.

From here you can edit the file’s layout however you choose. Mine looks like this:

using UnityEngine;

public class #SCRIPTNAME# : MonoBehaviour 
{
    private void Start() 
    {
        #NOTRIM#
    }
    
    private void Update()
    {
        #NOTRIM#
    }
}

Note: You may be unable to save/overwrite the template file if you did not open your text editor As Administrator. Don’t worry, you can just Save As to your Desktop and drag/drop the new version from the Desktop to the ScriptTemplates directory.

Event Delegation in Unity

What is Event Delegation?

“…a helper object, known as a delegate, is given the responsibility to execute a task for the delegator
– Delegation Pattern Wikipedia

Why use Event Delegation?

A good practice when working with Unity (or any framework) is to decouple your UI logic from your game logic. It’s fine to have the UI code reach down to the game logic layer and call methods directly on it but having the game logic layer directly call methods on the UI logic’s layer is, in general, a bad practice because doing so “marries” you to whatever UI you are currently using. So to get around this we can use C#’s Delegates and Events to fire off methods throughout our UI and even on the game logic layer.

How to use Event Delegation with Unity

All we have to do is:

  • create a static Event Manager class
    • Add delegates and events to this Event Manager
  • Listeners will add functions to the events
  • Delegators will fire off the events

The Manager: Defining events

public class EventManager {
    public delegate void EnemyHovered(int laneIndex, int targetRange);
    public static event EnemyHovered EnemyTargetedRequest;
    public static void EnemyTargeted(int laneIndex, int targetRange) {
        if(EnemyTargetedRequest != null) EnemyTargetedRequest(laneIndex, targetRange);
    }
}

In this example we create a delegate with the type EnemyHovered which takes the arguments laneIndex and targetRange. Then we make an event EnemyTargetRequest which is the event that the listeners will subscribe functions to. Finally, there is a static method that can be called by delegators when they want to fire off this event, triggering all the functions that are subscribed to it.

The Listener: Subscribing to the event

In another class we can add the following:

void Awake() {
    EventManager.EnemyTargetedRequest += DoSomething;
}

public void DoSomething(int targetedIndex, int targetRange){
    // do something
}

In this class we define some function called DoSomething that takes the same arguments as our delegate. In the Awake() method we add the function to the static class’s EnemyTargetedRequest event.

The Delegator: Firing off events

In yet another class we can do the following:

public void OnPointerEnter(PointerEventData eventData) {      
    EventManager.EnemyTargeted(_index, _targetCount);
}

Here we’re just using Unity’s OnPointerEnter event as the UI event that will trigger our EnemyTargeted event. Because our Listener class subscribed it’s DoSomething function to the EnemyTargetRequest event when SignalManager.EnemyTargeted is called it will fire off the DoSomething function!

So with this, you can keep all your events off in the static Event Manager, subscribe to them when you need an object to react to an event and fire off the events whenever you need to which allows you to keep UI and game logic separated. You could even have GameObjects subscribe to events and unsubscribe from them as they are created and destroyed which is very useful when these objects are created and destroyed dynamically.

 

Good Enough Guide to Unity’s Unet Transport Layer (LLAPI)

I was excited to see that just as I was getting ready to start my first networked multiplayer Unity project, Unity was releasing their new Unet networking APIs. “What great timing!”, I thought. However, I was a total noob when it comes to working with sockets and communicating over a network and after playing around with Unet’s HLAPI (High-Level API) it quickly became clear to me that I’d have to dive deeper to get the functionality that I was looking for. So I began to read the documentation for the LLAPI (Low-Level API) which was not pleasant at all. After seeking advice and guidance from everyone I found shake down I managed to get everything working, connecting, and sending messages to and fro.

So here is my tutorial on working with Unity’s Unet LLAPI in C# for networking noobs. There are 4 main parts to any socket networking setup, opening a socket, connecting to another socket, sending messages and receiving messages:

Starting a “Host” (or Opening a Socket)

First make a new Unity project, 2D or 3D, it doesn’t matter for this tutorial. Then add an Empty GameObject to the scene and name it Transport. Then add a new C# script to the object and open the script.

We’re going to setup our socket right as the application begins so let’s begin in the Start() method. First thing we want to do is call initialize on the NetworkTransport class (don’t forget to add using UnityEngine.Networking to the class):

public void Start() {
  NetworkTransport.Init();
...

Next we just follow Unity’s documentation and add the ConnectionConfig. For most situations using the default config is fine, so let’s just go with that:

...
ConnectionConfig config = new ConnectionConfig();
...

Up next we need to add a channel and keep the channelId handy so we can use it later for sending/receiving. To do this we’ll add an int member variable to the class (not just the Start() method). We’ll also use the QosType of Reliable when setting up our channel. You don’t really need to know what this means right now (read: I don’t know enough about what this means and I still survive):

int myReliableChannelId; // above Start()
...
  myReliableChannelId = config.AddChannel(QosType.Reliable); // within Start()
...

This next part pretty much just sets the max number of connections allowed on your soon to exist socket:

...
  int maxConnections = 10;
  HostTopology topology = new HostTopology(config, maxConnections);
...

and finally we open the socket. One of the main stumbling blocks when trying to understand the LLAPI based on Unity’s documentation is that many thing are just named poorly. For starters, there is NetworkTransport.AddHost(). This doesn’t actually add a “Host” like the HLAPI does. This command actually just starts up a socket, I’m pretty sure they should change the name of the method to AddSocket, but who am I?? When we start the socket we have to tell it which port to listen to and in this case we use port 8888. Also the AddHost() method returns an int which is the “HostID” but screw that name we’re going to call it what it is, a SocketId. This SocketId also has to be accessible from other methods in this class so let’s put it up with the channelId:

int socketId; // above Start()
int socketPort = 8888; // Also a class member variable
... // back in Start()  
  socketId = NetworkTransport.AddHost(topology, socketPort);
  Debug.Log("Socket Open. SocketId is: " + socketId);
} // closing curly for Start()

And with that we have our code which sets up a socket! It’ll run right away when you click the Play button in Unity. You should see the debug message appear in the console, probably with the socketId of 0. It’s not that cool yet but we’re getting there.

Connecting to the socket

Once our socket is open we use it to connect to another socket, typically on another device. We can worry about getting another device in the mix later. For now, let’s just write our Connect() method.

int connectionId;
...

public void Connect() {
  byte error;
  connectionId = NetworkTransport.Connect(socketId, "localhost", socketPort, 0, out error);
  Debug.Log("Connected to server. ConnectionId: " + connectionId);
}

We need to keep the connectionId available to all methods because later we’ll use it to send messages. NetworkTransport.Connect() … connects us to another server (Hey! They did a proper job naming that one!). We pass in our socketId, the ip for the remote device (in this case we’re just connecting with ourselves, like a long weekend alone in the woods), the socketPort of the remote machine (same as ours in this case), 0 (I forget what this is but whatever), and if there is a problem we get an error out.

The Unity documentation mentions that we can check the error with:

if (error != kOk) // wat?

But I have no idea what kOk is and judging by all the red squiggles it certainly isn’t a byte. If you know what kOk is please tell someone (preferably me) we need to figure this out people! Basically, I just include the out error parameter because I have to.

I used my Android phone as the remote device but you can use another computer if you have one available. But for now you can do most of your testing by connecting to your own socket (I’m sure there is a rude joke in there).

Lastly, go into Unity and add a UI button and set the OnClick event to fire off our Connect() method. If you don’t want to do that I suppose you can just call Connect() at the end of Start() after our code that adds the socket. That would be good enough for now if you don’t want to make the button.

Sending a Message!

Finally (half of) the thing we actually want to do! Here we turn a string into a stream of bytes then send those bytes out our socket connection.

public void SendSocketMessage() {
  byte error;
  byte[] buffer = new byte[1024];
  Stream stream = new MemoryStream(buffer);
  BinaryFormatter formatter = new BinaryFormatter();
  formatter.Serialize(stream, "HelloServer");

  int bufferSize = 1024;

  NetworkTransport.Send(hostId, connectionId, myReliableChannelId, buffer, bufferSize, out error);
}

Quick run down: Declare another (unused) byte variable called errorCreate byte array called buffer and set it’s length to 1024 (this is the max length of our message when it is in byte form). The next 3 lines do the conversion from string to byte array. I don’t know the details about it, but it works, so it’s good enough. We also send over the size of our buffer byte array as an int (which is bufferSize). Lastly we put all the stuff together, starting with out class variables hostId, connectionIdand myReliableChannelId then adding the rest.

Now that we’ve got our SendSocketMessage() method you can go back into Unity and add a UI button to fire off the method on the buttons OnClick event.

Listening for NetworkEvents (or Receiving a Message)

Last part! We can send a message to other connected devices but now we have to make our application do something when it gets these messages. Otherwise we’re just shouting into the void. We need to always be checking for new messages coming in so this portion is added to the Update() method.

void Update() {
  int recHostId;
  int recConnectionId;
  int recChannelId;
  byte[] recBuffer = new byte[1024];
  int bufferSize = 1024;
  int dataSize;
  byte error;
  NetworkEventType recNetworkEvent = NetworkTransport.Receive(out recHostId, out recConnectionId, out recChannelId, recBuffer, bufferSize, out dataSize, out error);
...

All we’re doing is declaring all the variables we need then setting up a NetworkTransport.Receive() method. Almost all those variables are assigned as a result of a message being received (all the parameters that begin with out). The recBuffer contains the byte array message that was received, while recNetworkEvent is an enum with 4 possible event types:

  • Nothing – When no messages are received.
  • ConnectionEvent – A socket connection is made.
  • DataEvent – A message is received.
  • DisconnectEvent – A device that was connected as told us it is closing the connection.

We’re going to use these event types to decide what to actually do with the messages we receive. So we’re going to continue to add on to our Update() method with a big ol’ switch statement:

...
switch (recNetworkEvent) {
  case NetworkEventType.Nothing:
    break;
  case NetworkEventType.ConnectEvent:
    Debug.Log("incoming connection event received");
    break;
  case NetworkEventType.DataEvent:
    Stream stream = new MemoryStream(recBuffer);
    BinaryFormatter formatter = new BinaryFormatter();
    string message = formatter.Deserialize(stream) as string;
    Debug.Log("incoming message event received: " + message);
    break;
  case NetworkEventType.DisconnectEvent:
    Debug.Log("remote client event disconnected");
    break;
}

So based on the type of network event we have a few different debug messages display.  With the event type Nothing we do… nothing. This message comes in every Update() that a message of some other type is not received so we can ignore it. With ConnectionEvent we just want to be notified of the connection, but in a game you might do something like load a player prefab or display some text that a new player has connected.

DataEvent is the real meat and potatoes. This is where a message is received from a connected device and our application has to do something based on that message. Since our SendSocketMessage() method currently only sends a string we’ll only include code to handle string messages received (it’ll still try to convert any bytes into a string, so if you send something other than a string you’ll get an error or a garbage string (probably? Didn’t try it.)).

You can see that in the DataEvent case we’re doing almost the same thing as we did in the SendSocketMessage() method but instead of making a string into bytes, now we’re making bytes into a string. Once the message is back in a string form we display it as part of a debug message. Bam! Message Received!

Lastly there is the DisconnectEvent type. I don’t do anything with that event type here except log it to the console but you can image using this event as the time to do things like remove a player’s prefab, or display a disconnect message on screen.

Try it out

That should be all you need to get up and running. You have an application that, on startup, makes a socket available for connections. With the press of your Connect button the application uses it’s socket to connect to another device’s socket. Pressing your Send Message button will blast a string message from your socket to the remote devices socket and the remote device will receive the message, unpack it and display it in the console.

I did my testing initially just having my computer running Unity connect to it’s own socket, just as a way to rapidly test things. Because of this I saw the connect message in the console 2x, since one event was made for each side of the connection. After I got everything working like this, I changed the “localhost” to my computer’s IP address then built the project and sent it to my Android phone. I would then run the application in the Unity editor so I could see the console and I used the app on my phone to connect and send the message. It was really rewarding to hit the Send Message button on my phone and see the message appear in Unity’s console on my PC!

Expanding

This post is already super long, but I just want to give some final thoughts and extra tips.

How do I use this to make a game?

You can have another switch statement that executes different methods or series of methods based on the message received. So getting a message like “ChangeToNight” can trigger a method that changes the time in your game environment.

Does the message have to be a string?

No! It can be any object, all you have to do is serialize the object in a similar way to how we serialized the string. For instance I have experimented with sending JSON messages so that I can transport more complex objects. Using JSON .NET for Unity made this super easy.

Where can I read more about sockets?

While trying to figure all of this out I was directed to Beej’s Guide to Network Programming. It’s pretty advanced, written for C++ and I didn’t read much of it, but the What is a socket? section helped clear up some of my confusion about sockets.

I hope this helps some people who want to dive into Unity’s new networking API but don’t know a thing about network programming prior. If you are an experienced network programmer and have noticed things that I am wrong about, or things that could be expanded upon please let me know and I’ll update this guide.