I’ve read a few posts on bitwise tilemapping and I think they kind of over complicate the idea so I wanted to take a whack at explaining it.

The basic idea is that, instead of needing to meticulously place every tile for a given map (slow, manual), you can mathematically calculate what tile should go where (fast, automatic!) depending on its surrounding tiles. This means you can basically say“land here” on a map and it will place the proper land tile by accounting for the surrounding tiles. This is how most level editors with“brushes” work. The“brush” is just calculating the proper tile to use for a given connection. It may seem like magic but this is pretty easy to do on your own!

Imagine you have a single tile and imagine a data structure that says whether a tile exists in a given direction from that tile. So if I’m checking the North, South, East, and West directions, my data structure would be“NSEW”. For each of those directions, a tile can either exist at that position or not, meaning each direction can be either True (tile exists) or False (no tile).

So a tile with only a tile to the north of it would be“TFFF”. To only the south and the west would be“FTFT”. Look familiar? This is just binary! So TFFF = 1000 = 8 and FTFT = 0101 = 5. Hence, every unique combination directions yields a unique number from 1 to 15. You can also rearrange your“data structure” to make the values different — so instead of NSEW you could use SENW or something like that. Note that your bitwise numbers would change, but as long as you are consistent with how you“encode” the directions you’ll be fine.

With a direct mapping of unique directions to unique number, you can build a simple look up table to tell your game what sprite should go where. So for the following tile map:

A calculated bitwise index then maps to a sprite. Note that you can also easily check corners by just expanding your data structure to include those checks, something like N|S|E|W|NE|NW|SE|SW

Why“Bitwise”?

Although what I presented suggests that you just convert from binary to integer, the term“bitwise” comes from the fact that older ways in which you did this likely used actual bitwise operators for determining the correct tile (to conserve memory). So“North” was likely hardcoded as 1000, South as 0100, East as 0010, and West as 0001. If a tile existed in those directions, you would“logical or” combine them, so NORTH | SOUTH = 1100 = 12, which then maps to a sprite value. You could also still do it this way!

Why not just count?

In doing the operation“bitwise”, you’re assigning unique powers of 2 to every possible neighbor tile, and hence ensuring that (bitwise) combinations of the neighbors are unique and non-repeatable. If you just assigned random numbers, you run into two issues:

Tile direction combinations aren’t guaranteed to be unique. If you just used the numbers 1-4 for directions North(1), South(2), East(3), West(4), different directional combinations would yield the same result in the created lookup table. For this example, a tile with a neighbor to the North(1) and South(2) would yield a lookup value of 3, the same value as a tile with a neighbor only to the East(3).

If you were smarter about your assignment and did something like North(12), South(13), East(18), West(45), you would generate unique table lookup values, but they wouldn’t necessarily have any meaningful relationship to each other. Assigning directional values in a bitwise manner allows them to maintain a small memory footprint and be deterministic and open for operations — if you want to check if a tile exists to the North of a tile with a bitwise value (and you’re storing the bitwise value), you can just use if(value & NORTH > 0).

Networking feels like a massive task to take on as an indie and the truthfulness of it is that it becomes harder and harder the later you start trying to implement it. This is to say that, if you plan on having your game be networked, you ideally start implementing network functionality from day one.

The reason for this is that, when you’re working with networked code in a P2P context, you’ll want to be able to use the same code that executes local game logic to be the same code that you call when you need to execute an event that you receive from the network.

Otherwise, you’ll end up having two functions for every call, one that works locally and one that the network calls that then calls the local function. The second method is totally viable but the former allows for much cleaner code. When you receive a call from the network, you just call the same function that you would normally call to move something locally.

To elaborate a bit more, here’s how I’m doing this in my game.

To start, I just write down what the action I went sent over the network. These are usually“big actions” that affect moment to moment play like moving, shooting, spawning, etc. Once you know the action, you need to come up with your own network packet type that your game understands.“Network Packet” sounds both scary and archaic, but it loosely translates to“data structure that your game understands and can be easily sent across a network”.

The goal here is to send the minimum amount of information required to still successfully produce the required action on the side of the person you’re send to. You want your packets to be small so you can ensure that you are using a lot of data over the network due to any sort of interruptions.

Thinking about what this is can be difficult depending on the action you’re implementing, but, if you’re reusing client code of network code it’s pretty easy — it’s likely just the function parameters! So, let’s assume I’m trying to move something, and get started with my move function.

When I move something, I do the moving (in the omitted code), then send out an event that states that something has moved. This event is subscribed to by my class P2PHandler, and when it receives this event calls the requisite function that bundles up the network packet to be sent:

A few notes on this before moving on. At points NOTE A/B, you can see that I’m kind of“casting” my function parameters to different types. I’m converting a list of Tiles to a List of Vector2’s and converting the moved interactable to just be an int. What I’m doing here is serializing my parameters into a format that can be serialized by Unity.

Serialization is a whole topic in and of itself, but the core idea is that Unity cannot remember every detail about any type you declare, and instead only“knows” about a specific set of types outlined here. It is possible to make it so that something like Tile could just be easily sent across the wire as is, but often time optimizing for serialization can lead to a lot of excess code and headaches as you may have to jump through extra hoops to get at simple parameters.

What I prefer doing for bigger types like this is to just send a integer reference that points to the object on the client side, and make sure that those tables mirror each other on initialization.

To actually send this data, I use P2PMessage which is defined like so:

So a P2PMessage is basically a key, and then a P2PAction that is serialized in the P2PMessage constructor. P2PMove in this case is the container for the data that is necessary to properly interpret the move action on the client side. So here’s the last bit of code from above that does the packing and sending:

So you package up your parameters and send off the message. I’m using Facepunch.Steamworks to do this, which makes sending P2P data really easy. Here’s the code for that:

public void SendP2PMessage(P2PMessage message)
{
//serialize the whole message
string serializedMessage = JsonUtility.ToJson(message);
//convert to bytes
var data = Encoding.UTF8.GetBytes( serializedMessage );
//loop through all members of the current lobby and send the data
//lobbies in my game act as a sort of server
foreach (ulong id in GetLobbyMemberIDs())
{
// don't send the P2P message to the player who sent the message
if(id == PlayerID){continue;}
//call the Facepunch.Steamworks DLL
Native.Networking.SendP2PPacket( id, data, data.Length );
}
}

Once you send the packet, how do you get it? In the same class that sends the P2PMessage, I’m also subscribing to P2PEvents:

Which brings us back to the same class that sent the message originally, but on the other side of the wire! For now, the P2PHandler class both sends and parses events, though it may change if things become to bulky. When it recieves a message, it is parsed like this:

This code calls the move function for the proper intractable, and now both clients are in sync! I didn’t realize this would be as long-winded when I set out to write about some P2P stuff, but I hope this helps out anyone looking to implement P2P networking in their (Unity) games! I will say that this envato tuts post was a godsend, and most of the ideas here are an outgrowth of that. I highly recommend people who are interested in this read over that, because it provides a great high level overview of P2P networking. Until next time!

Introduction

Like most game developers, I’m very interested in getting my game on Steam.

Like most indie game developers, I lack any sort of access to the resources/knowledge that would easily clarify for me what“being on Steam” actually means.

It’s also hard to bridge this gap in knowledge because, though a lot of Steam’s functionality is well documented, knowing where to start in that massive store of documentation, as well as what ties all the disparate pieces together, can be difficult. On top of that, general discussion about the Steam platform happens on a private forum that is only open to developers that have been approved for the platform already through either Steam Direct or a Valve referral. So for someone starting out, looking for answers to basic questions can be difficult.

Because of this, I wanted to write a high-level overview for people who are just setting out, trying to get Steam working with their games. Specifically, I wanted to dive into the Steamworks SDK, the Valve-provided software library that gives you access to things like Workshop, Leaderboards, Achievements, and so on.

Steamworks is already well documented by Valve, but it’s written from the perspective of someone who is using the native C++ library and likely already knows how all its functionality intersects. If this isn’t you, even better! What follows is for that second person, someone who is making a game in a higher-level language and just wants a simple Steamworks integration (it exists, I promise!). More specifically, this post is targeted at people using C# in some for or another, but ideally using Unity as their game engine.

Steamworks

Steamworks is two things. First, it’s the developer portal for managing everything about your game’s presence on Steam, from changing your game’s banner pictures to managing sales to listing controller support, etc. Secondly, it’s an SDK Valve provides that lets you interoperate with everything else Steam provides like Workshop, Leaderboards, Servers, Achievements, etc. Keep that order in mind! The SDK“is only required to upload your content to Steam”, [source]. This means you can totally forego tackling nearly all of the aforementioned stuff of the SDK and just focus on how to use it to get your game on Steam. However, the SDK does offer a lot of other great, useful functionality. So let’s get it up and running!

But, if you’re a C#/Unity developer, we’ve got a little work to do. Because native C++ headers/source aren’t compatible with Unity, we need to use a wrapper library that allows us to integrate the SDK’s functionality. Such a wrapper library would allow us to use high level C# functions to call low level C++ functions. In the past, the go-to library for this was Steamworks.NET, which is exactly as it sounds: Steamworks implemented with .NET. However, it is exactly as it sounds, to a fault.

Steamworks.NET provides one-to-one mapping of Steamworks functions to C# functions, but that means you need to fully understand Steamworks as a library to get anything done. For someone who is just getting started and wants to do simple tasks, this can be a lot of work. If you want to do something more complex, Steamworks.NET requires you to essentially write your own utility wrapper on top of their wrapper, which seems to defeat the purpose of a wrapper in the first place.

Facepunch.Steamworks

Due to these limitations and other reasons, Facepunch Studios (of Rust and Garry’s Mod fame) set out to build a better Steamworks library for C#/Unity with the explicit purpose of making everything easier.

It gets rid of the need for tons of code scaffolding to do basic (and complex) tasks in Steamworks, which lets you focus on just“working” with Steam. It’s also currently being used in Rust, which means it is production tested on one of the highest user-volume games on Steam. Complex tasks are abstracted away into simple function calls, and the library itself is only three files so it doesn’t cause any extra bloat. I can’t emphasize enough how much more of a godsend it is for someone starting out; it’s truly wonderful. The creator of Steamworks.NET has even said that Facepunch.Steamworks is “basically what I wanted the next step of Steamworks.NET to be” and that it “should probably be the default choice for most people”. Steamworks.NET is still there for people who want to implement their own version of what Facepunch.Steamworks essentially is, but in my opinion, if it’s good enough for Rust it’s good enough for me. So how does it work and what’s so special about it? Let’s get started.

Getting Started

First off, It’s easy to think that you need to be an approved Steamworks developer to start working with Steamworks, but the truth is that you can start using the SDKright now without needing to have gone through the process of registering. This is because Valve provides developers with a test“AppID” of 480 that you can program against.

The AppID

An AppID is how your game is uniquely identified on Steam (and Steamworks), and is one of the primary things you get when you get your game properly registered. It“stakes out” your section of Steam/Steamworks and allows you to wholly own anything associated with that AppID. AppID 480 corresponds to“SpaceWar”, a demonstration game Valve made and open-sourced that shows of some of the capabilities of Steamworks (you should check it out!).

While a unique AppID is nice and obviously required for your game at some point, the test AppID (480) allows you to work with Steam’s services as if your game were live. Your real AppID should be substituted in once you get one, but in the meantime, 480 will serve you just fine. That said, probably don’t create a server with the name“My‘Trademark Pending Game Name’ Server”.

Downloading and Importing Facepunch.Steamworks

So, let’s download the Facepunch.Steamworks library (FP lib from now on), knowing we can properly test it with AppID 480. Head to the releases section of its Github page (the library is fully open source, MIT licensed) and download the latest release. Once you extract the .zip file you should see a few folders. The READMEs go into more detail, but you essentially need to copy a small set of these files over to your Unity project, depending on your platform. The Facepunch.Steamworks files are the lib itself, and the steam_api files are platform specific files that contain the actual Steamworks SDK. Your Unity directory should look something like this after your files are imported (assuming Windows x86/x64):

The steam_appid.txt is literally a text file with only your AppID in it, so for our cases it should just be a text file with 480 in it, no quotes. The .dll, .pdb, and .xml files come from the Release folder of the downloaded .zip file, using whichever .NET version you’re targeting. For Unity, 3.5 is fine. If you’re starting out with a clean project, Facepunch has also graciously provided a small test project that does a lot of this for you that you can you to start off your project.

Unity

Once you’ve copied all the lib’s files to their proper directory locations, you’re basically setup! All we need to do now is to write some code to get everything integrated. I’m going to copy over the test file from the test project and just abbreviate it here for clarity’s sake.

And… that’s it! If you attach that script to a GameObject in your scene and enter play mode, you should see yourself in Steam as playing“Spacewar”, and see the console print out some basic Steam information about you (if not, make sure you are actually logged onto Steam).

Life with Facepunch.Steamworks

Capabilities

Once you’re set up, accessing deeper Steam functionality is pretty easy since the FP lib covers and wraps almost all parts of the standard Steamworks SDK. The question does still stand though as to“what” that stuff is, so here’s a small list and some descriptions of what you can work with (in the FP lib):

Servers - Create servers using a player’s client or run a headless server elsewhere. This is used for ping-sensitive games that have steep networking requirements (think Dota 2, Overwatch, etc.)

Lobbies - These are essentially“staging rooms” for players that act as a meeting point to exchange SteamIDs or other user info.

Friends - You and your player’s friends on Steam!

Workshop - Upload/Download content from Steam Workshop!

Leaderboards - Create and maintain global leaderboards for your game.

Achievements - Create or award achievements.

Networking - Send P2P data to clients.

Steam Cloud - Save data to Steam Cloud! This is very useful for Saves.

Voice - Interact with the Steam voice API for in-game chat.

Stats - Set Steam-side stats for a given player.

The best way to see how to use a given function is to see if there is a working example of it in the Facepunch.Steamworks test project (NOTE: this is not the Unity test project), and model the implementation in your game.

Most of these features are documented further in the the FP lib’s wiki, but only a few classes really properly filled out. If you don’t see any example, check out the library’s code and see if the function is implemented at all. If not, see how far you can get implementing it on your end, or just submit an issue to the library. The Facepunch team is generally very responsive, so they can let you know if something is being worked on or not and even guide you on how to give back to the community, if you go the route of implementing it yourself.

Subscribers and Callbacks

When working with the FP lib (or even the native API), you’ll notice it’s not always as easy to work with as simply calling something like Client.Instance.SteamId. This is because the Steamworks SDK (and FP lib by extension) makes heavy use of asynchronous functions so that your game doesn’t hang every time you want to do some non-trivial interaction with Steam. Without async calls, you would have to wait for the main Steam server to respond before any more of your code could execute, which is obviously error-prone and frustrating, as far as play experience goes. So, to use the library, you will need to get familiar with the idea of delegates and callbacks. It may be a lot for someone just getting started, but it’s easy to understand once you grasp the core idea. I’ll give an example.

If you want to get a list of all the lobbies in your game using the FP lib, you would do this:

client.LobbyList.Refresh();

Notice how there is no return or assignment happening there. If that’s the case, how do we actually get what we just requested? In Steamworks, once this function is called, the Steam backend gets everything ready for you, and then sends you some data via a“callback”. Almost literally, Steam“calls you back” to say“Hey, your data is ready! Here!”.

To receive the call, we need to pick up the phone, or as it’s actually known,“subscribe”, to the callback. This is done by defining a function that takes in the data the callback provides. Sometimes, no data is provided, and the callback is used primarily as a“hook”, or a way to know that it’s OK to resume. Once you’re inside your callback handler, you can safely continue operation. Here’s an example:

void Start()
{
// Subscribe to the proper event by defining the function you want to be called when OnLobbyJoined is called by Steam.
client.Lobby.OnLobbyJoined += OnLobbyJoinedCallback;
// Call the function
Native.Lobby.Join(LobbyID);
}
void OnLobbyJoinedCallback(bool success)
{
// If we're inside here, the callback has properly fired!
// We can check the status of this callback by seeing if the bool "success" that Steam passed in is true or false
if(success)
{
// If there were no errors, we can safely call functions in here that require a specific circumstance
// For example, we can now print out the id of the Lobby's Owner
Debug.Log(client.Lobby.Owner);
}
}

Understanding this pattern will be immensely helpful as you use the library, as well as for understanding what Steamworks is actually doing when you inevitably peek at the actual documentation. If you want a more in-depth discussion of how this works, I definitely recommend Valve’s documentation on the topic, as well as some bits on the Steamworks.NET website.

Moving Forward

From here on, you’re free to implement whatever you want! Valve has no requirements here, but if you are on the platform it is obviously in your best interest to engage with it and its community in the ways Valve has made available. Once you get registered with Steam Direct you can simply swap in your AppID and carry over any Steam functionality you implemented with the test AppID.

I really hope this is helpful to anyone looking to get started with Steam, and I obviously strongly recommend people check out Facepunch.Steamworks on Github. If you feel so inclined, try contributing in small ways like filling out the documentation, or if you want something meatier to chew on submit an issue and ask if anything needs doing. If you have any questions about this article, feel free to reach out to me @kkukshtel. I’d also love it if you followed my game on Twitter @isotacticsgame or sign up for the newsletter.

]]>http://blog.kylekukshtel.com/welcome
http://blog.kylekukshtel.com/welcomeWed, 16 Aug 2017 00:00:00 -0400I’ve been wanting to start up a more formal design crit/design blog for a while now so am taking the first step in trying to maintain one.

What I’d mainly like to do with this blog is carve out a space to air my own thoughts on game development as well as try to talk more formally about design aspects of other games. I’ll also try and post small dossiers on topics that I’m interested in at a given time.

I’m also currently working on a game of my own (that’s what’s in the header), so expect to see some thoughts here about the process of working on that. Think of this blog as somewhere in between a personal blog and a devlog. Let’s get going!