Dec 2, 2016 - 2D Overhead Traversal

Comments

Why are open world games so fun? A lot of reasons: a huge, interesting world, lots of things to see and do. But one important mechanic that support this, and which pops up a lot when people talk about open world games, is traversal. What’s that?

In a nutshell, it’s the way the player moves around the world, getting from A to B. This sounds (and often is) mundane, which would be a problem for open world games with huge worlds, which is why these games often have interesting, advanced techniques to get around. You see this a lot on 3D open world games.

When it comes to great traversal mechanics, two games often get mentioned: Spiderman 2 and Just Cause 2. In the former, you use your web to swing around the city, and in the latter, a unique combination of paraglide and grappling hook lets you fly around quickly. Both take some skill to pick up, but the result is a fast and cool way to get around their game worlds.

spiderman 2just cause 2

Other games also get mentioned, but I’ve noticed that they are all 3D games, and the traversal mechanics described are 3D mechanics. I’ve been thinking about how traversal might work in a top-down 2D game; a lot of the things that work in 3D simply aren’t there. Like:

  • Great views: open world games are fun because they have great scenery to enjoy. Many open world gamers have anecdotes of climbing up that big mountain to get a spectacular view, or seeing majestic buildings and landscapes in the distance. In a top-down 2D game this simply isn’t possible.

    oblivionarkham knight

  • Vertical movement: lots of traversal is about cool ways to navigate the environment, the vertical axis in particular. Jumping, climbing, spelunking, grappling, gliding, these are all things that are really awkward if not impossible to pull off in top-down 2D. Incidentally, these things are possible in 2D platformers, which is why the 2D platformer equivalent of open world games - Metroidvania - all feature novel movement mechanics, and not just the jump.

    metroid bomb jumpworms ninja rope

  • An extra dimension for navigation: seems obvious, but let’s look at an example of a house. In 2D, usually you can just walk in, out, and around it. But in 3D, you could climb up the walls over it, jump off the roof to the ground, maybe go under it through a tunnel or basement, and so on. For multi-storey buildings or more complex architecture, 3D has even more options. You can fake these things in 2D but in 3D it is much more natural. This means that you can more easily pack in a very content-rich area in a small space, and have the player easily and quickly navigate it. Platforms, lifts, stairs, balconies, trap doors - all very easy to do.

    quake 2minecraft caves

So is it possible to create immersive, rich open worlds in 2D overhead, just like the 3D ones? If it’s possible it’s certainly a lot harder. Let’s go back to first principles: what makes traversal fun? There’s a great article called Traversal Level Design Principles, which covers lots of the points:

  • Fun to get around
    • Interesting mechanics: if getting around is trivial, it’s not very interesting. But make it mechanically challenging, and getting around becomes a game of its own.
    • Lots of ways to traverse. Variety is the spice of life; if there’s just one path from A to B then it’s not very interesting. But what if there’s a bunch of detours, shortcuts, maybe even secret paths? That’s interesting.
    • Make the journey interesting. You know road trips? Hours of driving through featureless terrain isn’t most people’s idea of fun. But what about a road trip with friends? It makes all the difference. As I’ve mentioned, 3D games make the journey interesting by having spectacular views, which is hard to pull off in 2D, but there are many other methods to try, like filler content (think about car radios, for example).
  • Fast travel. Sometimes the trip is just too dull, and most players would rather skip the tedium. That’s ok; having either instant travel or faster travel is a great way to skip the boring bits, especially when you’re backtracking.

Once we start thinking about the principles behind traversal and what makes it fun, it’s easy to see a lot of common techniques already in use, many of which are applicable to 2D overhead as well!

  • Vehicles, which are both more challenging to use and faster than regular movement.

final fantasy airshipsgta

  • Shortcuts. Things like portals and secret passageways are already common in 2D overhead games. One very subtle yet clever implementation is the ledges in Pokemon games, which are one-way obstacles, strategically placed so that during your first trip you cannot pass through them, but on your way back you can jump over them. This removes the tedium of backtracking without compromising the experience when you are first exploring an area.

pokemon ledge

  • Multi-storey Levels. 2D overhead can do multi-storey architecture, even though it doesn’t do it quite as well. Still, it’s a great way to pack lots of content in a limited amount of space, which makes it very useful for 2D overhead where the viewport is constrained. Separate storeys can be linked with portal techniques disguised as stairs, elevators or sometimes even holes.

earthbound stairsfigaro castle

  • Overworld. 2D overhead games have actually portrayed huge worlds for a long time, using an old trick: the overworld. That is, when travelling between key locations, the game scales all the way out, representing vast distances in a small space. The player gets a sense of the size of the world, even though it’s smoke-and-mirrors, and very little of that world is actually fleshed out. A very well established hack!

ultima overworldfinal fantasy overworldchrono trigger overworld

  • Signposts. One of the most un-fun ways to traverse is when you are lost, so signposts help prevent that. Not just literal signposts though; in Final Fantasy 6, Game Design Forum’s Reverse Design shows how the game cleverly uses its NPCs to give direct, subtle, even ironic directions to its game world and plot. It also helps engender a sense of place - the sense that this place is a living, breathing and self-consistent entity which has complex relations between itself and the player.

pokemon signpostsfinal fantasy 6 NPC directions

  • Traversal tools. Who says 2D overhead games can’t have awesome traversal tools? It’s not common but there are examples of special tools that are either challenging to use or get the player to inaccessible places. Adding places that are out-of-the-way, hard to reach makes it all the more rewarding to actually get there, and makes it all the more fun to explore the world.

zelda hookshotpokemon acro bikechocobo in shallows

With all these techniques, it should be possible to create open-world 2D overhead games with great traversal mechanics. As I’ve said before, it always pays to study how games have approached these design problems, and it really helps you make better games!

Apr 7, 2016 - A Review of Overhead 8-Directional Shooters

Comments

To make better games, one can look for similar games (not only in the same genre), and see what worked and what didn’t. One game I’m making is C-Dogs SDL, an overhead 8-directional shoot-em-up. A while ago I started looking for similar games, looking for cool features I can steal, but also for where they weren’t fun, and why. Bertram25 (of Valyria Tear and OpenDungeons) encouraged me to elaborate on some of my conclusions in a blog post, so here it is :smile:!

What are Overhead 8-Directional Shoot-em-ups?

8-way

This mouthful of a sub-genre doesn’t get mentioned a lot. In a nutshell, it’s where you can move and shoot in 8 directions, from an overhead perspective. Sounds awfully specific, so people simply describe these games as top-down shooters or 2D shooters, which lumps them together with other sub-genres like twin-stick shooters (Geometry Wars), scrolling shooters (Gradius, most of the Touhou games), run-and-guns (Contra), even games like Asteroids (which have tank-controls, and includes the Strike series or even the on-foot sections of 2D GTA). Fans of those sub-genres will understand how different they are; each has different design lessons to learn.

Small differences in game mechanics can mean big changes in gameplay. I think overhead 8-directional shoot-em-ups strikes a sweet balance between movement and shooting, between tactical play and arcade action. The 8 directions means some, but not complete, freedom in engaging enemies around you. As a player, you will:

  1. Move into an ideal firing line
  2. Shoot in one of the 8 directions

But also:

  1. Make tactical decisions whether to stay back and shoot in one direction, or charge in and shoot in many directions
  2. You can freely move to dodge incoming fire, but doing so will affect your line of fire

It is this close relation between moving and shooting, and limitations in both, that creates very dynamic gameplay. Great games in this sub-genre understand this, and design accordingly: map design, to weapons, to enemy AI. Let’s compare with its sibling sub-genres:

  • Twin-stick shooters: here you can aim in any direction, not just 8. Movement is much less important, since you can shoot at any target from any position. The implication is, for 8-directionals, indirect-fire weapons like shotguns and seeking weapons are much more powerful. The limits in aiming also affects map design; maps with walls that aren’t in the 8 directions are more awkward for 8-directionals.

    crimsonland

    Because twin-stick shooters often use analog sticks for aiming, they are imprecise over long range, and often feature auto-aim. Some twin-stick shooters use the mouse to aim, which is extremely precise, and instead feature recoil. This means that twin-stick shooters’ primary tactical consideration is range. For 8-directionals, there’s a greater emphasis on positioning; range can also be a factor, but often produced by projectile speed. Recoil and auto-aim are less important.

  • Scrolling shooters: only being able to shoot in one direction has a huge effect on game design. Map design is minimal; many scrolling shooters have no walls or obstacles at all. Instead, it’s all about enemy design, including their movement patterns, firing patterns and so on. The challenge is to shoot at enemies moving and firing unpredictably before they overwhelm the player.

    xevious

    A lot of 8-directionals go the tactical, emergent gameplay route, where AI is relatively simple and independent. This has its perks, for example you can play with crowd control with simple, predictable AI, but scrolling shooter’s patterns have a lot to offer too. Bosses really benefit from complex firing patterns.

  • 4-directional shooters: the most similar to 8-directionals. What does the lack of diagonal directions mean? More movement, faster action, and enemies that can shoot in the 4 directions are much more dangerous. Weapons that can shoot diagonally or seek are much more powerful.

Early arcade/console games

Overhead shooters have a long heritage; one of the first arcade games ever, Gun Fight, had players duelling with a two-stick control scheme - one to move, the other to aim and shoot. Through the 80’s game makers added features - powerups, different weapons - and tweaked game mechanics, learning valuable design lessons.

Front Line

Front Line

An early Taito game, this is a really underrated one with some neat ideas. You play as a soldier who can shoot a gun or throw grenades, the animations are hilarious, and you can even drive tanks! Nevertheless, it has significant flaws too:

  • Bullets come out of your gun barrel on your right hand, which makes sense but makes aiming really hard, especially since enemies can come from all around
  • Enemies are really hard to pre-empt. This is long before game designers learned to use antics. Instead, the enemy AI literally performs actions at random, including shooting at you.
  • There’s not enough meaningful difference between the gun and grenade; most of the time they are both useful. I think shmups with their screen-clearing “bombs” got it right.

Some of these flaws may be intentional, given that it’s a quarter-munching game at heart. It seems that the arcade version is much more superior to the NES port. The pacing in the NES port is really slow too.

Super Contra and Jackal

Super Contra Jackal

This duo of Konami-made classic NES games share many similarities, and are distinctive, quality entries in the subgenre. Not only are these games heaps of fun, they are also super polished, with great music as evidenced in the covers and remixes for Konami games in general.

These games really do a lot with the subgenre, with a great variety in enemies, powerups and weapons:

  • Enemies include weak-and-slow infantry (that, in Jackal, can be run over!), fixed turrets, vehicles of various speeds and strength, even fixed-path planes. This gives the player a lot of choice in how to engage. The action is frantic so making these choices really puts pressure on the player.
  • The weapons that both you and the enemies use are interesting. There are slow-moving but accurate bullets, faster but fixed-axis bullets, indirect-fire grenades, spread shots, even homing missiles. Some of these keep you away, some keep you moving, some force you to stop and evade. The games are at their hardest when multiple bullet types are in play, where their combination is much more lethal.

One downside, especially compared to their contemporaries, is that the pace is slow. Since both games have 1-hit-kills, stray bullets often send the player running in the opposite direction. Two possible improvements are: auto scroll, and removing 1-hit-kills.

Another significant flaw is that your player is quite close to the direction of scrolling, making you vulnerable to new enemies that appear suddenly. This is especially a problem in Jackal. Perhaps this is due to the arcade heritage (cheap, sudden deaths means more quarters), or to the NES’s low resolution.

Heavy Barrel

Heavy Barrel

A late NES game, less well known but not for its quality, because it’s really awesome. Coming after seminal titles like the aforementioned Konami games and the influential Commando, Heavy Barrel benefited from the design lessons from those games. As a result this game sports many cool and powerful weapons, virtually all accessible in the first level. In fact the first level is a real tour-de-force demonstration of how awesome shooters can be.

  • Less than half a minute into the first level, you are accosted by two enemies: fixed machine gunners and fast-running soldiers. This sets up an interesting tactical challenge, as the machine gunners zone you out, whereas the fast runners can approach and threaten you. There are at least two ways to deal with this: quickly take out the machine gunners so you have space to evade the runners, or patiently take out the runners while staying out of the machine gunners’ zones.
  • All weapon pickups in the game (including grenades, which are cool in theory but overshadowed by the main weapons) have a fixed amount of ammo (think Metal Slug). It’s an effective system that discourages player spamming, and keeps them moving with the promise of more ammo.

Mercs

Mercs

This game is basically a more polished version of the earlier Commando game (and similar ones like Ikari Warriors and Gun.Smoke). As a result it’s pretty straightforward and repetitive: lots of enemies, lots of shooting. A few points are worth mentioning:

  • 3 player co-op. Shooters, especially multi-directional ones, are great for co-op because you can help each other out by shooting at enemies threatening the other players - that’s more ways to interact and co-op.
  • Lots of enemies use grenades. Grenades are interesting weapons - because they take time to land and explode, they give the player a bit of time to react thoughtfully, keeping them on the move and the pace of the game up.

90’s Innovation

Overhead shooters really blossomed in this era. Enabled by technical advancements and more discerning players, game makers looked for all kinds of ways to enhance shooters, taking ideas from other genres and games, as well as simply adding more polish to what’s become an established genre.

Meanwhile in PC land, shooters saw lots of innovation from diverse game makers. Not only were these shooters creative, many were made with loving care; games like C-Dogs and its ilk were made by people who grew up with and genuinely adored these games.

Smash TV

Smash TV

Perhaps the quintessential 8-directional twin-stick shooter; this enhanced remake of Robotron: 2084 distils everything great about overhead shooters into a no-nonsense, crazy-hectic arena shooter with a fantastically-absurd premise. Shoot endless hordes of enemies, get big powerups, fight ridiculous bosses, collect unending piles of cash. It’s simple and unsophisticated: the weapon selection is pretty standard, the enemies even more so - there are ones that run towards you, ones that run towards you faster, some that occasionally shoot you, others that run towards you in funny patterns.

Unfortunately the game suffers from a big flaw: uneven pacing. In between the ceaseless enemies and unpredictable powerups, it’s very hard to control difficulty and player experience. Sometimes normal levels with unfortunate powerup placement can be way more brutal than boss fights. This is a problem we’ll see again in a closely related game: Crimsonland. I think the game could really benefit from something like the AI Director; unfortunately this wouldn’t be developed until a decade later.

Tapan Kaikki + Assault Trooper

Tapan Kaikki Assault Trooper

These two games share more than a few things in common. They were both made by Finns, were released around the same time (1995, 1997), have tank controls, and are chock full of 90’s shooter goodies. Tapan Kaikki has some of the most elaborate gore effects of any game: enemies explode in gibs, which leave blood trails, which you can kick (and leave more blood trails), and did I mention you can get your feet covered and leave bloody footprints? Assault Trooper on the other hand is full of interactivity and cool ideas; everything’s destructible, even the trees and walls. Both are very interesting examples to study.

Both games are unfortunately hampered by their tank controls - that is, players mainly move forward and rotate via keyboard controls. Both have strafing functions but they are quite awkward to use. Like other games with tank controls, aiming, especially at far targets, is challenging. Navigating twisty passages is likewise difficult. Both games feature lots of tight, indoor areas which are bad with tank controls; I remember dying endlessly in Assault Trooper because my grenade didn’t go where I wanted it to, and bounced back from a corner. My opinion is that tank controls should be avoided in indoor, fast-paced shooters for these reasons.

But don’t let that colour your perception of these games; they are flawed gems that are seriously underappreciated.

Strike Series + Fire Fight

Strike Series Fire Fight

Compared to the last two games, these adapt well to tank controls. Recall that the two problems with tank controls are moving around in tight spaces and aiming at far targets. Both are about flying aircraft in wide-open spaces, rather than tight indoors. Both also solve the problem of low accuracy with interesting weapons and mechanics. In Strike’s case, there is a limited amount of auto-aim, which is cleverly explaned as having a “gunner”. In Fire Fight, there’s the cool “swarmer” weapon which fires a spread salvo of homing missiles.

Strike also has the interesting fuel mechanic, which is basically a draining health meter and you must scour the map for extra fuel to stay alive. It’s a good way of countering an otherwise slow-paced game, but this sort of resource mechanic has its problems too.

Crimsonland

Crimsonland

Coming after an era of gory shooters, Crimsonland plays like an unpretentious distillation of late-90’s game design sensibilities. It’s a twin-stick shooter with tons of everything: weapons, powerups, simple swarm enemies, an interesting perk system, and lots of blood decals. It’s great fun and uneven too, and it offers plenty of lessons:

  • Overhead shooters are fun! The huge range of weapons, explosions and sounds make shooting endless zombies satisfying, all the time.
  • There are so many weapons and they are unique. From the standard shotguns and machine guns, to rockets with explosions, homing weapons, piercing weapons, even ones that bounce around. Crimsonland proves that 2D shooters have the prettiest and most interesting weapons, because you can see and appreciate all the bullet patterns. Balance is very poor though.
  • The powerups, even though they are even more unbalanced than the weapons, are lots of fun, and are at the core of its gameplay. Once players have mastered the basic game, it becomes more about desperately negotiating overwhelming swarms of enemies to get to crucial, game-changing powerups, only to die inches from them. Critics say this makes the game luck-based, but there’s no denying its excitement.
  • Unfortunately, the game is severely lacking in content. Its huge range of weapons, powerups, perks and enemies serves as its content, via its quest mode, and while that’s lots of fun, after the whole game is unlocked there’s not much else to do. To me this proves that there’s only so much you can do with shooting things in an open arena; you really need content in the form of maps to create interesting spaces for unique gameplay.

Ultimately, I think Crimsonland is a great case-study on how less-is-more, at least for balance. There are so many weapons, powerups, perks and enemies that balance is simply impossible. Games that don’t rely on the number of weapons for content would do well with less, if they want to be balanced, for example. One type of game that thrives on variety however is roguelikes, and sadly Crimsonland missed this boat on becoming a game like Binding of Isaac or Nuclear Throne.

Modern Overhead Shooters

The core design of overhead shooters has been rather stagnant after the 90’s. There has been a lot of innovation at the fringes, like cinematic plots, but the basic mechanics are much the same. Titles like Alien Shooter, Shadowgrounds, and the recent Helldivers are all great, polished games, but their gameplay is often considered “retro”, and in many ways are less ambitious in their design as some of the creative entries from the 90’s.

Binding of Isaac + Nuclear Throne

Binding of Isaac Nuclear Throne

One exception is the games that marry overhead shooting action within a rogue-like framework. Exemplified by Binding of Isaac, but in this regard surpassed by Nuclear Throne, the marriage does a lot of justice to shooters - the myriad combinations of weapons and enemies typically seen in roguelikes makes these shooters more enjoyable than many traditional shooters, much as Crimsonland’s numerous weapons had.

This mixed-genre benefits the rogue-like aspect too; just as different weapons and enemies forces you to play the game differently, each run-through is a unique experience due to the items and powerups you happen to get.

The Future?

I believe we’ll continue to see a steady trickle of great overhead shooters, because the genre is simple unadulterated fun. But there’ll always be room for innovation, whether that’s taking ideas from other, even unrelated genres, but also revisiting old games that had neat ideas but didn’t explore them to their fullest, or for whatever reason weren’t influential.

The same could be said for any genre, really. We ought to look back on games from the past, because they have a lot of lessons to teach, both what to do and what not to do.

Jan 27, 2016 - How to Write a LAN Server

Comments

Recently I had to write a LAN game server/client for C-Dogs SDL. I was surprised at how little information was available, so I thought I might document my solution here.

The Problem: Which IP to connect to?

Most people who have made, or attempted to make, network-multiplayer games will know that there are two ways to get two game instances to connect to each other:

  1. Directly, by entering the IP address of the other game instance, or
  2. Using an online “server list”, which is basically a list of IP addresses constantly updated

Most “game server browsers” actually download lists from several known locations, a fancy way of doing no. 2. But no. 2 boils down to picking an IP from a list, which the game then uses to connect to directly anyway - no. 1. The point is: to connect two games, you need the IP address.

In ages past there were dial-up modems where you could connect using phone numbers, or IPX which is similar to IP but has different addresses. The protocols have changed but the problem is the same.

But how do games see each other on a LAN? Somehow many LAN-enabled games can scan and find servers running on a LAN, and avoid having to enter IP addresses manually. They also do this without having to access a remote server list.

Broadcast Address

Fortunately, the solution is provided by the network itself: in IP networks, you can send messages to the broadcast address (255.255.255.255) and the network will pass the message on to all hosts on the network, that is, the LAN. Servers that understand the broadcast message can then reply back, alerting the broadcaster to their presence and address.

This is very simple in concept but takes a surprising amount of code to implement; IP broadcasts are only available for connectionless, datagram sockets, and most game network services either use TCP or a connection-based scheme to make things easier, so chances are you can’t just shoehorn the broadcast functionality into your existing network handler. Therefore, the LAN “scanner” service will have to run on a different port, using UDP. The procedure is this:

  1. The game server itself runs on port A, but a “listen” socket runs on a fixed port B.
  2. The client scans for LAN servers by broadcasting a UDP packet on port B.
  3. Servers receiving the broadcast scan reply back, optionally including the information that a game server is running on port A.
  4. The client, upon receiving the reply, connects normally to the IP and on port A.

Full credit for this solution goes to Lee Salzman, of Sauerbraten and ENet.

To illustrate, I’ll provide a code walkthrough by implementing a basic chat service using C and ENet, an excellent cross-platform game networking library. But the same approach will work for your chosen language/framework, because we’re dealing with socket networking for the most part. A full working server/client code example is available here: https://github.com/cxong/ENetLANChatServer

The Server

The chat server will run the following:

  1. Bind a UDP port for listening to broadcast scans
  2. Bind another socket for the chat server itself
  3. In a loop, we’ll check for:
    • Scans: we’ll reply with the chat server port
    • Chat server events: as we’re a chat server, we’ll just resend the text message to all clients

First, the initialisation:

enet_initialize();

A common mistake is to forget to initialise ENet itself; you’ll run into mysterious errors with the other ENet functions if you forget. Of course, like a good programmer you should always check your error values, but I’m omitting those in this post for brevity.

Next, start the listening socket, on port 34567 (pick any port that is likely to be unused):

ENetSocket listen = enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM);
// Allow the port to be reused by other applications - this means we can run several servers at once
enet_socket_set_option(listen, ENET_SOCKOPT_REUSEADDR, 1);
ENetAddress addr;
addr.host = ENET_HOST_ANY;
addr.port = 34567;
enet_socket_bind(listen, &listenaddr);

Now start the chat server itself (supporting up to 16 clients):

ENetAddress addr;
addr.host = ENET_HOST_ANY;
addr.port = ENET_PORT_ANY;
ENetHost *host = enet_host_create(&addr, 16, 2, 0, 0);

Finally, in a loop, check for scans and also perform chat server logic. First the listener: since we’re dealing with raw sockets, we’re using the old select()/recv() combo to do non-blocking I/O.

// The following code belongs in a function; we're using return to step out

// Use select to see if there is data to read
ENetSocketSet set;
ENET_SOCKETSET_EMPTY(set);
ENET_SOCKETSET_ADD(set, listen);
if (enet_socketset_select(listen, &set, NULL, 0) <= 0) return;

// Construct a data buffer (ENetBuffer) to receive the data
// Because we know exactly how big the scan packets will be (1 byte),
// we'll only set aside enough memory for that.
// If you want bigger payloads, adjust this to suit.
// If you want dynamic payloads, or you want to receive any payload just for the heck of it,
// use a suitably big buffer.
ENetAddress addr;
char buf;
ENetBuffer recvbuf;
recvbuf.data = &buf;
recvbuf.dataLength = 1;
if (enet_socket_receive(listen, &addr, &recvbuf, 1) <= 0) return;
// At this point we've received a packet; it would be a good idea to check its contents
// to make sure it's what we're looking for (like a magic number) and not random data,
// but all we're doing is sending a small reply so let's just do it, hooray for laziness!
// Reply to scanner client with the port of the server host
// We know the client address from the enet_socket_receive function
ENetBuffer replybuf;
replybuf.data = &host->address.port;
replybuf.dataLength = sizeof host->address.port;
enet_socket_send(listen, &addr, &replybuf, 1);

Then the chat server itself; as we’re going for maximum laziness simplicity, we’ll just broadcast the client’s data packet right back at all clients. Since there’s no validation or bounds checking, in a production environment this would be a gaping security hole :smile:

ENetEvent event;
if (enet_host_service(host, &event, 0) > 0)
{
	// Whenever a client connects or disconnects, broadcast a message
	// Whenever a client says something, broadcast it including
	// which client it was from
	char buf[256];
	switch (event.type)
	{
		case ENET_EVENT_TYPE_CONNECT:
			send_string(host, "New client connected!");
			break;
		case ENET_EVENT_TYPE_RECEIVE:
			sprintf(buf, "Client says: %s", event.packet->data);
			send_string(server.host, buf);
			break;
		case ENET_EVENT_TYPE_DISCONNECT:
			send_string(host, "Client disconnected :(");
			break;
		default:
			break;
	}
}

Don’t forget the helper function, send_string():

void send_string(ENetHost *host, char *s)
{
    // +1 for the null-terminator
	ENetPacket *packet = enet_packet_create(s, strlen(s) + 1, ENET_PACKET_FLAG_RELIABLE);
	enet_host_broadcast(host, 0, packet);
}

Finally, don’t forget to tear everything down at the end:

enet_socket_shutdown(listen, ENET_SOCKET_SHUTDOWN_READ_WRITE);
enet_socket_destroy(listen);
enet_host_destroy(host);
enet_deinitialize();

The Client

The client is conceptually simple:

  1. Send UDP broadcast scans to look for servers
  2. Once we’ve received a reply, connect to that IP as a normal ENetHost
  3. In a loop:
    • Get keys typed by the user; when they press enter send what they typed
    • Check for messages from the server; if there’s any print them out

It turns out that getting keyboard input and performing network I/O together is pretty hard; we’ll use rlutil, a sweet header file that contains some utility functions for console programs. We’ll only be using nb_getch(), to get keyboard hits in a non-blocking manner.

First, as always, initialisation:

enet_initialize();

Scan for the server, on port 34567 (where the server is listening)…

ENetSocket scanner = enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM);
// We need to set a socket option in order to send to the broadcast address
enet_socket_set_option(scanner, ENET_SOCKOPT_BROADCAST, 1);
ENetAddress addr;
addr.host = ENET_HOST_BROADCAST;
addr.port = 34567;
// Send a dummy payload; you can make your own (larger) payload
// but make sure to update the server code if you do
char data = 42;
ENetBuffer sendbuf;
sendbuf.data = &data;
sendbuf.dataLength = 1;
enet_socket_send(scanner, &addr, &sendbuf, 1);

…and wait for the reply:

// Note that enet_socket_receive is blocking;
// for a non-blocking version use enet_socketset_select to check before receiving
ENetAddress addr;
enet_uint16 server_port;
ENetBuffer recvbuf;
recvbuf.data = &server_port;
recvbuf.dataLength = sizeof server_port;
enet_socket_receive(scanner, &addr, &recvbuf, 1);
// If the message is correct, we should have received sizeof(enet_uint16) worth of data
// Once again, error checking would be nice here, but omitted for brevity
addr.port = server_port;
// Now addr holds the exact host/port to connect to

// But first, shut down the scanner because we're done with it
enet_socket_shutdown(scanner, ENET_SOCKET_SHUTDOWN_READ_WRITE);
enet_socket_destroy(scanner);

Now that we have the server’s address (addr), start our chat client host:

ENetHost *host = enet_host_create(NULL, 1, 2, 0, 0);
ENetPeer *peer = enet_host_connect(host, &addr, 2, 0);
// Wait for 5 seconds for connection to succeed
ENetEvent event;
if (enet_host_service(host, &event, 5000) > 0 && event.type == ENET_EVENT_TYPE_CONNECT)
{
	printf("Connected\n");
}

The chat client is now connected; in a loop, check for the user’s typed input, collecting the keys and sending them off on enter/return:

// Keep a keyboard buffer outside the main loop
char buf[256];

// ... inside the loop

int k = nb_getch();
if (k == KEY_ENTER || k == '\r')
{
	// If we have something to say, say it to the server
	if (strlen(buf) > 0)
	{
		send_string(peer, buf);
	}
	memset(buf, 0, sizeof buf);
	printf("\n");
}
else if (k > 0 && strlen(buf) < 255)
{
	// Hold on to our message until we press enter
	buf[strlen(buf)] = (char)k;
	// Print the typed character out; otherwise the user doesn't know what was typed
	printf("%c", k);
}

The send_string() helper function is different for the client because we’re only sending to the server, but otherwise it’s exactly the same:

void send_string(ENetPeer *peer, char *s)
{
	ENetPacket *packet = enet_packet_create(s, strlen(s) + 1, ENET_PACKET_FLAG_RELIABLE);
	enet_peer_send(peer, 0, packet);
}

We also need to check for server messages, and print whatever we get:

ENetEvent event;
if (enet_host_service(host, &event, 0) > 0 && event.type == ENET_EVENT_TYPE_RECEIVE)
{
	printf("%s\n", event.packet->data);
}

Don’t forget to tear down everything at the end:

enet_peer_disconnect_now(peer, 0);
enet_host_destroy(host);
enet_deinitialize();

The End

Phew! Hope that all makes sense. As I’ve said, the concept is simple but the code is verbose because we’re pretty deep into socket code, with all the select()s, recv()s and socket options, thinly wrapped in ENet which makes it slightly less verbose. There’s a working server/client project available here, with the proper error checking mess for you to get started. Good luck!