Hey Folks! I'm happy to report that today was more productive, and was mostly spent coding an alternative ship-building system. Namely, prefabs instead of tiles.
Prefabs, as mentioned yesterday, are basically items like the bed and fridge I showed in previous builds. The difference is that these are meant to be used to layout the ship itself, not just decorate it. For example, there might be a series of structural prefabs for things like struts and beams, others for straight and corner walls, and still more for floor panels.
Each of these prefabs may be larger than a tile, and like the earlier decorative items, they have a certain grid pattern they need below them to be placed. So things like a wall piece may require that a structural beam be below it, and that the beam's sockets line up with the wall. Essentially, it's like hanging walls on a frame of a house, then adding flooring, etc.
Here's a quick and dirty shot of it in action:
So what we see above is a series of beams, the brown lines that criss-cross behind everything else, which frame the ship's outline. Floor grates sit atop those beams, and white wall/cladding panels attach to the beams to form a perimeter. The green dots are just reference points for me to measure/debug, so they can be ignored.
Walls and floors can only be placed in areas where the underlying structure fits a certain pattern. And the structure itself must be contiguous, so each beam must connect to a previous one.
In this example, everything is laid out on a 32x32 grid. This is the same grid the tilemap would've used if we could see it. But the difference here is that the grid is hidden, and is only used to track things like where different sockets are available to install items. Later, I'm thinking I can have the game review the placed items and structures, figure out which tiles in the grid can be walked on, and use them for other things like air pressure, maybe even lighting? Basically, keep the functionality the grid offered, while using arbitrary prefabs to define the visuals.
It's still pretty crude. Just a few part types and really basic programmer art. But I think the idea has legs. For one thing, it already allows for angular walls and more interesting shapes. I can also probably leverage draw-order to make each type of item render on a separate layer, so we can drill-down from ceiling to wall to floor to substructure, like one does with floors in Sims.
The real question is: will it work in practice? Can I get the crew walking around this type of layout as they did on the tilemap one? And can I get it to look better?
So far, I'm optimistic. But we'll need to see next week. For now, have a good weekend!
Not a lot to show today. The NEO Scavenger sale on Steam is, of course, pretty big news. Especially if you still don't have the game. (Hint, hint.) But in terms of development, today was not as exciting.
For one thing, most of the morning was cratered by errands which had snuck up on us and were past due. So first order of business was to get the house in order.
Second order of business was to take care of some server maintenance. Again, necessary but boring.
In the time that was left, I found myself a bit paralyzed by indecision. Namely, what's the best way to proceed with the prototype in order to get what I want? And actually, this may be a good time to establish exactly what that is:
I want to be able to draw ship layouts similar to Firefly, Millenium Falcon, Cowboy Bebop, and Nostromo. I.e. 1-10 person crews, not capital ships nor fighters.
I want to be able to simulate things like air pressure, gas contamination, fluid leaks, temperature, and radiation.
I want ship systems to lean more towards realism than science fantasy. So more air scrubbers/blackwater management than bubble shields/inertialess drives.
I want pixel art, but I want it to look rich. I think NEO Scavenger looked "okay," but I want people to look at screenshots of player ships and think, "Oh my god, I have to play that." The gold standard, to me, would be something like Megasphere, Galactic Princess, or Halfway. Rich in detail, atmospheric, lots for the eyes to feast upon.
I want crew to be walking around the ship, doing their thing. E.g. Prison Architect and Rimworld.
I've had moderate success with tilemaps so far, but the blockiness kind of turns me off. Even with snazzy lightmap rendering and line of sight, it seems to break down and look too chunky in practice. It kind of looks like an uglier version of Terraria. (Mind you, Terraria sold like a bazillion copies and is much-loved by players. But it's not what I'm going for.) Specifically, I don't like the jagged edges and how it has blocks of black intruding everywhere.
The thing is, tilemaps are useful. For one thing, they're built-into engines like HaxeFlixel, so I don't have to do a lot of work to get them running. They're also easy to extend, so I can try things like cellular automata logic to control gas and fluid propagation, or grid-based AI for firefights or similar. But you can't get away from the blocks.
So that got me thinking about "prefabs." Prefabs, in this case, are just larger sprites that cover more than one grid square. They could be a 3x3 grid with more detail (like a big circle), or a diagonal piece that spans multiple grid squares (to make a slanted wall without the blocky edges). I could even do something where the user lays down long structural beams and "hangs" walls and other equipment on them.
This starts to be something more like a skeleton of a real ship, with macroscopic parts that interconnect in specified ways (e.g. via connectors nodes or sockets). It allows for more visually-appealing designs. And I could even jury-rig the tile grid to control how they fit together, and do something like a post-construction analysis to figure out which grid squares are occupied vs. open.
The thing is, this probably wouldn't work with my current lighting model. The grid-based lighting would have to tell each prefab how to be lit, and either this means whole prefabs have one amount of lighting, or I use the grid to overlay shadows/lights onto the prefab. The former is going to mean large sections looking out of place in the lighting (e.g. bright pieces sticking into dark areas), while the latter is going to mean that blocky look over the nice, smooth parts.
There's also the option to go with a 3D engine to get them properly done. There's a slight chance that hardware shaders can do it in 2D. However, I'd have to delve into OpenGL, and I'm not sure if Haxe/OpenFL/HaxeFlixel is ready for that yet. (Or if it would even perform well with a large number of lights.) But a 3D engine does this handily. It's the core feature. But I'd have to learn a new engine.
I don't know. Maybe I need to abandon the lightmaps. Maybe they're not worth the trouble. Halfway and Galactic Princess, above, go without them (as far as I can tell). So maybe hand-drawn lighting is the best compromise.
I'll have to think about this some. If anyone reading this has seen other games that do this, let me know in the comments!
Hey Folks! I managed to get a new tileset done in order to experiment more with lighting and layouts. This one uses 10x10 tiles instead of the last one's 32x32. Also, this one has a single, dedicated material type per tile, while the last one was "straddling" 2 or 3 materials per tile.
The result? A mixed outcome. See for yourself:
First, the good. Lighting behaves better now. You can see several places where walls have light differences on one side vs. the other. This can be different-colored lights, or light/shadow differences. So score one improvement.
Also, the smaller 10x10 grid size means the lightmaps look a bit better. Shadows cast around corners and other obstacles are more discernable, and look a bit better as a result. The old 32-pixel tiles were so large that one rarely saw these shadow "rays" on the map. Score two.
Finally, the map itself can support more detail per human-sized area. The walls can be thinner, and the room/exterior shapes more detailed. One can get closer to the desired aesthetic they seek using smaller tiles. (I.e. better layout resolution)
Now for the bad.
The small tiles look positively boring compared to the 32-pixel ones:
Smaller tiles have less room for detail, so they have less going on per-tile. And what's more, their small size means they repeat more to cover the same area as a larger tile. Lose one mark for repetition.
Smaller tiles also have the issues with pathfinding/walking overlapping with larger human sprites. It's fixable, but it's more work to setup. (E.g. adding special non-walkable floor tiles to "pad" between wall and floor). Lose another mark.
Finally, the increased tile count means the engine has to work harder when calculating lighting, pathfinding, and other per-tile algorithms. This can be mitigated by limiting the frequency of said calcs, but it's already an issue with as few as a dozen lights in the scene.
Now, to be fair, these pluses and minuses are not all equal. Performance isn't a huge concern in a game like this, where I can probably only calculate lighting or pathfinding when something major changes.
Also, it isn't exactly fair for me to compare the snazzy 3-part (outer cladding/structure/and inner wall), 32-pixel tiles against 10-pixel tiles with only the cladding and interior walls. The smaller tiles could have more variants to break up the patterns. I could add a set of structural tiles to sandwich in between cladding and interior walls, etc. I could even add a few multi-tile pieces (e.g. a sloped corner that spans 2-3 grid squares) to spruce things up.
However, I'm also having doubts now that I see the lighting in action. For example, certain inner corner tiles are completely black due to being surrounded, despite lights being near. And the harsh transition looks bad. (See the top of the ship, where the outer white and inner blue light hit the jagged slope.)
And while watching Mal walk around the ship with his line of sight sweeping rooms is cool, I'm not sure it'll be fun. Nor may it be sensible if I decide all crew LOS can be seen at once.
Food for thought, this is. Though, this is exactly why prototyping is good!
Oh, and in other news, this switch to 10x10 grid exposed some tilemapping bugs that I fixed today. And also prompted me to write code to save and load the working ship layout to a file between sessions. So not a total loss by a long shot!
Anyway, I'll let this steep in my brain overnight. Tomorrow, maybe I'll try adding a few more tile types to spice things up. See if it resolves any doubts. Or maybe it's time to switch back to crew sim for a bit, and make more "game" to play. We'll see!
Hey Folks! Today was sort of a mixed-bag of work spread across NEO Scavenger, NEO Scavenger Tablet, and the space prototype.
First, Kaaven pointed out a pretty significant bug in NEO Scavenger's treasure code. (Thanks, Kaaven!) Looks like any time treasure was giving out a range of x-y copies of an item, the game would only give x-(y-1) copies. This turned out to be an integer-rounding error, and I've changed the code to correctly round-up when appropriate.
The batch of NEO Scavenger fixes is getting a bit longer, so a new build may be due soon.
Steve also needed some additional sound assets for NEO Scavenger Tablet, so I uploaded those. Namely, the audio for environmental sounds and music were embedded in a different way than normal audio, so I needed to add them separately.
Thus began an hour-long wrestling match with Git GUI, a front-end to a version control system. Now, version control systems aren't known for their user-friendliness, so some opaqueness is to be expected. But man, Git is a special beast. The level of redundant-sounding commands beats even the worst VCS systems I've used in the past. I want to get some files. Do I Clone? Checkout? Branch? Pull? Or Fetch?
And when done? Do I add? Push? Commit?
I get that people don't like typing more than a few characters on the command-line. But come on. Also, it doesn't help that nearly every "tutorial" on Git starts with the preamble "let me tell you something about the history of version control..." Ugh. Just tell me what commands a human would type for a simple checkout/checkin process. Pretty please?
Anyway, I got that working despite the documentation's best efforts.
Finally, I've been thinking about alternate ways to handle ship tiles to satisfy some basic rules:
Outer walls only lit by outside sources.
Inner walls only lit by inside sources.
Humans don't overlap into non-walkable tiles when moving around.
Structure between inner and outer walls remains unlit (optional).
I think my first attempt is going to be a smaller grid (10x10) where each tile is a single material type. E.g. floor, inner wall, outer wall, etc. The smaller size means I can make walls thinner compared to the current 32 pixel humans, and generally get more detail/granularity in ship layout.
It also, unfortunately, means pathfinding might cause overlaps unless I add special "padding" between open floor and walls. E.g. some floor adjacent to walls might be unwalkable.
And finally, it also seems like I'll have to divorce pathfinding flags on each tile from lightmap calcs.
So, work began on that today, and continues tomorrow. Have a good night, all!
Hey folks! Hope everyone had a good weekend. I sort of violated one of my rules this weekend and did some work in my brief free time. I had a real hankering to work on some pixel art spaceship stuff, so I couldn't help myself.
Up until now, I've been using a hacked-together, green ship layout tileset I made many years ago. It was a 10x10 grid tileset I bumped up to 32x32 crudely. Neither the art style nor the quality were my goal, so I set about working on some bespoke 32x32 tiles for this prototype.
Here's a shot of what I came up with:
Now there's a lot going on in this pic, so let me break things down.
First, the new artwork. I drew some new tiles which combine a white exterior cladding with rust-colored girders/structure and blue-tinted interior walls. The floor is also a rust-colored grating. I think it's a big improvement over the old tiles, for sure, but still pretty basic. Even so, it's a step in the right direction, and more importantly, has revealed some new questions I need to answer about the game. But let's put a pin in that for a moment.
The second thing you'll notice is that there's a big white line down the center. This is where the image is split between a flat "diffuse map" renderer and a "lightmap" renderer. (A crude lightmap, but bear with me.)
"Diffuse map" just means the tiles are drawn without any shading. The input images are drawn on-screen as they appear in the files. This is on the left.
"Lightmap" means the tiles are tinted according to nearby lights. Some tiles can block light (such as walls) while others don't (like floors). This is the right side.
Now, this may not be the best map layout to illustrate, but it's what I screengrabbed, so we'll work with it. Notice that the left side is the same brightness everywhere, and doesn't look too bad. The right side, on the other hand, has variable brightness, including a completely dark room. You can also see how the lights affect nearby walls and floors, with the tiles getting darker as distance from light increases.
Here's where the question comes in. Notice how the lights inside the ship are illuminating the outside cladding of the ship? It's also happening on interior walls, but the walls are darker so it's hard to tell.
This is due to the way I've drawn the tiles. In this tileset, a single tile can "straddle" up to three materials. E.g. an outside wall has 1/3 cladding, 1/3 rust-colored structure, and 1/3 interior blue wall. However, the lighting engine doesn't know that. It just sees a single tile, and lights the whole thing.
So my next experiment was going to be creating a tileset where each tile is a single material. One whole tile for cladding, one for structure, and one for interior wall. In theory, this would mean exterior cladding (and even the rust-colored structure) would remain unlit in such a tileset, and the lights would only affect interior walls. It would also mean that interior dividing walls could be lit separately from either side.
However, the trouble I'm running into is that 32x32 tiles look way too "thick" for each of those materials. In order to have a double interior wall (like we see between two adjoining rooms above), that'd be 64 pixels thick. And with humans only 32 pixels wide, that's one heck of a thick wall :)
(I can sort of bypass this problem on the outside cladding since only one side of it needs to connect to structure. The other is exposed to empty space, so I could make them less than 32 pixels thick, if desired.)
Now, one's first instinct might be to "just make humans bigger than 32 pixels" and/or make the tiles smaller than 32 pixels. However, then we start to run into another problem: the game gets a bit weird when the human size doesn't match the tile size. Humans start clipping through walls when they walk around. E.g. they'll see that a 16x16 tile is walkable, and move into it, but they'll overlap into the adjoining wall tile without triggering any problems in the pathfinding code.
It's probably solvable, but it breaks with Flixel's standard pathfinding algorithm. So I'll need to write my own code atop it if I want to do that. Not sure if it's worth it. (Then again, I'm already writing my own stuff for the lighting, so maybe...)
Anyway, food for thought. It was a welcome break from boring UI and data-parsing work, though :)
Hey Folks! I'm happy to report that today just about made up for yesterday's lack of progress.
First of all, I believe I have item code working now. It's crude. It's going to need some cleaning up to make it more maintainable. It's even lacking features. But it works.
Basically, I added some more code to handle situations where items have no parent item or crew, such as items on the floor of a ship. If an interaction says to remove self, the parent item/crew/ship will do so when the interaction executes. My test case was for a hungry Mal to query the ship for any food, walk to where a food packet was lying on the floor, "SeekFood" on it, and it replied with "SeekFoodAllowDirect," delivering StatFood to Mal while deleting itself from the ship.
I also added a special item to the game called "[us]". Like the same phrase in NEO Scavenger, the game will replace [us] with whomever is acting. So if "YellowFoodPacket" has an interaction that removes "[us]", that interaction replaces "[us]" with "YellowFoodPacket" on-the-fly. This way, one interaction can be used for multiple items or crew members, instead of needing one specific interaction per item/crew type.
Today's other major breakthrough was being able to debug a Haxe Windows app (generated by HXCPP) using MS Visual Studio Express (MSVC).
I use FlashDevelop to write Haxe code. Partly, it's because I'm so familiar with FD from my Flash programming days. But also, it's one of the few IDEs with decent Haxe integration.
However, one of the drawbacks of FD is that it cannot directly debug a C++ (CPP) app. (It was designed to debug Flash AS3 code, which it does well.) It writes Haxe code, which gets converted to C++, AS3, HTML5, or whatever target you're aiming for. If I want to compile my app to Windows, FD actually uses a library called HXCPP to generate C++ files, talk to MSVC and compile them into a .exe. Setting a breakpoint in FD does nothing in the C++ app.
Enter MSVC. Also enter the always-helpful Lars Doucet, who pointed me in the right direction. (Thanks, Lars!)
MSVC has the ability to "attach to process", which basically means it'll start monitoring a running app. Provided that app has debug info/hooks, MSVC can trigger breakpoints (pause the app), examine variable values at that moment, step forward, and show a host of useful information about what the app is currently doing.
And fortunately, HXCPP generates these debug hooks!
In practice, one just has to F5 compile their Haxe Windows app, wait for it to launch, then tell MSVC to attach to that app's process. Then, one can use MSVC to open any .cpp file in the generated C++ code, toggle a breakpoint by clicking the sidebar, let the Haxe app run, and MSVC will pause/step forward/show locals/etc.!
Spoiler: Highlight to view
Open the .hxproj Haxe project in need of debugging.
Using the dropdowns at the top of FlashDevelop, select "Debug" and "Windows" from the available options. (Ctrl+F5 and Ctrl+F6 also toggle these.)
Hit F5 to compile the project for Windows. Wait a few seconds to a few minutes (depending on project size and whether it's been compiled before) until the application finishes compiling and launches.
Open MS Visual Studio Express.
Look for a green arrow at the top that says "Attach..." and press it (or use menu Debug->Attach to Process...)
At the bottom of the resulting "Attach to Process" dialog, search the "Available Processes" list for the Haxe project, and select it.
Open Windows Explorer and navigate to the Haxe project's "bin/windows/cpp/obj/src" folder.
Drag a the .cpp file in which you want a breakpoint into MS Visual Studio Express. (You can alternately just open the .cpp file from MSVC's File menu.)
Search for the line of code at which you want to insert a breakpoint.
Click to the far left of the line of code. A red dot should appear.
Switch back to the running Haxe app. (Depending on where your breakpoint is set, you may need to trigger something in the Haxe app to reach that point in code. An easy place to start is a per-frame update method.)
Begin using debugging tools. F10 and F11 to step through the code, hover mouse over variables for value info, examine call stack and locals, etc.
When done, you can either hit the red "Stop" button at the top of MSVC, or close the app if it's accessible.
Now, fair warning: it's ugly. The generated C++ code isn't as human-readable as the raw Haxe code. A lot of the same var and function names are in there, but you'll also find a lot of generically-named temp variables to wade through. Fortunately, HXCPP injects a lot of debug info that can help humans map between raw Haxe code and the generated C++. E.g. you'll see a lot of "HX_STACK_LINE" calls with line numbers that correspond to the Haxe code. So prepare to alt-tab between MSVC and FD quite a bit.
Still, being able to break, inspect locals, step into and out of functions was a real help for me today as I was debugging the item interactions. So hopefully, typing all this out will help someone else in my situation down the road!
I'm actually pretty excited about reaching this point. Not only do I have rough item logic in the prototype now, which is a milestone in itself, but also now I have a powerful tool for debugging non-Flash output from Haxe!
So today was a bit of a wash. The library updates I downloaded yesterday played havoc with my prototype, and I spent most of the day installing, uninstalling, reinstalling, and reverting various pieces of software.
Near as I can tell, my problems started with updating to Haxe 3.2.1 from 3.2.0. It seems that multiple inheritance was broken (deprecated?) by the update, so any classes that extended or implemented more than one other class failed to compile. Since quite a few classes in HaxeFlixel fit this category, I couldn't compile anything. The error I was getting looked like:
'set_x': is not a member of IFlxUIButton_obj
for anyone else stuck in this rut. Basically, set_x was a property on one interface IFlxUIButton implemented, but Haxe didn't see it anymore.
However, this is hindsight. At the time, I thought "maybe this is a compatibility issue with Haxe 3.2.1 and my older libraries." So I updated my libraries. At first, as few as possible. And when that didn't work, pretty much all the rest. Among these was updating hxcpp, which I think (keep reading) somehow broke the link between Haxe and Visual Studio (used for C++ targets). Namely, I kept getting this error:
Process creation failure : cl.exe
cl.exe is a binary within the MSVC .../VC/bin/ folder used by hxcpp (I think) to make a MSVC solution on-the-fly and then compile it to create a Windows binary. And it'd get called a few times before crapping-out with the above error.
I poked around for anyone else having this issue, and the common reply was that it was a mismatch between hxcpp and MSVC versions. Most users reported reinstalling MSVC from the MS website (not lime setup windows) fixed the issue. And it sort of did, but...
As part of launching the updated MSVC install for the first time, I was asked for login info. This reminded me that a Microsoft site asked me to change my password this morning for security reasons. Could that have been it? The cl.exe issue wasn't present yesterday. It's quite possible my login info was preventing MSVC from doing anything via command-line until I updated its little login widget. Which is kinda annoying and troubling at the same time.
Whatever the case, either updating MSVC or the login fixed the cl.exe issue.
Then, it was off to fix compile issues. This time, JoystickEvent didn't exist in OpenFL Next, but HaxeFlixel still thought it did. I callously just commented-out the whole joystick bit from HaxeFlixel to see if that would work. And it did. I was fine with that ugly hack (and feature cut) for now, as I suspect I'll update all these libs again before needing any joystick support (if ever).
And THEN, color issues. It seems something between OpenFL 3.3.6 and 3.3.9 borked the color byte order, so all my reds were blue, and vice versa. Took me a bit of sleuthing to figure that one out, so I decided to just revert to 3.3.6 for now, and voila, back to working project.
It was a pretty ugly day. By the time I had working tools again, I was so spent that I decided to just tinker with some ship part sprites. I didn't manage to do much more than change a pattern and color scheme before it was time to write this devlog. And here I am.
The good news is I'm up and running again. The bad news is that I wasted a whole day doing what amounts to nothing.
Today was sort of split into two parts. The first was coding, and the second was gamedev community.
The coding stuff was a continuation of yesterday's item work. As I was finishing up the item transfer code, I noticed a few things that would need fleshing-out. Things like retrieving nested items on a target (e.g. an item from within a container the crew was holding), and code to make sure items correctly updated parent/child relations.
I also made some changes to the way crew queries their surroundings for items and crew to fulfill their needs. Previously, they asked the ship for a list of compatible items/crew for their need. Now, they first check their own inventory, and then the ship.
I still have to test this, but most of the code is done and compiling.
The community aspect of my day involved discussing some ways to help improve HaxeFlixel with Lars. Since I'm using it for both NEO Scavenger tablet and this new prototype, he was pinging me for some input on what I use, what works and doesn't, etc. During which, I explained a lot of the textfield issues I encountered.
Since this was news to him, he encouraged me to submit a bug. So part of my day was building a test case to illustrate the bug, and that meant updating my libraries. (Haxe 3.2.1 has since come out, as has OpenFL 3.3.9 and Lime 2.6.9.) I've submitted my bug, along with sample code, and hopefully some folks find that helpful in pinning-down the issue!
I also agreed to send him a wishlist of features and fixes I'd like to see to make HaxeFlixel my go-to engine. So I'm going to spend some time thinking on that before sending it over. A couple of the things may have already been added since I last checked (such as shaders, woohoo!). And my list may actually be pretty short.
Anyway, minor progress today. I'm hoping to get more gameplay stuff in tomorrow. Have a good night, all!
Today was a pretty productive day. Since the baby decided to poop pants and flip-out at 5:30am, I decided to just stay up and start work early. As a result, a got quite a bit more coding done today.
The main thing on my plate was getting items more fleshed-out in the prototype. Namely, I wanted to make sure items were reading from and writing to data files appropriately. This meant some more JSON handler code, and discovering that built-in JSON functions don't like Map classes in Haxe very much. They seem to write out okay, but cannot read-in. So instead, I did some conversions to and from string Arrays for the affected data fields.
Once that was done, I did a quick test to make sure the ship-building mode was still working, and it mostly was. I noticed a few bugs with the way items cloned and their lights rotated, so I had to fix those. And I also made the lights' position offset apply to both the source of light and the sprite appearance of the light, since the latter wasn't being affected by that offset yet.
Then, I decided to add buttons to the editor and ship-builder screens so I could switch between them without restarting the app. If I can keep this working, it might mean the players can load the data editor from within the game if they want to rapidly mod/test/edit/test.
Finally, I got started on adding a rudimentary inventory to each item and crew class. This meant methods for adding, removing, and getting references to items in each inventory.
With those in place, I started adding code to add/remove/transfer items when an interaction is performed. I think I have the code ready on Crew, and I just need to copy it over to Items before I can test it out. My first test will be interacting with a food packet vs. with a fridge, to see if the crew will get stat changes and inventory changes, accordingly.
Actually, I'll also need to add default inventories to items so the fridge starts with food packets inside it. This might mean I need to tackle treasure specifications sooner than later. But I might be able to squeak by for now by just specifying items' contents directly.
Feels good to be coding game stuff again, instead of editor stuff!
Hey folks! Hope everyone had a good weekend. It was more or less a baby weekend, here, as we struggled to take care of normal life stuff while not making the baby cry. Saturday night was particularly rough. I managed to sneak in an hour of playing Brigador, though, which was a nice break. Still in early access, but already a fun romp reminiscent of Desert Strike, Mechwarrior, and Syndicate on the Sega Genesis.
I actually authored data today in the editor! This time, for real! I basically just did the same thing I was trying to do Friday, but this time, all the bugs seem to be fixed, and I could successfully save modified data out to JSON and read it back in again. Cool!
As you may recall, the data I was modifying was to make way for a new type of interaction: giving food stat directly vs. giving a food item that can later give food stat. Basically, a prototype of how containers and consumables might work.
Almost before I finished modifying the relevant interactions and conditions, however, I started wondering: is the condition and trigger system strong enough to build upon? As I started to imagine situations where an AI should only do something if it had 1x an item, 3x an item, or other arbitrary numbers, I wondered if using conditions as they are now would make data maintenance a nightmare.
Would I need a special condition for Has3xItem, Has5xItem, etc? Should I be testing things differently? Also, should I be listing added/removed/transferred items in an interaction individually, or similar to how NEO Scavenger does it (with a treasure group)?
I spent hours on this. I even started typing my thoughts out in a text file, where I often find answers just by asking questions and thinking "out loud." I started to imagine what it would entail to make these changes, and I came to the realization that maybe now's not the right time to be mucking with data formats again. I just got them working in the editor, after all. And this might be a situation common to programmers where they over-engineer a solution before they've proven they need it.
So I deleted the text file, and resumed work on a dumb/brute-force solution for now. Interactions list items individually. No fancy modifiers or probabilities. Let's just get the damned thing working, and only add bells and whistles when absolutely necessary. Been digging down this rabbit hole too long now, and need to get back to gameplay!
As of now, I have most of the item stuff added to the game. Previously, Items were a hard-coded placeholder, so I had to start making items something that other game objects could refer to by name in the data. I have the interaction UI hooked up to accept items already, and a chunk of the data format in the code. I just need to finish the bit that reads and writes the JSON fields into the right places, and I should be able to resume prototyping food.
After most of a day spent hooking-up the remaining Interaction fields and handlers, I managed to edit some things! Sort of.
Specifically, I was able to modify the SeekFood interaction chain to accommodate two paths: getting food stat directly vs. getting an item of food which can be used later. It involved editing an existing SeekFoodAllow interaction to only apply to things which are food (renaming it to be SeekFoodAllowDirect), and add a new SeekFoodAllowItem interaction that only applies if the party has a food item.
And to signify either of these conditions, I created HasFood and IsFood conditions, and hooked them up accordingly. Then, I hit "save," and voila!
You see, when I hooked-up all those data fields to update game data on-the-fly, I forgot one thing: if you rename an item to match the name of an existing item in the game data, it overwrites that data quietly in the background. So as I was typing "SeekFoodAllowItem" in the name field of my new interaction, I briefly had a moment in the text field where the text read "SeekFood," and that steamrolled my original SeekFood interaction. And as I kept typing, the old interaction was lost forever in its wake as the new one kept updating it's name.
So I think one thing I'll do Monday is to skip updating game data if there's a name conflict, and highlight the field in red to make it clearer. This way, the old data will be preserved, the user warned, and worst-case scenario is that the newly-created data won't get saved due to the conflict.
But yeah! Editing! It actually went pretty smoothly, otherwise. Jumping between editing interactions, creating conditions, and back again to link them, all went pretty quickly. Way faster than hand-editing text files! (And way easier to keep track of.) Hopefully, this means I'll be back to prototyping game data again soon. (Though I suspect Items will need to be brought up-to-speed soon, too, for more crew actions to be possible.)
Oh! And in other news, it appears that HaxeFlixel just got an update that allows for custom shaders per-camera. This is perhaps one of the most-wanted features on my wishlist, as it allows for cool things like normal-mapped sprites (e.g. sprites with light and shadows playing across the surface) and other effects. Some very cool possibilities may have opened-up!
I finished hooking-up the Conditions UI to the data in the editor today. Now any field I change in the UI immediately changes the loaded game data, and I can choose to save that out to JSON files by pressing ctrl+s.
I had to add some special handling code to this latest UI to make sure it was adding/removing data in lists in the right way. I was originally assuming any time a user selected something it would be tacked-on at the end of a list. But in some cases, the user will be changing a listbox earlier in the stack, and the game data needs to update accordingly.
E.g. if a sleep condition applies triggers sleep01, sleep02, and sleep03, and the user changes sleep02 to sleep02a, the editor needs to update the second item in the list, not just plop a new sleep02a at the end of the list.
As you might have guessed, this also meant going over the previous UIs I've built to make sure they handle similar situations. However, since I had to go over them anyway to hook-up the rest of their fields to the game data, that wasn't too far out of my way. As of this evening, I've updated EditCondTrigger to use this new handler code, too, and all of its fields are hooked-up.
Tomorrow, it's time to tackle the hook-ups for EditInteraction, and make sure it has the requisite handlers for lists. I'll probably skip adding a UI editor for colors, since they're trivial to edit by hand. (It'll mean having to reload the editor if I edit colors, but I'm willing to lean on that crutch for now, until it becomes more of a pain.)
I managed to successfully convert all the prototype's XML data over to JSON, and update the game to read and write JSON. It simplified code quite a bit, in exchange for some extra JSON read/write handlers within each class. I also learned that typedefs are not available at runtime, so I had to do without some type checking in the JSON code. It's poor programming practice, but I chalked it up to "get it working first, and optimize later when there isn't time left and you can forget about it."
Once the game was using the new JSON data, I started work on the condition editor UI. Looks like it'll be mostly like the UIs I already created, so it's mostly copy-pasting chunks of code and modifying as-needed.
I also think there are still quite a few data fields that need event handlers attached to them so they talk back to the game data when they are edited. But once that is done, I think we're "go" for editing. I've already got ctrl+S hooked up to save all data back out to JSON.
Hey Folks! Hope everyone had a good weekend. Our Canadian Thanksgiving was sort of a fizzle. Our dinner plans fell through, and our back-up plan was closed for the holidays. Rochelle at least made a pumpkin pie, but then the local store was out of whipping cream. So we just bought ice cream and went to town on pie and ice cream. Still kinda missed our turkey, but leftover chili and pie wasn't bad!
I finally finished up the condition trigger portion of the editor, and it seems to be dealing well with the data. I added a few event handlers to it today so it would automatically update the game data any time fields were edited. This, of course, meant a bit more time was needed adding clean-up code for the handlers. But all-told, it was not too bad.
Before tackling the condition portion of the editor, I thought I'd see about writing the data out to files again. And since a lot of folks have recommended JSON instead of XML format, I decided to give that a shot. For those wondering what JSON looks like, here's an example condition trigger in JSON:
It's quite a bit easier to use than NEO Scavenger's XML data. I can avoid writing a lot of XML parsing/formatting code. And for modders, it should be easier to navigate and edit this format. Though to be fair, XML can be made similarly easy to read. NEO Scavenger just used the default mySQL XML export, which is a bit more bloated than needed.
Anyway, Haxe conveniently provides some built-in JSON parsing and "stringifying" code. Basically, I can just feed Haxe an object from the game, say Json.stringify(TDcAltruism), and I'll get text output like what you see above. And reading that object in from a text file is just as easy: Json.parse(txt) (assuming one has already read a file into the txt variable, which is similarly easy in Haxe/OpenFL).
The only complication I ran into was my own fault (as usual). I assumed Json would automatically cast the data it was reading into the correct format for the container I provided, which it didn't. This caused some strange memory referencing errors that confused me for a while before I figured it out. Once I wrote some code to manually transfer the Dynamic object's values over to the container's fields, it seemed to work smoothly. (That, and I needed to add some special handling code for default values that needed to be +/- Infinity instead of a finite number.)
As of now, I'm able to write out all CondTriggers to JSON and read them back in again, and I'm thinking I'll just covert all my XML data to JSON. And when that's done, I'll probably go back to tackling the editor for Conditions, and then start authoring some data!
Oh! And I had another sort of brainstorm over the weekend, regarding AI getting food from fridges. Basically, I can probably just create a new type of interaction that fridges have, which gives an item instead of a condition to the petitioner.
AI uses "SeekFood" on a food item: interaction response is "GrantFood" which decreases AI's hunger directly.
AI uses "SeekFood" on a fridge: interaction response is "GrantFoodItem" which transfers a food item to AI. The AI can then use "SeekFood" on the food item on their next turn.
The above case can make use of interactions' built-in "aCondTrigsNext" field, which describes what the petitioner expects to get next from this interaction. Both "GrantFood" and "GrantFoodItem" can be set to yield "Food" to the AI, so it will seek them equally.
The only changes needed to support this are to add which items "us" and "them" get in an interaction (and code to transfer said items), as well as AI code to check one's inventory first before seeking other AI or furniture to fulfill a need.
Seems pretty doable, and requires little reworking of existing systems. Might be a good full-scale test of the editor once it's done!
I think I've just about finished the interaction editor component. The last few things I added were the ability to add a new link to another interaction (i.e. continuing the chain), breaking a link, breaking all incoming links (i.e. orphan an interaction), and delete an interaction from the data entirely (unlinks all, then deletes the data permanently).
With these in place, I think all the tools I need to author interactions are in place. I also added a small feature to improve user-friendliness: backtracing. Anytime an interaction is added to the screen, the editor will find any unrelated interactions that point to it and add those, as well. My thinking is that it'll be useful to see if an interaction is linked from elsewhere before editing or deleting it, as it could have repercussions in other interactions.
That all seems to work now, and is just missing something to save the data back out to XML. Before I do that, however, there are two other pieces to the editor that I'll need: editing conditions and condition triggers. Since interactions are largely collections of these condition and trigger objects, it makes sense to be able to quickly edit those data types while working on interactions.
Since triggers are a simpler data type, I set about tackling them first. And since I started that task at a little after 4pm, I didn't finish it. I'm actually pretty far along, though. I think most of the UI is authored, and the logic for the UI is in place. It's mainly fixing compiling errors and then testing it left, which I'll start next week.
Speaking of, Happy Thanksgiving! Canadian Thanksgiving is Monday, so I won't be in the office then. I'll probably be sitting lazily about the house, digesting and trying to play games and read in between baby-minding. Hope everyone has a good weekend, and see you Tuesday!
Compared to the past week and a half, today's progress was a serious leap. The editor is getting very near a point where I can author content in it, and it's already useful for showing data relationships. It's impressive how fast stuff gets done when you're not struggling against the tools!
The above is a composite shot of a whole interaction chain with an inset below it zoomed-in. Specifically, this shows the sleep interaction cycle, starting on the left and following a chain of interactions to the right until it reaches the far right, and either exits or loops back to the beginning.
Each of the nodes along the way include a name, a description (what the user sees, if applicable), a series of required and forbidden conditions us or them must have to see this node, and a series of triggers which control whether certain conditions are applied to us/them.
A lot of the stuff I added today involves these trigger and condition fields. I basically added some boxes to the UI that let me arbitrarily add or remove triggers/conditions in each category, as well as pre-populate the data the interaction already had defined in the xml.
I also started adding some code to let me add/remove whole interaction nodes (the big blue boxes between arrows). This should hopefully allow me to start building and modifying interaction chains.
Some of the stuff yet to come includes:
The ability to add a new arrow to an existing interaction (e.g. building chains)
The ability to write all the modified data back to XML. (And possibly modify the data format so it's easier to read/edit)
A way to add new interactions to the game data (i.e. create an empty interaction, fill-in with data, and save it)
A similar way to visually edit conditions and condition triggers
That last one might be complex, but hopefully easier than it was to get this first editor done. And I'd kind of like for it to be usable from within this editor (maybe as a pop-up or modal screen).
By the time I'm done, I'm hoping I can start authoring and reviewing interactions, conditions, and triggers in the game more quickly and error-free than I was via text-editing multiple XML files.
Now that I've got a better handle on how to make UI stuff happen, I've been making pretty good progress on the editor.
By the end of the day, I was able to get an interaction to display on the screen, with arrows pointing to downstream interactions it can yield, and each of those pointing to their respective yields, et al. It was also able to loop back onto itself, if appropriate (e.g. sleep cycle). Clicking and dragging would update the interaction's position, as well as all connected arrows.
The editor would also clear the screen and start mapping anew anytime the drop-down in the top menu was changed.
The next thing I'm looking into is adding UI widgets for each condition trigger (CT) on an interaction. There are CTs that describe things that happen to the petitioner/requester in an interaction, those applied to the granter as a result of being asked, as well as those that might happen as a result (used by AI in determining which interaction to seek next).
The way I picture it, any time a user chooses a new CT from the drop-down on an interaction, it adds a new CT widget below it to allow the user to select another one later. And deleting a CT removes it from the list, moving all CTs below it up one. (Like adding/removing rows in a spreadsheet).
And if I can get that to work, perhaps I'll add a widget to allow editing of the CT in a pop-up, which will update all game data referencing it. And if I get that running, I should be able to quickly edit the CTs for a given interaction. I'll also need to do a similar thing to the list of required/forbidden conditions on each interaction, as well as the ability to add a new downstream or upstream interaction.
And then, get back to editing game data. E.g. figure out how AI can seek items (food) from an object (fridge) that dispenses things which grant a stat boost (hunger). Probably a data reformat to make it easier to read/search in plain XML wouldn't be amiss, either.
Lots of work! But it's good to be doing actual work again, instead of flailing ineffectually with libraries.
Ok, I think I'm better now. As usual, several hours away from the problem, a good night's sleep, and explaining the problem to my charitable wife, all seem to have calmed the feckless rage from yesterday. I was able to think of one or two more things to try, and we're getting some traction again:
Basically, since the StableXUI library seems to prefer UIs done in XML, I decided to revisit making the UI in XML. I originally gave up on it when I ran into trouble getting references to each UI widget at runtime. I'd load up one blob with some text from a game object, and upon trying to do the same with the next blob+game object, ran into name collision crashes.
Upon further investigation, however, I noticed some documentation stating that I could edit the widgets' ID after it is loaded. And if I apply some algorithmic naming convention to things, I can make each blob's widgets names both universally unique and also easy to figure out/point to. (Essentially, the original widget ID plus a unique number for that blob.)
Once I got that working, I went back and recreated my widget blobs in XML. And as progress was made, I started adding data to the fields, layout parameters, and color schemes. I ran into some trouble using the StableXUI drop-downs, since they aren't really designed for dozens or more options (runs out of screen space). So I borrowed my hacky scrolling drop-down from the NEO Scavenger Editor project.
Finally, I arrived at the main challenge: figuring out how to display the relationship between in-game interactions visually.
The screenshot above shows the beginnings of an idea at work. A drop-down at the top left allows the user to select which interaction they want to inspect/edit. I've chosen "SeekAltruism" in this case, and it will point to both "SeekAltruismAllow" and "SeekAltruismDeny" replies, seen on the right. I want to draw arrows kinda like the blue one on the left running from origin to destination for each pair. And probably continue the chain of interactions in a branching way until they run out of replies.
This way, I'm hoping I can visually make sense of how the interaction chains look. Where it needs more variety, where circular loops might be, etc. That'll be tomorrow. Tonight, a beer to reward myself. And maybe some humble pie for yesterday's impatience :)
Hey Folks! Hope everyone had a good weekend. More of the same here: baby stuff, chores, and brief snippets where I get to read "Leviathan Wakes" and play a bit of "Duskers." Enjoyable, both, but gone are the days where I can sit down for more than 30 minutes at a time, though :)
Before resuming work on the editor today, I decided to see if I could integrate my textfield changes back into Github. It took about an hour to setup Github and create a test project using my fork of OpenFL. And then about another hour of me climbing down the rabbit hole of OpenFL TextField states before I decided this wasn't going to happen. The thing I've done to make it work for me makes some serious assumptions about the situation that won't apply to most. (TextFieldTyle = INPUT instead of DYNAMIC) And doing it the "right" way would mean rewriting TextField to untangle the text selection from the text input code.
Maybe some other time I'll do that. But it's been over a week since I've made anything resembling progress, and I'm desperate to move forward on something. Sorry open source community!
Turning back to the editor, I almost immediately hit another hang up. (FFS!) This time, I think it was neko target and/or OpenFL "next" incorrectly detecting when the game loses focus. I'd click in a text field, then click outside a text field, and the whole app would "pause," locking out all other input. Alt-tabbing would unpause again, but this was not going to be workable. Clearly users would need to click things in the editor without HaxeFlixel locking them out every few seconds.
I briefly considered making a new "data editor" project that just used OpenFL and ditched Flixel. I could then ship the game with an app to play and an app to edit.
However, I quickly realized that I'd need to do some fancy source-sharing between two projects to ensure parity between the data classes and data-reading code. No way. I'm not going to test out FlashDevelop's code-sharing tools. Not after a week of mind-numbing agony trying to get just basic code features working.
So I decided to make my project load an OpenFL-based editor right from the get-go. Later, when I have more patience, I can make a menu screen to let the user choose between play mode and edit mode, and load Flixel or not accordingly. For now, though, I'm hard-coding the damned thing so I can get something on-screen.
After this, I finally had a couple hours of productivity, mainly getting the editor to pan around using WASD, zoom using the mousewheel, and click/draggable data nodes. It was nice to be effectual for a few moments.
Then, I decided to add a checkbox to the data node, and we're back in "what the hell" territory. StableXUI checkboxes are super-easy to add to the screen, but don't show up. I tried looking through the docs for it, but it appears last week's comment about it having good documentation only applies if you're specifying layouts in XML. Hard-coded layouts, not so much.
(Why not specify in XML, you ask? Well, I tried that. But there was no way I could tell to instantiate the same UI multiple times and apply a different set of data to each UI. Adding IDs to each field seemed to crash the app as soon as the second copy of the UI was loaded, since StableXUI seemed to require each ID be unique.)
I tried guessing a few times on input parameters, but no dice. Then, on a whim, I searched on Google and found a Google group for StableXUI. Lo and behold, the latest thread was someone having the exact problem I was. And the dev replied!
Unfortunately, doing what the dev suggested doesn't seem to work.
It's been one of those days. And looking back, it's been one of those days for almost a fortnight. Try one thing, fail. Try to fix it, fail. Discover an alternative, looks promising, fail. Try to roll your own, fail a different way. Finally figure out a way to work around the issue, fail at a new thing. Repeat.