It’s been too long since we went to Paris (in 2021) for me to properly caption these cars. But hey, I did take pictures, so let me at least post them.
Author: emr
Practical Godot Networking: MPEVMVP technical discussion
Godot’s High Level Networking tutorial (and book chapter) do a great job of explaining a peer-to-peer networking setup. However, many games want to be server-authoritative, and to set up a multi-area game, you sort of need to. Luckily, you can use the same primitives to build a server/client game. This is just sort of a brain dump of my notes that may be helpful in navigating the MPEVMVP source. Feel free to post any questions you have about it; I love to talk about this stuff.
The technical requirements that deviate from the basic tutorial they hand out are as follows:
- Server-authoritative client/server game
- Multiple levels that players can switch between
- Players are able to join a match in progress
In case you haven’t tried it, the project is here: https://github.com/eamonnmr/mpevmvp. The gameplay is similar to Asteroids (and, well, similar to Flythrough.Space): it uses RigidBodies to simulate movement, you can shoot other players to force them to respawn, and you can press “J” to initiate a hyperjump after you’ve pressed “m” to select a star system from the map.
Godot’s Networking Golden Rule
A remote call (rpc, rset) is going to be called on the remote node with the same node path. That includes name of the node, the name of the parent, etc, all the way to the root node. You can set a child node’s name with set_name
but if a similarly named child already exists, an @number will be added to your node. This is a major source of bugs for networked projects, so be careful. You cannot set a node to a name with @ in it. So in effect, you cannot use Godot’s auto-incremented names (since they append @increment) to sync between the client and the server. For this reason, I used a uuid library for generating node names.
The need for the same structure on client and server despite the fact that the server held a whole universe while the client only cared about one system is a major source of complexity in the codebase.
Server Authoritative
I implemented the Client and Server as singletons that exist on both sides. The reason for this is that it makes it really readable; when the client needs to send something to the server you write Server.rpc
and when the server needs to send something to the client, you use Client.rpc
. Besides this line of communication, I’ve used rpc
and rset
within various nodes to update and alter the client versions of themselves. This always happens inside an is_network_master
block, to ensure that it’s being called on the server version of the game.
The one thing we do need to gather from clients is input, and for that each client has a PlayerInput node, network_master’d to them. They rset_id input up to the server. The server copy of the player nodes looks at this remote copy of the player_input to determine it’s behavior, then pushes its state back down to all clients.
Multi Level
Suppose you want to have multiple different levels/worlds/rooms in your game. The trick is that you need to mesh the following two constraints:
- Node paths need to be the same between client and server (see discussion above)
- The server needs to have different node paths for each level
The trick, then, is to send the client to the new level by loading the appropriate level and making sure it’s named appropriately. There’s one wrinkle though: different 2d physics worlds need to use a Viewport class, but you don’t want to add additional viewports on the client for performance reasons (tried it, it was way too slow.) My solution was to add an extra layer of nodes called “universes” in the comments which are a Node2d on the client but a Viewport in the server. They are managed on the server by ServerMultiverse and on the client by ClientUniverse. Client Universe cares about a single “universe” child whereas ServerMultiverse handles multiple children.
Sending Entities/Switching Levels
In order to join a match in progress or switch to a level that already has stuff in it (or, indeed, switch a player into a level) we need a robust way for the server to move fully-formed nodes to the client. Godot does not provide a generic “send this node” method, so we need to write one for ourselves. The approach I took was:
- Assume that the ent will be instanced from the same scene that the ent on the server is
- Write a “serialize” and “deserialize” method that allows it to dump a dictionary with all of its important state and recreate itself from that dictionary.
- Make sure the node on the client side is assigned the same name as the one on the server side.
So when a client’s level is switched, they dump the current level and recreate the new one by loading in the scene and then, node by node, deserializing the state sent from the server. As it turns out, this means that any state can be synced freely, and it enables us to dispense with the lobby entirely and let players join and leave at will.
Sync In Multiple Levels
Each level owns the process of syncing its state to clients in that level. Scenes within the level can declare a method that serializes their state for a net frame, and the level gathers all of those up and sends them. The client receives the frames from the server, and the individual scenes use the content of those frames to interpolate their position. To save bandwidth, I only do this for ships and guided projectiles, everything else moves deterministically. This whole process is derived from the teaching of (and better described by) this video.
Player Lifecycle
Because we’re using the player’s presence in a level to determine if we should update entities in that level for that player, when a player’s avatar is destroyed the world seems to stop for that player until they respawn. This might be desirable in some games, but I think most games at least want to show the player the immediate seconds after their own demise. So what we do is replace the player with a ghost.
Tooling & Workflow
GDScript is based on Python 3 and the most basic syntax resembles it. ‘func’ in place of ‘def’, no ‘self’ and no list or dict comprehensions or other advanced features. It feels like the python of basic python tutorials. However in exchange for this, you get one thing python 3 does not offer: true static typing. In Python 3 you can offer a type hint for a function argument but it is not truly enforced. GDscript enforces the types at compile time and boy does it ever catch a lot of bugs. You also get the ability to define classes with typed members, similar to what you get in Python with Pydantic. Overall I like gdscript and the things I miss aren’t dealbreakers.
The lack of a vi mode for the editor hurts. I know I could just use the godot plugin for vi, but I actually really like staying inside Godot’s editor. Despite the slightly crowded layout, it’s really very nice. The autocomplete to node paths is a killer feature that makes dealing with complicated trees less of a pain.
Conclusion
Building a multiplayer game in Godot is possible but by no means easy. The high level multiplayer API despite its gotchas works well, but you need to implement the sync logic yourself. This shouldn’t be too surprising as games have very different needs when it comes to net code. I hear that a similar mechanism for frame based sync and lerping is going to be more built-in in godot 4, which would be sweet. The puppet system (which I initially used; you can see a version in the tutorial) seems to be useful only for very low latency situations, so I regret that it’s a first-class feature because it may lead people down a rabbit hole of net code that will not work for most games.
Kenwood 3010 Repair
It’s been at least a decade since I’ve serviced this box. The volume dial developed dead zones and the light won’t turn on. In addition to corroded contacts, I think it may have a dead bulb and/or a blown fuse. I’m going to open it up, clean up the dust, clean the contacts with Deoxit, and see if I can determine what else might need replacing. I found a service manual here (free account required.)
The two fuses are easily located. I don’t see any leaky capacitors, which is a good sign. I tested the two visible fuses in-situ and both read the same as shorting the contacts, so I assume they’re good. Next step was to clean the dust out and apply Deoxit to the pots and switches.
With some trepidation I powered it up. No light bulbs and there are still some deadzones in the volume knob, but I’m able to pick up FM stations. I’d probably call that a success but I’m not sure where I’m going to put the thing yet so I might as well go the distance and try to fix the bulbs before I screw it back together. I’ve seen enough mixed messages about the dead zones that I’m a little afraid of doing more harm than good by repeatedly cleaning the main pot.
I found replacement lamps from this ebay seller. When trying to replace the bulbs, that’s where my lack of experience really started to show. The bulbs where wired in like this:
Two of the bulbs are on fairly long wires which give you enough slack to pry the connectors off and squeeze the connectors onto new bulbs or splice the wires. The middle bulb, however, does not afford you enough slack to pry the connectors off, so I cut the leads from the old bulb and attempted unsuccessfully to splice the old leads to the new leads. As a hail mary, I crammed the bulb into the socket anyway, figuring that the narrow wells that admit the wires should force them into contact. And I was right! All three bulbs lit up.
And with that (and a desk our neighbor didn’t want anymore) the setup is complete. I have a Bluetooth connector so that I don’t need to plug in my phone to use it; it’s now fully integrated into the 2021 music ecosystem. Not bad for a forty year old piece of hardware. And it’s still plenty loud.
MP EV MVP Retro
What I’ve learned from breaking my own rule.
I remade a game again
EVMVMVP is the awkward initialism for my latest project; a multiplayer EV-like. You can download it here, and look at the source code here. I know I said I shouldn’t do it, but I really wanted to learn Godot and having a multiplayer server with multiple levels seemed like a really interesting problem to tackle. Implementing a bunch of stuff I already know pretty well but in a new engine and language has been a fun ride. I’ve jotted some notes down about the project so far. I’ve saved a deep technical discussion of Godot for another post.
Using an engine is well worth it
After flythrough.space I decided that I wasn’t going to build too much from scratch next time, not was I going to fight against tooling. The options I considered for FTS where Panda3D and BabylonJS. However over the course of that project also tried out Unity and Godot for small side demos and ended up liking Godot (and it’s permissive license and thriving community) enough to go all-in. In retrospect this was the absolute right move and I regret nothing.
Working With Onyx’s Sprites
I’ve been staring at these sprites on and off for something like fifteen years, itching to put them into a game. The original models used to render them are long gone, but Onyx (in a tutorial) explained how to separate out the engine glows. Working with these sprites feels like stepping out of time. They’re from the 90s. There are dithering tricks here I wouldn’t even imagine. They use a tiny palette but they’re so damn weighty. Present. Metallic when they need to be, plastic when they want to be. They tend towards the Star Wars / Used Future look. They invite stories to be written about them. And the planets are just absolutely lush too. Something about that limited palette…
Testing with real people is essential
I’ve been nagging more people to play this one. On the one hand, it’s much easier to convince someone to play your game if you can play it with them. On the other hand, you really need to do that testing or you will (like I did) find out that the sync method you’re using is totally busted and you need to replace it with interpolation. Furthermore, you’ve got no idea if your game is fun to anyone but yourself unless you subject it to ruthless testing by people who will give honest feedback. It becomes very easy to get settled in and work around horrible UI issues you’ve coded because “well, I know how it works.”
The ability to test solo is essential
Wrangling people for a test is hard. You need to be able to fire up an instance of your server and client with minimal effort or you’re going to wait too long and leave a bunch of bugs that you’ll be scrambling to fix when you finally get people around to test with. And absolutely nothing is more frustrating than the stars aligning for a test only to have a showstopper rear its head at the worst possible moment.
Procedural Generation
I had a conversation with a coworker about EV games and roguelikes. They made a claim that I’m not sure is true but definitely opened my eyes-they thought that the star maps in EV games probably had been procedurally generated-once.
Actually hand-crafting a full EV map is a bit of a process. One thing I never finished doing in FTS was populating all of the systems.
Meanwhile, Mag Steel glass has developed a really cool universe generator spreadsheet. I figured I could leverage it to make a map. Traditional EV games require you to specify exactly who spawns in what star system and FTS carried on that painful tradition. For this one I had simpler rules; factions had starting locations and then grew “influence” where planets (or stations) would belong to them and their ships would spawn. If two areas of influence overlapped, they’d fight.
Document enough for people to get up and running locally
Port forwarding is a lost art. There was much grumbling when my friends and I went to go start a game of Valheim; luckily I’d learned to properly port forward as part of this project! If you need a server for people to play your game, you can’t rely on your master server; you’ve got to give people an option to join localhost
and put it in your manual/readme. Having images in the readme also helps show people what your project is about; this is especially important for games.
You don’t get cross platform for free
Using cross platform technology does not absolve you from cross platform testing. All of your target platforms might have the same features but they may all have different bugs for you to work around. I’m developing on linux out of what is probably just bloody mindedness at this point, so when I did my live demos on windows I often learned exciting new things like ‘your sound exports are busted’ or ‘only one computer can be assigned to a given port by a given router’ or ‘you need to version bump the editor for correct mac exports.’ Guess which one of those lead to an incredibly embarrassing platform bug report!
Video Tutorials are worth it
Part of my commitment to overcoming my stubborn hangups was relenting and watching video tutorials. I still strongly prefer written tutorials as a medium but the content is moving to video. For example:
This (and the followup on extrapolation) gave me enough to totally re implement my networked movement.
Working In Public
I post progress updates on discord channels full of fans from the old days, and regularly demo the game with friends. This has been a source of motivation and helped me stick to a more iteration focused (and less “well, I’ll go off for a month and make all of the models/textures/features”) work habit. I’m not sure I’m going to do this for every project; part of why I did it for this one was I wanted to spur participation and that didn’t really happen. Very few people who I didn’t know personally went to the trouble of getting the game running. Part of that is because it wasn’t immediately approachable (you need to host or find a server then run another client to join it) and wasn’t immediately grippy (ok, I can buy a ship, now what?) Any amount of friction is going to turn away potential players, and if you’re used to playing rough unfinished demos this can become a blind spot. But beyond even that, getting someone to try something new is just plain hard.
People respond to Video
At the end of the day, pictures and text don’t cut it for sharing a game. Games are animation. People are used to watching streamers. You need a video of your thing and it needs to show off what the thing is about, including how you interact with it and why it’s compelling. This was my attempt:
Have features and fixes gone in since that video was made? Sure. But it’s still the best tool to show off what the project is about.
Parting Shots
Has the project met its goals so far?
- Learn the Godot engine: ✔️
I’m comfortable with the technology now; expect future prototypes to be more rapid.
- Use Onyx’s Sprites in a game: ✔️
I used most of the ship sprites themselves and lovingly separated out the engine glows for even the ones I didn’t use, in case someone in the future wants to use them again. Cosmic Frontier mod anyone?
- Build a reusable platform for multiplayer EV-clones: ✔️
Maybe this is a partial check. If someone has an idea and that idea is based on multiplayer EV gameplay, I’m confident that if they’re willing to learn Godot they could at the very least copypasta big chunks of the MPEVMVP codebase and get something running. Or they could fork it, replace everything, add missions, remove multiplayer, and make an EV clone real fast.
- Discover if EV gameplay works in multiplayer: ✔️
Learned important lessons about how much bullet hell spam a networked game can handle, and as a straight dogfighting sim it let me figure out what is and isn’t fun in PVP EV.
- Build a game people want/like/play: ❌
As far as I can tell, nobody enjoyed playing this besides on demo night. The service I think people want this game to be is beyond the scope of what it can be with a team this size.
4/5 ain’t bad. Thanks a bunch to everyone who tested it, gave feedback, and flew too far to find the center of the map again.
iMac resto
The iMac G3 is, to my nostalgic eyes, the most beautiful computer ever designed. So when I saw one lying there at the dump I had to take it, to see if it would boot. It did. It hadn’t been used since ’06 and was slightly beat up. I took pictures while restoring it, but much of this post is from memory.
When I found the machine it was booting OSX, and absolutely dog slow. It’s crazy how much faster SSDs have made computing; we used to wait. I posted on /r/vintageapple and got tons of help picking a hard drive replacement. Of course I found out that you pretty much need a working disc drive to boot one of these things, so I picked one of those up on ebay.
In order to get the thing apart you need to first remove the plastic on the bottom, then remove the EMI shield which is a metallic mesh under the plastic. It requires some finicky movements and faith that it’s not all going to fall apart on you. Also screws will try to get lost, so be careful about that. I was able to recover all of the screws once I removed the drive cage; I even had some extra!
Once the thing was put back together with a new hard drive and disc drive, I installed OS9Lives’s version of OS9 from a burned CD. I was then able to load games on via a USB key!
Return of the Flash Games
The Emularity and Ruffle teams have finally done it – Flash is running natively in the browser. No more flash plugin. You can play flash games and watch flash animations on archive.org. Flash defined internet content in the mid 00s. It has been effectively dead since the introduction of the iPhone, and to really enjoy it you need something with a mouse, or a very large tablet I suppose. Actually playing flash has gotten progressively harder, until now.
During the aughts, these where some of the games I played the most. Call it casual if you want, but these where the games you could play on school computers, that you didn’t need to buy. You could discover new ones every day. By timing alone, at least, they’ve ended up meaningful to me.
Heli Attack 2 – Chris Rhodes & Chris Hildenbrand
This is a great example of how the mouse was used for what you might call a sidescroller/shooter. Rather than negotiate a level with pitfalls, the task of your Mario-like character is to dodge incoming bullets, sort of like a bullet hell shooter. It’s also got an array of different creative weapons, each accompanied by a cool robotic voice announcing it when you pick it up. It never leaves this basic loop, spawning helis as fast as you can kill them. Once you get good at it, you can keep playing it for quite a long time. You can play it here.
Fancy Pants Adventure – Brad Borne
https://archive.org/details/fancypantsadventure_202011
This game made a huge splash when it was released. The norm for sidescrollers since eras where denoted by the number of bits systems has was for side scrollers to be very similar to Mario and have the following characteristics:
- Maps made out of a tile grid
- Maps defined by axis-aligned bounding boxes
- Movement defined by walking and jumping.
Fancy Pants adventure subverts these expectations while still sticking to the intuitive sensibilities of a platformer:
- The levels are defined by smooth shapes much larger than what you’d expect in a tile map.
- The maps use curved surfaces rather than straight lines or uniform curve sections.
- In addition to walking and jumping, you can build up momentum and slide
But oh man, the style. This game dripped style. The lush animation, everything about it. I don’t think I ever made it past the first level. I didn’t care. When this came out it felt like it injected new life into the platformer formula. I think Flash’s vector nature really played a role here – it could do things you just couldn’t do on an NES. You can play it here.
Defend your castle – XGen Studios
This is a game that really only works with a mouse, and also illustrates the obsession with violence against stick figures. The figures attempt to knock down your castle and your defense against them is to click and drag them violently into the air so that they splatter down on the ground into a puddle of blood. Eventually you get enough points and abilities to take stick figures into your castle and turn the game a little bit more into a tower defense setup. You might be able to get this working on a very large tablet, but really the interaction is tailored for the mouse. The graphics are basic and make heavy use of gradients and stick figures – both flash tropes. Yet here I am in 2020, actually getting sucked into it. It’s a very well crafted dopamine loop. Launching the little bastards with your mouse is satisfying, mastering doing it quickly before they get to your gates is rewarding, and the relief of having your job automated by a bunch of archers is even more rewarding. You can play it here.
FlashTrek: Broken Mirror – Vex Xiang
https://archive.org/details/flashtrek-broken-mirror
As a big fan of the Escape Velocity series, Broken Mirror kept me playing for many hours. It’s a space trader game set in the star trek universe. Well, the Trek’s mirror universe-the one where everyone is the baddies. It’s the rare fan game but it fills the exact kind of niche that you’d love to see for that setting. It’s also absolutely dripping with humor, especially inside fandom jokes. As a fan work it is monumental. I’d daresay that until Star Trek Online was a thing, it was the definitive star trek video game experience. The open world of the space trader genera fits perfectly with the open feel of Star Trek. And really, having a big open world RPG on a platform that was mostly used for single-screen arcade games is quite an accomplishment. It plays at breakneck speed on modern systems, but you can play it here.
Soylent Recipes
The lockdown has given me occasion to consume lots and lots of Soylent. As a result, I’ve gotten modestly creative with it, and thought I’d share my notes.
Powder is best prepared in a blender (I use one of the top-threads-into-blade-base deals because they’re easy to clean) with a goodly amount of ice, a banana, and a small amount of water. If no fruit is added, make sure you add extra water. I tend to prefer as thick a shake as possible, but if you don’t put in enough water the powder will clump around the blades and you won’t end up with an edible result. With those guidelines in mind, here are some fun things to mix in:
Peanuts – Why add peanut butter when your blender is going to turn them into paste anyway? This does a good job of thickening your shakes. Goes great with Banana and Chocolate. Almonds work but not quite as well. Cashews didn’t do a great job. You can use salted or unsalted peanuts, but I preferred unsalted.
Pistachios – These taste great and work well as a thickener. Didn’t try it with the shells still on though.
Chia Seeds – A somewhat finicky thickener. They seem to add a glassy, neutral quality when added in, but they do great things to the texture. Further mixing experiments are needed. A good option if you’re tired of peanuts.
Pudding powder – I tried pistachio and vanilla flavored, and it worked reasonably well as a thickener. If you add milk it might even turn into pudding.
Cocoa powder – This is the best way to give a chocolate flavor. Make sure you sweeten to compensate, and adding a something (banana, etc) to make it thicker is important – watery chocolate shakes don’t turn out well.
Sucralose – Generally only needed when you need to balance out something bitter or sour such as cocoa powder, and not needed if you’re adding a ripe banana or flavored syrup.
Flavored Syrup – This was my go-to sweetener. Vanilla Almond, Maple Burbon Pecan and caramel cheesecake where the ones used most frequently.
Milk – Use in place of water for turn the shake into a milkshake. Subtile difference but if you’re starved for variety it’s worth a shot.
Banana – You don’t really need anything else if you have one of these at perfect ripeness.
Apples – Make sure you remove the seeds because supposedly blender will make the poison in them bioavailable. Goes really well with nutmeg, allspice, and/or cinnamon.
Blueberries – but make sure you add a small amount of sweetener to compensate for the sourness.
Cherries – Make sure you remove the pits, which is rather time consuming.
Avocado – This will give the shake an almost ice-cream like texture, highly recommended.
Jackfruit – Adds a great flavor and sweetness but leaves an uncomfortable texture in your mouth.
Novelty ice tray ice – It appears that the closer an ice cube is to a sphere the more difficult it is for the blender to pulverize it. Novelty ice trays will produce ice that is more readily smashed to bits.
Bonus – if you have chocolate 2.0 and don’t like the texture but do have the blender bottles and a bunch of peanut butter powder, go ahead and shake the peanut butter powder into the chocolate 2.0 to make a far better drink.
Flythrough.Space Retrospective
I’m not going to rehash don’t remake an old game, but the principle very much applies. Flythrough.Space is a 3d remake of the EV series, and as such suffers from the “remastering someone else’s game” problem. That said, it was a long and involved software project, so there’s got to be something to take away from it, right?
Content Design
Don’t do content design up front. I had reams and reams of content for this project, a holdover from an even older project, making the oldest data seven years old! And the design of the map dates back to an EV Nova TC I attempted in 2005 or 6. The first plan involved using the graphics from Onyx’s Old Shipyard, back when the whole thing was going to be sprite based. FTS, while using the existing data, was 3d from the beginning so needed its own entire suite of assets.
I ended up using Blender because it’s Free Software and I wanted to keep the toolchain as free as possible. I wanted anyone to be able to pick up the same tools and build more content. It took me a while to become minimally proficient with Blender. One thing that ended up looking really cool was making rough textures with blender’s texture paint then applying a “paint” layer in GIMP with clean lines but dusted up with a rough brush and a makes for a worn look. The ships aren’t exactly up to modern standards, but I’m proud of the results nonetheless.
The planets turned out pretty good. Never did nail clouds though.
Technology
Flythrough.Space started out with very basic requirements. I wanted to do the game in 3d, I wanted menus, I wanted to be able to write object oriented code and I wanted to be able to break code into multiple files. Web was a platform I’d been working on for my whole career up to that point, and I wanted to make the game very easy to pick up and play, so web it was. There was a long period of using babel and Angular to compensate for the shortcomings of JS, but eventually we got all the goodies right in the browser! Once I was working in vanilla ES6 with no precompiler or other baggage, working with the code was pretty much a joy.
ECS
I tried to build an entity/component system. All of the game’s behavior is implemented in “systems” which are functions that get run each frame, requesting entities that have specific components to work on. For example:
export function velocitySystem(entMan){
// Provides inertia.
for (let ent of entMan.get_with(['velocity', 'position'])) {
// Do physics
}
}
The game state all belongs to entities or the player save object. This turned out to be a fairly awkward way to program a game. It was very nice that, say, velocity or AI could be added to any entity pretty easily. But there just weren’t that many different classes of things in FTS. A class hierarchy wouldn’t have become overly complicated, considering the small number of different entity types in the final game (ship, beam, planet, asteroid, projectile, explosion.) One major drawback was how it changed the code layout of the project. If you want to see what code controls the behavior of a ship, you need to browse several different files and it’s extremely unintuitive. Likewise, if you want to know what parameters a ship can have, there is similarly no single place to check out. There is no FTS bible. One possible evolution would be to put every possible ship param into the implicit base class, but then you’ve got a few parameters where absence matters…
Collisions
I wrote a primitive collision library myself, and my attempt to integrate a proper one later was frustrated by a lack of the primitives I needed, specifically objects with no rotation components.
The crowning achievement of the collision system is the line segment collider. Managing to implement (not invent, mind you, merely implement) allowed continuous collision detection which made combat work much better. It also enabled beams, which are a staple of the genre.
Missions
The missions system leverages ES6’s actually very nice text interpolation to make nice templated text. It uses eval
all over the place to do it. It’s a bit fiendish how it works, and it works very nicely for stuff like “deliver cargo” but to add features like “go blow up ship” you’d need to add something in the system code to spawn ships depending on active missions. Probably wouldn’t even be so hard, but it’s low hanging fruit that I haven’t picked. Missions where a very late addition, right before the Alpha release. The json
to define a mission looks like this:
"smuggle": {
"short_name": "Smuggle ${cgo(this.cargo.type)} to ${this.dest.spob}",
"desc": "Some shady exporters need ${this.cargo.amount} tons of ${cgo(this.cargo.type)} moved discretely.",
"offer_if": "true",
"offer_state": "missions",
"cargo": {
"type": "${get_illegal_cargo()}",
"amount": "randint(5,10)"
},
"dest": "get_spob_same_govt()",
"reward": 14000,
"accept_modal": {
"text": "The dockhands quietly load the mislabeled containers of \"${cgo(get_legal_cargo())}\" into your hold."
}
},
But that sort of thing only covers random cargo missions. I’d designed the world for FTS without giving too much thought to how it would become involved in any sort of story, besides the idea that the Loyal Suns wanted to take everybody over and the Itaskans wanted you to visit every homeworld. This is a problem because in EV games, you’re supposed to play missions to unlock faction ships, and most of the ships in the game (especially the ones I’m most proud of) where faction ships. My inelegant solution: all ships available all the time. No dynamism. Nobody wins or looses. Some people just fight sometimes and if you hail them they’ll give you the slogans of their government. I think that without plotlines, there isn’t much of a hook. There’s certainly no endgame besides grinding up to an Absolver, Nightshade, Capital, Taoiseach, etc.
Data Driven
Every ship, star system, etc is defined in json
files. Many previous game attempts had done a lot of work on making a perfect data loader. In this case, I was able to leverage Javascript’s own builtins to make something I’d consider basically perfect (or at least perfect in that it represents an idea taken to its full extent.) You can declare another object as a given object’s prototype and it just works, inheriting values that aren’t overridden. Objects are created on screen by instancing the data (with some enhancement, of course, but it’s all fairly easy to follow.) There’s no intermediary data is what I’m getting at; the javascript objects in the data directly translate to javascript objects in-game. Upgrades work by acting like a diff. Getting all of this to just work was one of the funnest parts of the project and will be the hardest part to let go of.
Community
The babylonjs community, by way of their forum, was extremely helpful. Having real live people who want your project to succeed and can help you use the tools they’ve built is a joy. I would definitely recommend treating community as a critical feature when picking frameworks and libraries.
That said, you also need to cultivate a community around your own project. That’s one angle where I failed in a big way. It isn’t easy to get other people to demo your game. Starting with something very you can get right into, rather than starting a player out as some sort of lowly level one wimp in an RPG might make a lot of sense. I eventually added cheat codes in the form of querystrings (bonus points if you can find them by looking through the source) so players could start in more powerful ships (and so that I could test them without grinding.) But without a large number of testers, tons of bugs slipped through the cracks. It took me way to long to realize that using Control as the fire button simply wasn’t going to work on mac, for example.
If you want to use FTS
I tried to do with FTS what Ambrosia never did with EV: make a totally open system that anyone can pick up, make a game, and truly own that game with. FTS is licensed under the GPL so if you throw in your own assets and release any code changes, you (yes, you!) can make a commercial EV Clone with it. The game scenario lives in the data and assets folders. If anyone has specific questions about how to implement something, I’d be glad to help. But I realized something: nobody is going to mod your game if they don’t love your game. Making a game easy to mod needs to be a secondary concern to making a great game. If you really truly want to build technology rather than a game, I would recommend partnering with someone with a vision for an excellent game, which brings us to our next point.
Putting the cart before the horse
I thought I knew exactly the game I was trying to build from scratch. However I was building it largely in a vacuum and I certainly wasn’t going back to EV Nova to see how the ship movement and turn speed compared. This was probably a mistake. I was so mired in what I could achieve technically that I wasn’t stopping to ask if the game I was building was actually fun or not.
I should have spent the bulk of the development on the basic combat loop, making sure the ship handling was fun, the AI was correct and tight and fun to play against, and the game balance was decent. Instead I focused on creating tons of content and features because I was trying to work from a feature checklist. Feature parity with a twenty year old game does not a compelling game make, as it turns out. On paper, FTS has what it needs, but I feel that it does not live up to that potential.
It’s a mistake I don’t intend to repeat. Future projects I’d like to get in front of people faster, I’d like to be less stuck on design decisions I didn’t even make, and I’d like to have the emotional fortitude to disengage from a project before it takes up half a decade.
Giant robot submarines, we’ve got those too
One interesting aspect of most knowledge being instantly accessible is the holes in that knowledge-things from the before time that never got ingested into the web and as such still mostly exist in your memory. I find myself trying to fill in those gaps sometimes. I found myself asking “what the heck was this old toy series I remember?” Not everything will get the Toys That Made Us treatment.
I picked up a set (not pictured) at what I seem to remember being an aquarium gift shop, but it could really have been any pit stop on the mass pike, back in the 90s or early 00s. The scifi theme and being unencumbered by a fleshed out fictional universe was appealing.
More recently, I decided to figure out what the heck they where. I didn’t have the original handy, but after googling some vague descriptions, an imageboard (of all places!) pointed me in the right direction with a very accurate rendition that sparked my memory.
I’ve now got a decent handle on what the internet seems to know about Silverlit Toys’ Multimac. There isn’t much of it. They can be had on ebay (see the lobster above.) There are good pictures of the drivers here, as well as some information.
some good pictures of the crustacean-shaped submarines as well. There are a couple of forum posts here and here that put it in context (how it related to other lines, where parts where reused, etc.)
But really, these just create more questions than answers. Especially looking at the shark, lobster, and crab shaped submarines I’m reminded of Lego’s Aquazone line – which one came first? Or was there a general atmosphere of “giant animal shaped robots piloted by humans” in the 90s?
I had a small breakthrough when looking at the packaging of the lobster and crab though – I believe that they are a later addition to the line because they have a URL on their packaging! It might be possible to date them by when that became common practice, but now I’m eager to actually dig up the site!
This one is small and hard to read.
And this one has a label over the URL, but a upon close reading they appear to have just owned “www.oceandiscovery.com”
And in 2001, the internet archive captured a copy!
And that’s it, everything the English-Speaking internet knows about this (dare I say mysterious?) line. I suppose that’s what made it appealing at the time: the suggestion of a wider world, a connection to a past (specifically the giant-robot-and-vehicle toy-verse that included more popular lines like Transformers and Zoids) that I didn’t really have knowledge but the matter-of-fact-ness of the packaging suggested it. It was as if to say “yeah, you know, giant robot submarines. We’ve got those too.”
Flythrough Space: Beta
It’s been a couple of months since I last wrote about Flythrough.Space. It was the first time I ever got any feedback on the project from people who understood what I was going for, so it was pretty informative. I had productive discussions about perspective and (as I’d feared) overlapping 3d models are a bit weirder than overlapping sprites.
In any case, if you tried it before and thought it was rubbish, you might as well give it another try because it’s radically different, at least in appearance. Go to the settings menu and try out the different options. Message me if you want cheat codes to try different ships (or figure it out from the source!) When in doubt try resetting the settings or refreshing the page.
New Features:
- Sound effects. Pew pew, etc.
- Anti-tunneling collisions. Players complained that it was hard to hit stuff; this was partly because of a well known problem called collision tunneling. I bit the bullet and ported over a line collider, so now fast-moving shots should connect more frequently.
- Implemented a settings menu so that as I started to add GPU and CPU hungry effects I wouldn’t leave people (or my own laptop) behind. It’s slightly jank so I recommend refreshing the page after you leave the menu to make sure the settings take effect.
- Guided weapons.
- Asteroids! Mine them for fun and profit! Blow the metal (orange) ones into very small (hard to see) pieces and scoop them up by flying over them. Then go to a market and sell!
- Lighting effects. Though each star system could already define its own lights, now ship explosions cause a flash in addition to particles. I was reading The Dark Forest and the descriptions of space made it necessary. Also shadows are in but don’t work very well.
- Piracy! You can now plunder disabled ships for cash and cargo. Press ‘B’ when you’re close to a disabled ship.
- Starfield. Classic space videogame effect… it lets you see where you’re going. Got some good help on the babylonjs forum with this one. I originally tried to build it with a shader, but gave up and did it with a massive number of sprites.
- Perspective (or, well, the camera looking at your ship from an angle) is now optional. If you prefer your space-shooters to be top down (because planets getting bigger and smaller is disorienting, for example) you can have that now. An ortho camera proved to be not quite what I wanted, though it would still be cool if combined with a vertex shader that applied perspective to individual objects, to better achieve the look of a sprite-based game but with the lighting benefits of a 3d engine.
- Impact Physics! When you hit stuff, it gets pushed!
- Zoom! It became too hard to debug weapon placement without it, so I added it in. Use [ and ] to zoom in and out.
- Beams! Take an XIC Prospector or drillship out for a cinematic experience.
- Textures. Ships have them now, including an (optional) glow effect around emissive (self-lit/glowing) bits which I think look pretty cool. Each model has multiple (per-faction) skins which are easy enough to palette swap and add more.
- Fixed various bugs, including making the map show up right away when you pause the game (now you don’t need to drag it) and explosions now show up reliably.
- Particle effects everywhere!
- Every item (ship or upgrade) should be available for purchase somewhere. There’s no notion of unlocks, you just need to get enough cash and drop by the right stellar object. There’s now a test which enforces this!
- Trade routes. The trade system is still a bit confusing, but the fluff text should direct you to some decent trade routes (or some very lucrative ones, if you are willing to brave pirate infested space!)
- Alert text at the bottom to tell you, for example, that you’re too close to the system center to engage your sidereal drive (jump to another system.)
- Optional ‘arcade’ mode where shots don’t inherit velocity from the things firing them. Should make hitting stuff easier. I think it matches the behavior of other genre games. I don’t like it very much myself, but that’s why it’s a setting.
- Carriers can launch fighters! They don’t do anything particularly clever yet though, they just use the normal AI for the most part. Q to launch, (hold) R to recall, F to attack your target.
- Saving and loading, so your progress isn’t erased every time you land on the page. Like settings, for now saves are using local storage. You can also upload or download a save file from the same menu.
- Pause button now takes you to the main menu; press ‘m’ for map and esc to return from the map. This means I don’t need to debounce map button presses and as a result it’s less janky.
- You can now see which systems are mission destinations in the map, even if you haven’t explored them yet. An orange circle around a system indicates that your mission is there.
- Code changes: Entity manager is now a singleton, so I should not have to pass it around everywhere. Refactored the HUD into individual widgets. Ships can now inherit from other ships with the “extends” property, which should cut down on clutter in
ships.json
and make nova-style ship variants much more possible. Input is a lot less gross. - Control changes. Using CTL as the fire button wasn’t feasible on Mac. Same deal with +/- for zoom.
- Data Changes: Cleaned up terminology for factions so it should be much easier to read the data files.
Where we go from here
So what’s next? Well, I’d really, really like feedback. Yelling into the void is less than satisfying. I’d like people to give the game a spin and tell me how horrible it is. One thing I’m especially concerned with is making sure the ships feel right – not too quick, not too fast, not too slow. The weapons could also be a lot more balanced. The biggest improvements to the game at this stage will be all about tweaking the numbers. Nothing would delight me more then someone downloading the game and trying out different tweaks to see if they can find the fun. Yes, I realize that this would ideally be done in the prototype rather than the final game but hey, not all projects can go perfectly.
What do I still want to add? I’d like to fill out the galaxy with more planets and more NPC placement. If anyone wants to write planet descriptions I’ll do my best at editing. A lot of the Loyal Suns, League, and a bit of Freehold territory still needs attention. More diverse asteroids would be cool too. As far as big code features, well, fleets are a big one. More missions would be nice. A more in-depth hailing system to allow planetary domination would be cool and give the game more of an end-state. Also, the AI is full of bugs and would really benefit from the level of unit testing I’ve applied to player.js.
I may take a hiatus from development for a short while, or I might not. I keep telling myself I’ll try to work on another project, but I keep coming back to FTS.