DSR Log #4: Code Shifts

Posted by Astryl on May 12, 2016, 12:51 p.m.

I decided to keep writing these, regardless of where the code goes and how "dry" the writing might get.

I'll still have some art (Probably) to show off on most weeks, as well as new features that aren't "spoilery" or anything.

I do think that next week I'll write this up on Saturday instead of Thursday, makes a bit more sense to do that I think.

So, let me first cover what I've done in Game Maker this week, where I started having troubles and why it was the last straw.

A good portion of the weekend and Monday I spent tweaking the tileset a fair bit, figuring out what I wanted things to look like. This is the current iteration.

A lot of subtle fixes and stuff. Still need to do some work on the grass, I think. Want to try make a few tiles of full-blade grass instead of this tangled mess.

Also the giant tree trunks. I'm not 100% sure on those, might keep them for another forest area I have planned (5th area, more or less).

So, this is where I started hitting a wall. The AI code I'm working with is fine, it's OK. That's not actually the problem here. The problem is, unfortunately, GM's pathfinding functionality.

Basically, I want a certain behavior called Flocking in my AI; they won't try to overlap with each other, move into each other, etc. If one enemy is to the North of my player, other AIs will try to move into an unoccupied cell around the player.

GM uses the A* pathfinding algorithm (Which is fine), but doesn't exactly have much variety in terms of configuration. I can add 'blocked' cells, remove them, add entire instance types as cells, etc, but I can't be a bit more selective.

Basically, my problem would be 'solved' if GM added a single parameter to the mp_grid_add_instance() function. A parameter they seem to love to include in many functions, some in which it isn't even that useful…

Basically the "Include Self" parameter.

The other thing it doesn't have is the ability to disable cells by instance type.

So what I ended up with is a bit of an abomination of code to perform pathfinding.

For each instance of an on-screen enemy, I have to clear the current cell grid, re-add the Level blocks to the grid, then use the very slow with keyword to add all the other instances to the cell list.

Rinse and repeat every frame (Or once a second or so as I ended up implementing it), for every on-screen entity, until those entities no longer exist.

This works, and doesn't result in a massive hit to performance, but it's annoying, it's ugly, and I hate not being able to just add something to the core of the pathfinding system to do this.

Naturally, I could write (And began writing) my own pathfinding scripts, but it's still unwieldy because of the nature of GML.

My pathfinder is, basically, a layered grid that utilizes A* with multiple "filters" applied over its grid, by instance type.

Internally, this is still having to use with(), and it's pretty much still slow and ugly… but I'll live with it. Of course, this entire thing happening sparked off the following section…

On Monday I started getting this feeling that GM wasn't going to stop throwing stupid things like the above problem at me. I'd already had to encounter some other really annoying problems (Long save times on a relatively small project, first save always ridiculously long. It's basically traversing the project tree, loading each resource and writing it again with no need even if I hit the Save button right after loading the project).

The saving problem is a minor annoyance, but one that shouldn't exist: GM:S stores all of its files on the filesystem in a folder hierarchy. Previous versions (6/7/8/8.1) should by all rights be slower (And tend not to be), because they package everything inside the project file.

Anyway, I did a few tests on Monday evening to figure out what I wanted to do. I basically took a look at:

> Godot

> Unity

> Unreal Engine

> C# + MonoGame

> C++ + Whatever I dredged up

My thoughts on Godot are that it has great potential, but is still buggy as hell. It's definitely a good contender for 2D game creation, but still lacks proper documentation… or at least an indication of when an API function is even implemented. I have to dig through the soruce to find out if half of the API functions even do what they seem to do, which is kinda defeating the point of having the reference to begin with.

Unity and UE I have mixed feelings on. I feel like Unity is a Swiss Army Knife and UE is a Swiss Army Chainsaw. Throwing together a quick 3D prototype in Unity is actually pretty fun (I made that Spectrum Analyzer in it pretty quickly), and UE is great if you want pretty lighting and are willing to wait overnight for it to build.

Even with Unity's 2D tools, I feel it's more suited to creating the kind of 2D you find in games like Rayman Origins than the type of 2D I'm going for. A lot of that has to do with the heavy integration of the physics engine into everything.

C# and Monogame are pretty great, I whipped up a few prototypes a couple of months ago that can load Ogmo tilemaps directly. Still, there's a lot to be done by-hand in order to get a working game out of things: You still need a way to handle game objects, collisions and game state. And I'll be honest, the last time I did that the results were messy; I'm not going to pretend I'm a C# programmer, just a dabbler.

C++, of course, I've saved for last, and for a reason. I'm "going" with this, in a loose sense.

I decided to do a trial run. I'm going to continue working on the GM version of the game as per usual in the mornings (Which is what I've been doing anyway), and spend some time in the evenings working on the "C++ Prototype". Once I've gotten that to a point where I'm happy with it, I'll release a test version here for people to try and give feedback on, check performance and compatibility and so on.

In the interests of coding smarter, not harder, I actually made use of some old code of mine. Fun fact: I have about 3 dev folders containing nothing but C++/C/Assembly code, totaling several GB of projects (About 60% of that is 'data', stuff like textures, memory dumps, etc).

A few of my projects are, as it turns out, have some very good code. There's an OpenGL renderer I made in a weekend that is great at rendering mixed 2D/3D graphics, scaling both dynamically, and operating on most machines 10 years old or newer.

I have a handy logging module I made a while back that shows the exact line and file the log message originates from without any extra effort required.

I have a keystore config class that creates human readable config files based on an in-code template.

I have a resource packer that creates a WAD-like file for storing resources in.

Basically I have a lot of code, and I'm going to use it. Some of it I'm tidying up to "fit" the style of C++ I'm using now, others I'm just compiling into static libraries and using as they stand. All told, I have all the trappings of an engine, I just need to stitch them together.

Being fond of the Ogmo editor and liking C#'s XMLReader for its easy ability to read XML-like files, I also integrated rapidxml into my source. It's a header-only XML parser that is ridiculously fast and released under the Boost license, so a pretty decent deal all round. Much better than trying to use .NET/Mono and C++ (Cleaner, less weird mixed in ^ references everywhere).

We'll see where this goes, it might fall flat. Either way, the game will continue to be developed.

I spent Sunday setting this up. GitLab on a 32-bit Celeron laptop is a bit of a silly thing to do, but I figured I had enough RAM and CPU power for the number of workers I'd need (Considering I'm the only one using it, with the possible exception of this one friend of mine occasionally helping out).

I'm running Linux Mint, but the official packages don't have 32-bit support, so I had to compile from source. The weekend before this I built a Linux From Scratch system, compiling things from source is pretty much rote muscle-memory at this point.

All told, when the service is active and I'm logged into the desktop, I'm using just over 800mb of my available memory as a whole (GitLab + Workers + Postgres) on an active system:

Firefox or Chrome hog way more.

Of course, I'm only servicing 1-2 users at any given time, so it's doable.

Anyway… Gitlab. It's useful as heck. I've basically added in my todo list for both versions of the game as Issues, filed them under Milestones and labels, and I get a nice visual summary of my "completion rate" for everything I'm doing, as well as the Todo list overview.

Also, Pie Charts!

This setup also acts as a lazy backup of sorts. Just push it to remote and I have an "off-machine" backup.

I'm also able to test Linux builds pretty easily with this (It has an auto-build scripting system that I'm figuring out; designed more for things like Ruby or Node, but it can execute system commands so I'll get it to produce my Linux test builds too).

One of my side-side projects with regard to this has been the porting of my inventory management software for the PC shop to an Electron compatible app, and getting it working on my Laptop properly. It's been remarkably useful so far, and I've only had it for a few days.

Not that much clear progress this week, I'm afraid. I basically had Monday to work.The last three days were bogged down by my day-job. I spent today working a long shift after stupidly thinking I just had 1 job to do (It turned into 4 while I was doing the first).

On the plus side, the PC shop is alive and well, even without a proper premises. We're still operating out of a Courier shop's front room (A temporary arrangement), and business has never been busier. Just from today's work I brought in more money than I used to make in a week last year; people are clamoring for us to reopen, and we've been getting a bunch of requests regarding when we'll be doing so.

With regard to that, we actually received a visit from an investigator from the Insurance company that will end up having to pay us out.

His valuation is that yes, we get a claim. We'll be unable to claim on lost potential profit, but we should get the cost-value of lost/damaged stock, furnishings and equipment (More than enough to kickstart our own office again, since we've already built up a nice bit of stock thanks to my boss working a second job).

Anyway, point of this bit of seemingly unrelated rambling is that I'm probably going to be running a PC shop again full-time, and I'm actually looking forward to it.

This does, of course, mean that development will be slowed (Though I'm going to look into setting up a VPN or something to use, that way I could continue during downtime at work).

But even with the cuts into development time, I'll be gaining something far more useful: Security. It's far easier to develop a game when you're not worrying (as much) about where your food is going to come from in a week's time.

Next week's log will be on Saturday as mentioned earlier. It will most likely contain more C++ than people want to read about, but ¯\_(ツ)_/¯

Comments

Jani_Nykanen 8 years, 6 months ago

It's actually worth reading these blogs: rapidxml is just what I need (I haven't found a good xml parser before, not that I have even tried to find one) for my next project (currently I'm using lua for the same purpose EDIT: I mean I use lua to read external data in text files, not parse xml, heh).

Oh, and I'm happy I'm not the only one who starts/considers to start a project in a game engine or programming language that is not C++ but ends up using C++.

aeron 8 years, 6 months ago

Good luck with the new engine. It'll be worth it, though. I like the plan to keep messing with the prototype in the meantime… gotta keep a fresh play-dough even while you chisel the stone so to speak. Also good to hear the shop is going to make a comeback. Gotta make that paper!

Nopykon 8 years, 6 months ago

Naturally, I enjoy c++ blogs far more than any about gm, since I don't use gm. I know we are a few c++ coders here that appreciates it.

I've never used xml as a dataformat for any of my games (except for html5 stuff). I've only used TinyXml

to parse collada and other formats into custom binary. It would sure be nice to just export from blender once and not having to run the converter every time I make a change. Would save time and tabs.