What the user sees is “click the icon, get the window”. What I see is “holy crap where do I attach this UI? How do I get the clicking on the icon to work? How does the act of clicking on the icon tell the window to show itself? And how do I get rid of the window when they decide they don’t want this facility, or when they do choose to rent it?” The biggest hurdles have been where to put the UI, and how to get the action to trigger the UI. In Unity, the UI is now represented by actual game objects, as opposed to the “in pure code” from Unity versions gone by. This means that we can design the UI in the Scene (working) view and see it during edit-time, but it also means that all UI elements are objects in the Scene, like models and lights and audio sources. There’s a certain hierarchy that needs to exist in order for the UI to render, so there’s also a tiered structure that needs to be considered when dealing with different UI elements.
I put the rental fee UI on the facility icon itself, which makes talking between the two easier. What I found very quickly was that with more UI elements comes more complexity when trying to figure out where to put the UI and how to talk to it. Putting the rental fee UI on the icon might work now, but what if there’s a situation where I need to open that UI from somewhere not associated with the icon? I envision a master control panel that will list all research facilities currently rented and operated by the player, so she could click on an item in that list which moves the camera to that point on the map and opens the panel that explains what’s going on with that facility. None of that would be sourced from the item itself; it would need to be called from outside the item, like from a main menu or toolbar. I could add component references between the buttons — wherever they are — and their UI targets, but that results in a lot of spaghetti connections that are difficult to trace when debugging.
The answer was “abstraction” and “oversimplification”. I created a “window manager” which is nothing more than a list of windows in the system. When a window starts up, it registers itself in the master window manager list, and then either stays put, or is hidden (or moved to a point off-screen). With the window manager system attached to the Game Data Object — the global, non-destroyed, singleton object that is accessible from everywhere in the game — I can call methods like ActivateGameWindow() and pass in a name as an argument, like “ResearchRentalUI”. If that UI has self-registered and is in the management stack, then the method will find it and turn it on, activate the animation, or do whatever it needs to do in order to activate that element. This messenger systems ensures that I don’t need to have one specific element know about the existence of another specific element, so long as I don’t misspell the name of the UI element I want to send the message to.
I’m not writing this because this is some kind of revolutionary design technique, but rather because what we see on the surface isn’t always what we think we’re looking at. Sometimes things are more complex, and sometimes they’re more simplistic, and sometimes they’re way out in left field.
I’ll admit that I’ve been violating Rule #7 of Software Development by not storing my project in a version control system. Actually, I’m storing it in my OneDrive folder, which means it synchronizes across multiple computers so, you know, I can work on it in multiple locations.
The other night I booted up the project at home, but I didn’t see my most recent changes. In fact, I did, but they were duplicate copies which had been renamed to refer to the other platform on which I’d last been using them. “Oh well,” I thought. “They’re just dupes.” So I deleted them. Hard deleted them.
Turns out those files were the most recent updates, and what I had left over were the older copies. I freaked out, to the point where I downloaded an app that supposedly allowed me to undelete files (which is scary when you see how many of your files you can undelete). But when I said I hard deleted them, I mean it, so good news is that Windows does a decent job of scrubbing things that your average off-the-shelf recovery software can’t find, if that matters to you, Mr Snowden.
Needless to say, I was pissed because one of the files was my core data management scripts that contained all of my loading and saving functions. Those functions comprised the one part of the game that I felt was “complete” in that it was generic enough that I wouldn’t need to touch it again even when adding elements that needed to be saved to the overall game itself. Nice, efficient, powerful. And gone.
I spent the next session re-writing the whole thing mostly from scratch. I still had a much older copy to serve as a reference, but was missing several key methods, like the one that managed the save game manifest file (the manifest holds info on all of the actual save game files, and is what is read when you click “Load Game” to allow you to select a saved game to load). The good news is that I had just enough of a memory (and some notes) to allow me to recreate the system, but better. I feel that this new iteration is more robust even than the original, which I was a big fan of. And once I’d completed the work, I zipped up the code and stashed it somewhere safe.
So I need to get this stuff into Github, which I’ll hopefully end up doing this weekend. That way, I can avoid future costly mistakes. Learn from my sorrow, kids: Always use source control.
Listen, I’m not a gifted hobbyist when it comes to working with Unity. My approach has been to logically suss out what I want to do using my knowledge of application development, build some test cases in code, and hopefully rely on the script (that I know) far more than I would rely on whatever automation Unity offers (which is what I’m generally fuzzy on). Of course, using Unity means using Unity, so I can’t simply script my way to Nirvana; at some point I’m going to need to use the Unity Editor to Get Stuff Done ™.
Exhibit A: Animating a panel to fly in on a button press, and to fly out when I click Cancel. The goal seems relatively simple enough, and I figured I was halfway there because many moons ago I had done some work in Flash which introduced me to the concept of key frames, which are points along a timeline where properties of an object to be animated can be changed. Unity’s animation system, at it’s most basic, uses keyframes as well, so I figured that I could create an animation clip, set some keyframes and alter properties, call the Play() method from script (either SlideIn or SlideOut) when the appropriate button was pressed, and everything would work as I assumed it would.
Check out this monstrosity. Click to embiggen and feel your soul being drained as I explain how this simple task is hampered by the Power of Unity.
The top portion of the screen is my design surface. You can see the frame of the UI boundary on the left, and the panel to fly in is on the right. When we run this, that panel is outside the bounds of the camera that draws the UI, so we can call it “exit, stage right” (or left depending on whether you’re on stage or in the audi…you know what, I don’t care about this metaphor). The properties of the panel are just a whole lot of technobabble, but the important part is the bottom of the screen. That’s the “flow” of animation that I was forced to deal with. What isn’t shown is the panel that allowed me to define the animation through the use of keyframes. In that, there are two “clips”: one that moves the panel into view from right to left, and one that moves the panel out of view from left to right.
At some point, I had actually had a simple version working. I had just defined the two clips, assigned them to the panel, and was able to call them from script, by name, and it worked flawlessly. Then Unity decided to cough up a techno-hairball and screwed up a whole bunch of UI elements Just Because(tm), forcing me to rebuild a few. That messed up my animation setup, and when I attempted to recreate it, Unity decided that now it wasn’t good enough, and started throwing errors. This sent me in search of a way to animate a UI panel.
Let me tell you: there’s fuck-all for info on how to do something as simple as UI animation in Unity. Doing a search for “animation unity3d” with any additional criteria thrown in only brings back information on how to animate character models or sprites. Yeah, I get that the character is really the heart and soul of a game and it’s also pretty complicated, but does everyone understand UI animation? Am I just Extra Clueless? That’s rhetorical, by the way.
What I had to do was to create the Idle state for the panel, which means it’s not doing anything when you start, or after the panel has moved. I also created two boolean flags: IsOpen and IsClosed, and are using them to brute-force the situation. When the user clicks the OPEN button, the IsOpen is set to TRUE and IsClosed is set to FALSE, which routes the state machine to the SlideIn clip, and then back to Idle. Reversing the booleans when I click CANCEL routes to SlideOut, and then back to Idle.
I can accept this, but I really question why I have to, since I’m not using script and not Unity-proper to handle my buttons. I feel that it would be a lot easier just to build the animation clips for a GameObject, put those clips in a reference bucket on that object, and then call those clips from code to have them play. In fact, I know this can happen, because the Play() method exists, but I can’t find a straightforward tutorial on how to set up the environment in a way that allows me to refer to those clips by name, and since I did have it set up once, but was rebuffed when I tried to replicate that situation, I’m more confused than I was before.
I’ve been working on that “mystery game idea” since I mentioned it in the last post in this column, and now I want to talk a little about it.
The idea is relatively simple on paper: you are the head of a corporation in a cyberpunk universe. You have to make your company financially viable by researching, manufacturing, distributing, and marketing products. Being cyberpunk, however, it’s not just about financial warfare; it’s also about actual warfare, so you can steal and sabotage your competitor’s resources which will strike a blow to their pipelines.
And that’s the pitch.
Right now, I’ve got the very initial framework down that allows me to create a CEO and a corporation, choosing a portrait and a corporate logo. All of that saves to disk. You can also choose to load a saved game from disk. Hey, that’s been the Achilles Heel mechanic of most of my previous project attempts, so I’m super pleased that this aspect of the game is already on the books (more or less) so I can concentrate on other things.
The game moves in phases. First, you start with nothing, and need to choose your first item to work on. You’ll get a “market research” panel that will give you three random options, and what it is about current products on the market that they don’t like. Maybe one option will be an anti-cybernetic-rejection drug that should be “more potent” but also “less addictive”. Choice of item really has no bearing on anything except as a way to goad the user into picking something, and giving them a vague target to aim for: better than the attributes the panel say they dislike.
Next, you’ll need to pick a location on the map to set up an R&D facility. It costs money to rent, and you get a level 1 lab which installs the selected item to research. Research is a passive affair, but you’ll need to decide which attributes to boost and which are OK to sacrifice. Each item will have X attributes, but only a few will be relevant when trying to appease the market research subjects. In order to increase your chance of making something better than what they have now, you’ll use sliders to spend points on attributes. But in order to get those points to spend, you’ll need to decrease the sliders on other, less important attributes. If you’ve got the money, you can hire a researcher who adds permanent points to your pool that don’t require you to sacrifice anything, but you can’t hire enough to max out an attribute, only to supplement it so your other attributes don’t suck as bad as they would otherwise.
You can get a market research panel to research new products, keep manufacturing the same stable of products, concentrate on a market or diversify, hire and fire, improve the level of your facilities, and so on.
That’s about as far as I have conceptually. Beyond this, there’s ideas for manufacturing and setting a price, then getting into a market which may or may not have been represented by the initial study that you worked hard to live up to in the first place. You can improve your chances of selling even the crappiest items by crafting a killer marketing strategy by hiring celebrities or creating controversies.
The corporate warfare is something I want to include because it’s a cyberpunk staple. If you’d rather not hire a researcher, say, you can hire a street merc squad to “extract” a researcher from a rival corporation, scoring you not just a researcher but other boosts in the form of bad PR for your target opponent. Of course, they can do the same thing to your off-duty researchers, so you’ll want to hire security for your facilities which could resort in some collateral damage along the way.
There’s a lot to flesh out, including the all important “what’s the damn point” in a game where your actions all support increasing your profit, but currently for no good purpose…and no end. Maybe you’ll have to run your rivals out of business, but how? Maybe you have to reach some kind of domination scenario, but how? I know it’s not really “a game” without a win or lose condition, but there’s always a bunch of opportunities for both when we’re talking about corporate warfare.
I read in several different locations that talking about a project often times can trick the mind into believing that progress is being made, which in turn subverts any real attempts to make actual progress on the project itself. I fully embrace this explanation, since I’ve fallen victim to it on several occasions. Still, I can’t help but write something about my projects because on the other hand, seeing something in writing makes things real for me. It also acts as a log of action, something that I can look back on and remind myself what I was thinking at the time. Ideally, writing about projects would keep me honest and hold my feet to the fire, but on their own these are just words; what I’d really need would be interest, and people to keep on my case over time.
Of course, it doesn’t help that my projects — like Project Universe — are insanely complex for someone with absolutely zero game development experience. Since game dev is pretty much a black box industry, all we see is the finished product. We the consumer might be treated to some talking head video diaries from the development company which feature distant captures of monitors with code, or teasing montages of artists working on out-of-context assets, but nothing we see is really about process; that stuff is horribly boring because at the end of the day, games are made using the same processes that pump out any other widget on the planet: meetings, budgets, and a lot of solitary work done while underneath a set of headphones. My point is, I’m really good at aiming high, and have been using this site to record my progress in the hopes that it would keep me going during the times when the task seems insurmountable because of all of the things I don’t know. Everything can be learned, although there’s only so many hours in the day, and for something like Project Universe which would have required me to be designer, developer, and artist, each day would need to be stretched out to something like 60 hours for me to feel that I had enough time left in life to get done what I want to get done.
Although this is something I’ve always realized, I found that making progress negates that worry significantly, so in that vein, I’ve been thinking about what I could make that would be less ambitious, task-wise, that I might actually be able to finish. I think I might have the answer, but of course I thought that Project Universe was also an answer at one point in my life.
I’ll not go into specifics about this project just yet, since I’m only brainstorming the concept and mechanics and what I want a player to get out of the game. Some parts already make sense, but some parts are leading to blatant dead-ends for fun, replayability, or general engagement. I have to be open to the idea of throwing away ideas that don’t work, rather than stubbornly trying to force those round pegs into square holes because I don’t think I can come up with an alternative, or because I am so focused on one particular end result that I feel that I must have.
The good news is that this concept could be simple enough to exist as a boring old form on a web page. By “simple” I mean “it doesn’t need a whole lot of flashy graphics to work”. I like enticing visuals as much as the next gamer, but the idea this time is to focus on my strength, which is coding. No matter what approach I take, I don’t foresee this project needing tons of “deep” art, most of it being static, and very little being animated, if anything.
That being said, I keep coming back to thinking of this project in terms of being a mobile game, or at least a tablet game. I’m not sure that’s the way I want to go, partly because I don’t do mobile or tablet gaming myself and have little to no interest in that market, but also because I have no experience in mobile or tablet development in anything. Using Unity (naturally), I could compile for mobile platforms with relative ease (sans Apple because I’d need a Mac), but it just throws a whole curve into the equation that would effectively take the place of some of the complexity that I think I’ve already engineered out of the endeavour.
So right now, I’m going back to thinking and planning about the first steps, the goals, and parameters of the most basic tasks that I want this to accomplish. Unfortunately I’m already trying to fend off secondary and tertiary system ideas, the kinds of things that flesh out a basic game concept so that it’s more than just “pushing buttons”. Those elements will get dropped into the sidebar, and I’ll have to revisit them once I’ve got a solid grasp on the fundamentals of what I hope to accomplish.
Here’s a study in “what you don’t know and how it feels to learn it”.
I was looking at my brownstone model and thinking about how I was going to texture it. It’s not the most detailed model out there: it’s got some windows, with window frames and panes and such, and that’s about it. But unwrapping this would be a real PITA because of the natural crenelations involved in recessed building techniques.
I was looking at Substance Painter and Quixel Suite 2 because both of those supposedly allow you to just paint right on the model, or define material placeholders on your model in Blender, which you can then just “auto-replace” with proper textures (oversimplification, but I don’t really understand “PBR” enough to provide a better explanation). I thought “Wow! That’s really cool!”, but after watching a tutorial on Quixel, it looked really complex. Substance Painter seems better explained (their tutorial videos are very easy to understand, so thank you, Allegorithmic!), although more expensive.
In the course of watching Substance Painter videos, I learned a key fact about 3D modeling, and why you would want to make a high-poly and low-poly version of the same model. I had heard of this dichotomy before, but thought of it as designing for different needs. A high-poly model would be useful for stand-alone rendering like ads or showcases of a product. Using a high-poly model in a game is dangerous, as the more complex the model the more horsepower the engine has to devote to draw it. Multiply that by however many models you need to render and update in real time, and it becomes clear that high-poly models are going to have a significant cost. So designers need to make a low-poly version for real-time use in the actual game. What I never understood was that there was a connection between high and low versions until I watched the Substance Painter videos: the high-poly model — the one with all the intricate detail — serves as the template from which you generate your mapping, such as a normal map and occlusion map. You then take those maps and apply it to the low-poly model, and suddenly the low-poly model looks like the high-poly model, but with less geometry. It’s all a trick of the virtual light that makes your generic, less detailed model look like a more intricate, highly-detailed model. Mind = blown.
This was the point where I went looking for information on generating maps for my brownstone. I’d generate the maps on the detailed model so those windows on the less detailed version would be simplified, and I’d let the normal and occlusion map take over the illusion of depth. But in order to get those maps, I’d still need to unwrap the UV, which is the absolute bane of my existence. Even Blender’s “Smart UV Unwrap” method didn’t provide me with a “good” implementation that I could understand. I needed more information on how to handle this specific aspect of modeling, but a lot of the documentation on Blender is either really outdated, or not informative enough in terms of technique.
So I went back to my uber-Udemy Blender course. I’d left off at a place where they were talking about the absolute basics of using Blender, so “watching” those videos meant spending the time playing Black Desert Online on the other monitor while the instructors went over loop cuts and things like that (i.e. all the things I end up forgetting exactly at the point where I need them). The next chapter, however, was a little more in-depth. We were working on creating a bowling pin and ball. Not the most exciting models, of course, but a lot was learned: using materials, bezier curves, how to turn most anything into a sphere, and some of the more “esoteric to new modelers” concepts. The course also touched briefly on getting the models into Unity, along with creating a collider “shell” for your object so physics works correctly in the game engine. In short, good, usable techniques with examples, explained well.
This course is long, but informative and easy to follow, and that’s the bottom line here: tech teaching usually sucks real hard. When I finished up the video instruction for the day, I had a really sweet looking bowling pin and ball! I credit the instructors for knowing how to talk to an audience that knows nothing about the upcoming task without talking down to the audience that knows nothing about the upcoming task. Tech people are the worst at this kind of thing, by and large, because they know what needs to be done, but don’t always think about what needs to be done. Tech people like to always move forward, and don’t always consider the steps they need to take to do the things that are now second nature to them. When tasked with instructing someone else in how to perform as task, at least one of two things happen:
- They get all eye-rolly and condescending
- They skip a crap-load of constituent information
Everyone knows — or has been at the center of — stories of tech folks talking about how non-tech people are “stupid”. That’s a load of bullshit. No one is born with knowledge they enjoy holding over people, there’s plenty of knowledge that even the smartest people have trouble grasping, and “stupid” calls to mind people who can’t do anything. I can build a PC from parts, but I can barely do more on my car then start it and change the wiper blades. To an auto-mechanic, I might look “stupid”. To me, a mechanic who can’t figure out what an error message on his computer screen means might look “stupid”. Different strokes, people. We all have potential, if someone else can muster the patience.
But having patience is no good if we can’t articulate. Tech people are funny in that they’re always thinking current or abstract. Here’s the desired outcome, and here’s what you need to do to get it done. A lot of the Blender tutorial info I was finding took that approach. It told me what I needed to click and what it did, but never really explained why I would want to do that. “To get the desired results,” is certainly the sarcastic answer, but it’s not the answer that helps me help myself in the long run. Because tech people rarely look back to evaluate what they’ve already learned, they usually can’t give out decent advice on how to get up to speed. This has been the core issue for me in game development. I can repeat steps someone tells me I should take, but I don’t understand why I need to do it. How do the parts relate? How can I recover something if it goes south? Are there any best practices involved, and what are they? And if I run into a similar but also different situation in the future, will this technique still be applicable? I’m being given a fish, not taught how to use the fishing rod.
I enjoyed my video tutorials so much that I didn’t want to stop last night, but I had to, you know…get up and move around to avoid an embolism or something. I felt that I was really getting somewhere and learning something. I had started out wanting to accomplish “a thing”, found that I couldn’t because I didn’t have adequate training on how to accomplish “a thing”, and then found that one of the resources I had at my disposal was actually helping me learn. Not specifically about the “a thing” I wanted to accomplish at that moment, but I feel that I’m making progress, and will eventually learn enough to be able to do that “a thing” that I need to do.
I’ve been looking over the ORK Framework (ORK from here on in) recently, clicking all the buttons and checkout out the integrated help panels, and while it seems like a lot of boxes to check and forms to fill out, I think it’ll go a long way towards helping streamline development of…something. Just, something.
The difficult part is going to be coming up with the part of the game that’s not really covered by the mechanics. With Project Universe, I didn’t need to really come up with a story. I was just providing the tools that would allow the player to interact with different aspects of the game — buying, selling, shooting, discovering, etc. — and let him go on from that point. Anything I try to work on with ORK is going to require an actual narrative of some kind. Maybe.
The easiest path would be to use ORK to handle missions, inventory, characters, combat, and AI. I’d be on the hook for visuals (terrain, models, animation, audio, UI) and story, of course. Taking this route would lead to a relatively standard RPG. I would need to come up with a story and missions, and would also need to spend cash on city terrain assets, and would have to find some way to deal with character and NPC models. That last part frightens me the most, because one option would be to have a character creator with customization options and that requires a whole lot of art assets that I don’t have and don’t have the skills to create. Or I could just go the Deus Ex route and say “you are this person, and this is your story”, trends be damned.
The more difficult path would be to use ORK to handle the above, and add to it the same elements as above, but also to add ancillary systems to the mix. I’m not sure how to get access to ORK from code, but I’m sure it can be done. There’s also a framework for plugins that allow developers to create their own systems to be recognized by the framework, and to hopefully take part in ORK’s features such as loading and saving, menus, events, and variable exposure. This option means that not only do I need to tackle the “easy” paths more difficult structures, but have to figure out how to code against ORK and maybe make plugins.
The bottom line is this: no matter how “easy” any of this seems when employing shortcuts like ORK or Playmaker or other framework, there’s never an “easy” way to create a game. It’s a project, like siding a house or building a boat (a real boat). When we’re living in the house or riding in the boat, we tend to take the work that went into putting these things together for granted, and that’s part of the point of construction anyway — so we don’t all have to construct our own. It’s only when we get down to trying our hand at making something ourselves do we really gain a deeper appreciation for the difficulty and time that goes into the things we enjoy.
In looking into other Unity projects I could work on, I’ve been combing through my Asset Store library to see what cool shortcuts I’d purchased that I could use to put something together. I’ve got a smattering of core assets like models and auto-rigging solutions, but I have a few higher level helper assets like Playmaker that might help bang out something quickly.
One asset that I have is the ORK RPG Framework. This massive asset takes care of a whole host of functionality for creating an RPG including menus, enemy AI, battle systems, items, inventory, and dialog. At first blush, it’s insanely complex, and also reminded me a lot of RPG Maker VX in it’s intent. But in delving into the documentation this morning, I’ve noticed that there’s a lot of options for creating other types of RPGs beyond a Final Fantasy remake.
But what I wanted to talk about was how the developer is operating. ORK by itself is vast, and out of the box it seems like it’ll serve almost anyone in almost any RPG task they want to tackle. For anything else, the developer has opened new features to a crowdsourcing method. If a development group wants a feature, either private for their own use, or agree to include it in the public release, they can commission the developer to work on it. Even better, he suggests that if the community is hell-bent on having a specific new feature — like a grid-based combat system — then they could get together and pool their money like a small Kickstarter campaign to make it happen.
I think I approve of this method. First, it helps the developer prioritize features. Second, it helps to reduce the screaming for “can you make it do X?” because if someone wants it, they need to convince the community to get behind it and fund it unless they can and want to pony up for it by themselves (or on behalf of their company). And third, it’s a good revenue stream for the developer. The update that includes a grid combat system was priced out at $3,200, funding was met, and will be part of the public release package (which is awesome, BTW).
I can see how some folks might not take kindly to this kind of process, though. We’re trained to believe that we should only have to pay once and get everything after that — or at least that’s how many communities behave. While it’s certainly the best case scenario to get as much as possible for as little cost as possible, the long tail of a project requires fuel in the form of capital, and in light of this crowdsourcing system I can see how the “fairness” is being spread around. If the developer only relied on new purchases to fund ongoing development, at some point everyone who wants the package will have the package, and will require the developer to sell a “version upgrade”. I think this system is preferrable, because someone can pay in $5 or $10 or $100 based on how much they want a new feature. And for those who want everything to be free, they can ride the coat-tails of those who are willing and able to pay into the request.
So far it seems to be working, and although I doubt this method would work for all developers, it’s an interesting method for the community to get their voices heard and to get their pet features added into the base framework.
I’m not sure how long I’ve been working on Project Universe. It started as a web game, and then a few initial attempts in Unity, and then back to a web game, and then back to Unity. All in all, I think it’s been something like six or seven years, on and off, since I first decided I wanted to give this game development thing a go.
The idea of having a space trading sim game has been with me for years, then, and for years before that. Post TradeWars, the only games that filled that niche for me were Freelancer and later EVE Online to some extent. The space sim (of any kind) fell out of favor as more money could be had making games with bullets and one-liners, and it was during those times that I decided that if it was going to be, it would be up to me: I had reached the point where I felt I had gotten what I could out of playing games, so the next logical step was to try making games. That put Project Universe front and center.
Being one person with zero game development skills might as well have been one person trying to redirect a river by cupping the water in his hands and walking it to its new course. I had the language skills thanks to my day job, but the mentality behind game development is worlds away from the mentality needed for business application development. Aside from the basest of structures and logic, there’s not a lot of overlap. Learning a language is easy; learning how to use it in service of what you want to accomplish isn’t always so, especially when you also have to learn new paradigms. On top of that is the resurgence of the dreaded maths. I’m able to skirt math of all but the most basic kind on a daily basis, but with game development that’s not a luxury; in fact, it’s worse, as game development requires math plus. Plus geometry. Plus physics. I could also go on about the visual aspects like 3D modeling and UI design, but I think you probably understand where I’m coming from at this point. Game development isn’t as push-button as forum dwellers wish it was, and that’s coming from someone who considers himself fairly intelligent and who works as a career developer.
I’ve tried, and I’ve succeeded in many tasks I’ve set down for myself. I’ve created a rudimentary AI system which saw my NPCs patrolling and moving about. I’ve coded a bastardized pathing system using universally accepted concepts, but modified for my own needs. After years of starts and stops, I have something that kind of works in that you can fly around, dock at stations and leave again, and see life in the universe that goes on about its business regardless of whatever silliness you decide to get up to.
But the thing is, during all the years that I’ve tried various iterations of Project Universe, I have rarely found myself beyond this certain point in this process. I have been re-doing the same work I’ve done several times already for various reasons. Like other aspects, it’s a learning curve, trying to figure out interconnected systems while building and testing those systems and while also making provisions for systems that aren’t even built yet and which might exist only a vague notions. When something doesn’t work, it’s not always just a matter of “fixing it”. Sometimes it’s a cascading failure that shows how ill-advised several other decisions were. The only recourse in a situation like that is to excise that system and rebuild it, taking the chance that anything that it touched would survive the process without the need for additional reworking. But that’s a best case scenario that could probably be survived by those with years of experience in game development. For someone who’s trying to learn his way around the tools and the methods, it’s another molehill that impedes progress.
I’m at the point now where I’ve run into data representation issues again, and those issues are systemic enough that they’re causing major issues throughout what little I have done on the project. I could try and re-work the data structures, which might be doable, but there’s so little “game” around those structures that I can’t see how removing them for review wouldn’t cause the project to collapse to the point where repair would look suspiciously like starting over.
At this point, several years after the idea first started me down a particular road, I think I need to consider that making a space trading sim is not going to work out. It’s ambitious, which is not a word you want to apply to your first foray into a new way of thinking. On the other hand, I can’t bring myself to spend time working on something that I dislike, such as a platformer. I want what I want, and I realize that’s hubris talking: if I ever want to accomplish anything, there’s no reason not to start work on it immediately. Anything less would only delay the gratification, and as an intelligent developer, I should be able to pull it off. That’s what I have been telling myself, but now I think I need to tell myself that it’s not always an application of existing knowledge through perseverance. It’s time. It’s patience. It’s learning. You can’t build a car while driving that car at 90 miles per hour down the highway.
I’ve already learned a lot about development, working with Unity, and a lot of what goes into creating a game. A lot of it is still shrouded in mystery, though, even aspects which I’ve been working with (saving data being the most notable). There’s a lot that’s still left to learn, and everything left to master. I’m going to have to find a simpler project, or a simpler way to approach a more complex project. My goal now isn’t to build something I want, necessarily, but to build something to a point where I can say “yes, this is feature-complete”. It doesn’t have to be be stellar, or even good, really. My early development work was absolute ass now that I look back on it, but those projects were required to get better by learning what not to do as much as it was to learn what to do.
For those who are following the Pathing Saga, I managed to suss out a solution to my “dead-end” woes by reversing the pathfinding attempt should the first pass yield a dead-end from origin to destination. The reason behind the dead-end situation is that while all gates now connect to at least two sectors, some gates are closer to the destination than those that participate in a more valid route, and because we shut down routes that were determined to be “inefficient”, we can’t backtrack or even move away from the destination in order to get back on track. Reversing the process — calculating from destination to origin — helps solve that in tests because the dead-end sector doesn’t even play a part. Should there be a new dead-end scenario, well…we’ll lie and say there’s no pathing possible.
Now that the route calculation is in a form that I can build upon, I have to re-imagine my NPCs as actual interstellar citizens. If you recall (or don’t want to read back-posts to find out), the current NPC implementation is pretty minimal. A merchant will be instantiated at a random jump gate, ID and fly to a random station in the sector, spend some time there to pretend it’s engaging in Commerce, and will then fly towards a random exit gate and “jump” out of sight. For the player, this looks all above-board, like NPCs are doing similar things to what they’re doing, when in reality the NPC is just aimlessly driving around in tight pattern, appearing and disappearing to make things look like they’re Doing Commerce.
One of the aspects of the game that needs attention is making the commodity market move on it’s own. If the player can ID a static route between two stations which allows him to buy at one and sell at another without having to move around to find better deals, then it’s a failure of purpose. We can avoid this by simulating the moving of goods through “other means”, and one way of doing that is by employing the NPC merchants to actually buy and sell goods to get them out from under the player and alter the stability of trade routes to some degree.
Here’s the framework of a new merchant NPC plan that I roughed out on paper:
- Right now, merchants are instantiated from prefabs in a sector where the player is. That’ll be altered according to the following plans.
- I need a new data object which represents everything about a merchant. This data object will be used to record an NPC “personality” in the Master Data Store so I can create “named NPCs” that the player will (hopefully) run into here and there to provide some kind of familiarity over the course of play. Yes, I will name them after people I know, with their permission.
- Some of the more important properties of this data object that will help in the simulation would be the current route, the current sector, the origin and destination stations, a simulation timer, wallet, and current cargo inventory.
- The NPCs would be loaded from the MDS (new game) or from the state file (save game) and put into the merchant pool. This will be what we’ll reference when we need to simulate NPC activity.
- Every simulation tick, we’ll check on NPCs to see what they’re doing right now, and what they need to do next:
- If they’re docked at a station, they need to calculate a destination sector and station based on the goods they have purchased (probably the lowest cost SELL that they can afford and/or fit in their holds). Then they’ll undock and move to the next sector and wait for the next tick.
- If they are “in space”, they’ll move to the next sector in their route.
- If they are “in space” and their next sector is their destination sector, they’ll dock at the destination station, sell their goods, buy new goods, and wait for the next tick in order to undock.
- If it’s determined during the sim update that their current sector is the same sector that holds the player (via global CurrentSector property used to track the player), then we need to slow things down and instantiate a merchant for visibility
- The NPC data object will have a reference to a model which will be stored in state so we have uniformity throughout the rest of the game.
- The model will be instantiated and the relevant data copied from the data object to the appropriate component properties (mostly ship info, but also data object ID for refer-back to the global data store)
- Where the model is instantiated will depend on what the NPC is planning to do next:
- If they need to leave a station, they’ll appear outside their current station. They’ll then move to the jumpgate which leads to the next sector in their route. Jumpgate mechanics will handle the Destroy() and will put the NPC back into “sim mode”.
- If they are passing through a sector to the next sector, they will appear at whatever jumpgate leads to their previous sector. They’ll then move to the jumpgate that leads to their next sector. Again, gate mechanics will handle putting them back into background sim mode.
- If they need to dock at a station in that sector, they will appear at a gate leading to their previous sector, and will move to the station. Once inside the station, they’ll sell and buy as normal via the sim, and will wait for the next tick. If the player is still there, they’ll appear and move. If the player has left, they’ll undock in background sim mode and restart their rounds.
- In the cases where the NPC is buying and selling, none of the activities happen on the prefab; they’ll still happen in the simulation layer (wallet amount, cargo inventory, etc). The prefab instance will have no info on aside from a pointer back to the global data object, and any info we need to use to present a visual to the player (model ID, name, portrait, or whatever).
The sim of all NPCs will be handled by the NPCController which is currently in charge of setting up NPC pools and spawning the instances in a sector. It currently only runs these processes in the active sector, and doesn’t do anything for any other sectors in the known database. I’ll be adding in the simulation process so that the simulation runs through the data and does what it determines it needs to, checks for the need to instantiate, and handles the instantiation using the current logic in the NPCController for merchant NPCs.
So I guess I need to answer the question “why bother”? This seems like a lot of work for something that the player won’t see, and which could probably be modeled easier by randomly instantiating NPCs here and there, and just redistributing commodities via a background process.
The main goal is to allow players to ID NPCs by name. I want there to be some kind of investment in the universe, and when things become familiar, we tend to feel some kind of kinship or ownership of those familiar elements. Even if there’s no direct interaction with the NPCs, seeing the same named ship may provide impetus for the player to, say, defend the NPC from a pirate attack, whereas with a generic new NPC the player might just pass by…or attack the NPC themselves.
Another reason is because I want there to be a level of logic and realism involving what are the player’s “main competition”. If NPCs could teleport between stations, buying and selling, then they could quickly outstrip the player and potentially unbalance the economics by clearing the shelves or meeting commodity quotas before the player has a chance to reach those stations. Since the player is governed by time and relative distance, this puts the player at a severe disadvantage. Simulating the time it takes for a ship to move across several sectors, dock, buy and sell, and undock gives the player some padding to “get ahead” of NPCs. It also allows the player to follow an NPC. With the instantiation plan, a player should be able to tail a merchant to a gate, jump through, and see that NPC on the other side (with some creative license re: timings). They should be able to follow the NPC to their destination, and then see the NPC leave and start a new route. Would a player do this? Maybe they would, just to see if they could, but they could also decide that they want to scan an NPC that crosses their path, and might decide to engage in piracy of their own. In that case, having cargo matters, and knowing when we should and shouldn’t instantiate a specific NPC in the player’s sector also matters. Going a bit further, if the player could open comms with an NPC, maybe the NPC could offer the player an escort job (if the cargo is worth enough) as an ad hoc mission. None of these could happen in a pleasing manner using the current per-sector instantiation method I have in place right now.