Long time no update! Well, by my standards anyway, since I'd like to update every week... that dream has been crushed ever since college started back up. Still, I could have updated last week, but when I get stuck into something new I just want to do and more and more without stopping, and that's been the situation for the past 2-ish weeks.
That said, there's way, way more material than I could possibly cover in detail, so I'm just gonna hit the highlights and stuff that might be important for future me reading back over these write-ups!
BUT BEFORE THAT... check out the video, 'cause most of what I did this month was visual. And I'm finally uploading updates on Youtube now... no idea why I wasn't doing that before.
It probably seems sudden to anyone who's been watching this, going from "UE4 default sunny sky and rectangle cover" to "foggy, moody city with old cars and something that looks like the outside of a strip club you'd never want to go to" in one update. Well, I assure you it's felt like quite a long process for me.
On the one hand, maybe I'm spoiled, because obviously I didn't have to make all the assets from scratch thanks to a plethora of high-quality assets available for purchase online. On the other hand... I'm just one person. The idea of lighting, adjusting asset materials/meshes/collisions/etc., designing level layouts for PvP and PvE, setting up cover, setting up spawns for weapons/pickups/players, implementing special interactable objects for each map, adding environmental sound, testing them repeatedly to make sure they don't break, etc., etc... for 8 maps minimum (that's the amount I've committed myself to for game launch)... is daunting to say the least.
However! I've been very careful in the design phase of all this not to bite off more than I can chew, so we're taking things one step at a time.
Step one for me was getting a couple basic maps setup so I can make sure performance won't be an issue and I can test out things like the cover system in a more "organic" environment (for example, objects like cars that aren't uniform height and have open areas the player should be able to shoot through, etc.). Hilariously, the end of my last article mentioned not getting caught up on visuals, but it's sort of hard to avoid sometimes. I kept thinking "I should work on adjusting numbers for the movement and shooting mechanics", but then I'd also think "crap, it's hard to know if this will feel right without having environments like what will be in the final game." So, in the end, I bit the bullet and set up some levels where I can be sure I'm testing gameplay and performance in an environment closer to what production will be like.
Ok, that was a lot of blabbering. I never know who all watches the videos and who doesn't, so have some screenshots of the levels I've been working on:
Since I already know at least one person will look at this and wonder what the performance targets are... 1080p, 60 FPS at "High" settings with an i5 processor and a GTX 1060 (or "equivalent" specs) is my unofficial target. If I can do better, I'll do better, but that to me is pretty modest.
Now, the pictures of the foggy city level are of what I'm calling "Retro City". That's going to be one of the multiplayer maps in the game, for both PvP and PvE. I'm using it primarily for gameplay and performance testing at the moment. I've been pleasantly surprised that I can set all the lighting in that map to dynamic without dropping below 60 FPS, provided I utilize optimization options such as the Fade Distance (which effectively turns lights off after a certain distance, potentially saving significant amounts of compute power). Lights won't all be dynamic in the final map, of course, but man does it save a lot of time not having to rebuild lighting... I might also not have much/any Global Illumination in the final build because I like how it looks with just the fog, but... well, I'm getting ahead of myself now.
The interior area with the blue and red color scheme is the "Night Club", which doubles as a multiplayer map and a Lobby. It's actually quite a bit bigger than that one room, but that's all I've worked on so far. I'll be filling it up with a bunch of NPCs I already have planned as well as some fun (and some, shall we say, "stimulating") events to keep players entertained while waiting on the match to start. I also just like the idea of players having a bit of time to interact outside of the main game; I think that really adds something to a multiplayer experience.
I had even considered, while writing the initial design document, having a "Destiny" style of "player hub", where players would load in to a random server with other players when they start the game. But, uh... well, I'm trying not to go broke while paying for dedicated servers for my indie multiplayer game... I'm sure you understand '^^.
I also got some work put in to starting a menu system. It has three simple options for now, PvP, Loadout, and Quit. I mostly wanted to lay the framework for the final design, so you can see elements of that in there now. Switching cameras when picking different options, and the characters you can see idling about, for example. In the finished game, there will be a couple NPCs you actually interact with in the main menu, and they even have small storylines of their own that progress as the player progresses. They also give the player quests and just engage in normal dialogue.
The goal is ultimately to add some real personality to the game; even though this is a multiplayer game, I'd really like it to have a backstory and some personable characters people can relate with. So I want to utilize time spent outside of playing "the main game", such as in menus and the lobby, to make that work. I hope we'll be able to see that come to fruition over the next year or so!
For now, though, the Menu system itself is quite simple. Here's a screenshot of what it looks like:
All very barebones at the moment, but it works for what I'm trying to do right now. Btw, the little running magical girl icon on the PvP screen (that's Madoka for those not up to snuff on your magical girl anime) is definitely going to be in the final game. Not Madoka specifically, of course, but some OG character. There's literally no way I'm not keeping that idea in. In fact, I'll probably have whatever artist I commission make like 20 more animations and have her strewn all over the menus like it's "Where's Waldo?"
While the menu itself is simple, there's quite a bit going on in terms of what the menu functionally allows the player to do. For example, while making the loadout menu, I finally set about figuring out how to get data sent to a remote server... since, you know, I'm not installing the server app on client computers :P Luckily, I didn't have to rent any server space to do that; there's a really handy tool called "ngrok" which gives you a public URL to send stuff to a localhost server. I used it to forward HTTP requests directly to CouchDB running on my main machine and it works like a charm!
The other thing is that we have to create/join lobbies, and that was a bit more tricky to get working. I ended up handling almost all of that logic in the GameInstance class, since it's the only one that persists all the way until the game is shut down. UE4 has a whole set of interfaces for this stuff in a module called the "OnlineSubsystem", so I spent a solid two full days learning all about that and how to use it. It appears to be platform-agnostic as well, and I can get it working with Steam, though I haven't yet fully figured out how much I'll be relying on UE4's system and Steam's SDK for different things.
My instinct tells me it's best to do the general stuff, like searching for and connecting to lobbies, in UE4 on the off-chance I ship to other platforms, and just use the Steam SDK for like... achievements and voice chat and whatnot. So that's the route I'm taking at the moment.
As for handling the logic of travelling to the Lobby and setting up things like map selection and voting and such... GameMode class. It's your friend. It only exists on the server, so clients can't tamper with it, and there are some really intuitive functions you can override to get things happening when you want them to. SPEAKING OF WHICH, I found out something I'd never known before, since UE's documentation is kind of awful sometimes (I still love you though):
The PostLogin() function only fires when a PlayerController is connecting to a server for the first time. It doesn't fire when a Server is seamless travelling a bunch of clients; in that case, HandleSeamlessTravel() fires. Kind of important to know! And you know what else? There's a PostSeamlessTravel() function which fires after Seamless Travel has been handled. Also kind of important to know!! Even the fabled God of UE Networking himself, Cedric Neukirchen, did not mention this in the Compendium! And we all know if it's not in the Compendium, no one will know about it!
... unless you read this article, that is ;) My advice for other developers? Bite the bullet, look over the documentation for useful-sounding functions, and test out the ones you don't understand. If you're using Intellisense, hovering over the functions can sometimes give some really excellent information that isn't found anywhere in Epic's online documentation, so that's another useful tool at your disposal.
This stuff is a bit tedious at times, but now that I've done it, I can look back and say it's actually not that hard once you get it. I have to hand it to this engine, it's REALLY well structured for session-based matches... though admittedly, a lot of the knowledge is very much specific to Unreal Engine.
Alright, I'll just touch on a few more technical points here that I think are important:
--> Creating an array of PlayerControllers on the GameMode and adding/removing players who enter/exit the server was very useful for things like updating HUDs. For example, every time a player joins, I can call a Client RPC on every valid PlayerController in the array to update their HUDs where it shows how many players are in the Lobby.
--> One should be really careful and pay attention to what is being stored on the Server's copy of the PlayerController vs. the Client, because it can get confusing. Generally speaking, my rule of thumb has been to store important values and handle everything gameplay important on the Server exclusively, and if the client needs the information for something like a HUD update, I use a Client RPC. For example, the GameMode holds MapNames and MapVotes, and those are ONLY modified on the Server. If the client needs to know how many votes a map has, the Server can send it to them and from there they can do whatever they want with their local copy because it won't affect anyone else.
--> I mentioned this before, but PostLogin() vs. HandleSeamlessTravel() is important. For example, when players first connect to a Lobby, I use PostLogin(), and there are specific things that need to be handled for a player first logging in. But after that, it's all Seamless Travel, to the match map, back to the lobby, to another match, and so on until the player quits to the main menu. PostSeamlessTravel() has proven useful as well; I found that my Listen Server would crash when I tried to initialize certain things on the PlayerController, and it was because I was doing it prior to HandleSeamlessTravel being finished. Putting that logic in PostSeamlessTravel() fixed everything without my having to use some awkward solution like Timers.
I don't know how much this article shows it, but there were a ton of different things going on these past weeks. I start one thing, immediately notice something else that needs to be done, and so the vicious cycle continues! However, I'm happy to say that at the moment things are pretty focused.
This next week I'll be working out the kinks in my Lobby system, making the transitions smoother with things like Loading Screens, and so on. Once I've got that all working, I'll hopefully still have a couple days to return to the core gameplay mechanics and smooth those out a bit.
What I'd really like is to have a fully playable game (not complete, just playable from start to finish) by the end of May, with a fully working lobby system integrated with Steam and some sound fx. That's what I'm shooting for, anyway... wish me luck!
- Flash <3