Played through Hibernator again to compare-and-contrast where I am with the current engine. With some distance between me and that project now, I can say definitively that bumping up the base tile resolution from 12×12 to 16×16 was the right choice.
(Also found a bug in Hibernator, where the ending art of all things doesn’t display sometimes. Gah.)
Platforming now looks proper, with the main player sprite centered within the bounding box that’s used for terrain collision, and weird platforming physics wrinkles ironed out. Renamed and organized a nightmarish tangle of ALL_CAPS_GLOBAL_VARIABLES into a platformerState table.
Jumps feel tight. This is the first time I’ve been able to play around with this character design plugged into any kind of game engine, and I’m still not sure if this is the one I should go with, but I’m feeling a little more confident about the project as a whole now.
Got the platformer code to the point that collision detection and walking across solid terrain now works again. Man, how did I survive with the collision and platformer code that was in Hibernator? This needs work.
When I split the codebase from Hibernator, I also removed most of the code specific to actors for that game, including the entire player’s Lua source. In Hibernator, only the player has gravity and platformer movement, because it’s all hardcoded into the player script. If you were to place a snake enemy in the air, it would just float horizontally, and it wouldn’t teleport through the transporter-style gates either.
So, this isn’t much of a platformer without any kind of platformer movement. It’s time to add that stuff back in. I understand Lua a bit better at this point, so I’m separating the platformer movement handling into a separate module, and dumping all of the state related to platforming into a sub-table. I’m hoping to have something generic enough that it can be shared between the player and other actors / objects.
For animated tiles, I added timer delay variables that are multiplied by the tile’s X and Y positions on the map. This could be used to make the tile updates appear slightly staggered, like a “wipe” across the screen, or to offset the current frame of a tile by whole frames. Specific use cases I’m thinking of are lapping water for the former, and grass swaying in the wind for the latter.
I’m really excited about what’s possible in terms of art and graphics now, with the tweaks I’ve made over the past week or so.
Added a per-row horizontal offset to the tilemaps. This has no effect on the coordinate system or collision detection, but would be useful for splitting background layers into multiple planes, and then scrolling or anchoring them independently (for example, to slowly offset clouds near the top of the screen, without making a new map layer or using a bunch of one-off actors.)
Old computers and game consoles do something similar, typically (though not always) through hardware interrupts that trigger at specific scanlines. If I wanted to do this on a per-line basis, I’d probably have to rewrite the function that draws map layers. I think per-tile will do for now. I could also do the same for vertical columns (though not both at the same time), but I think that would be more helpful in a game that primarily scrolls vertically, like a vertical shooter.
While testing, I added a short loop to assign an arbitrary offset to each row, just to make sure it’s rendering correctly, and the maps look hilarious with a successive offset of 1. I’ll have to put in a couple bits somewhere with lopsided buildings using this.
I learned enough Tkinter to load an image from a file selection dialog, display it within a frame, and set an integral zoom on it. Then I sat down with a pencil and some graph paper and sketched out some ideas for an animation editor, and … I think the time saved from having such an editor wouldn’t negate the effort necessary to build it up to the point where it’s not a hacky one-off thing. Maybe this is something to come back to for the next game.
On a similar note, thinking about what I would actually need in-engine widgets for in this game, and all I can really come up with an answer to that is: title screen menu, config screen, pause menu, etc. Not really any heavy lifting necessary for this game as I’m picturing it currently.
So what part of this needs my attention right now? Probably implementing platforming movement and collision detection again.
Finally relented, and added support for multiple map layers and parallax scrolling. Everything really pops out now. At some point, I had written that I wanted to minimize parallax scrolling and layers, and also background tile animation as a stylistic choice, but … I guess it depends on the context.
Reading up on Tkinter, and making some test programs. Lupa (a module that can run Lua code) coexists peacefully, which is a good sign. I guess there’s also Kivy, which I had been using originally.
Added the ability to draw a map wrapped horizontally or vertically. If you are on the edge of a map, the draw function will loop back to the other edge. This doesn’t cover the logic to wrap actors as well, but it would be suitable for a looping a background over and over, say, during a cutscene.
Added tile animations! I’ve wanted this for a long time, but I felt like I needed a new tile / cell definition structure before I could go forward with it. (In Hibernator, there was a terrain definition list, and then just a big array of integers to indicate what the terrain of each tile was supposed to be.) What I’ve opted to do instead is include the animation info in the tileset structure. The array is mostly nil, except for the offsets of tiles that should be animated. In those offsets, a table is added with the playback speed, number of frames, and a boolean to control whether the animation should play forwards, or play and then reverse back. The frames of animation start at the defined tile and step right, wrapping around to the left and down one row, and back to the very first quad if it gets that far. Each tile in the tileset can have its own parameters, but tiles of the same ID in the same scene will show the same animation frames, because the frame state is determined by a modulo of the scene’s elapsed logic ticks.
Okay, so I just noticed that GraphicsGale’s alpha transparency is working. For me, it’s been broken when running through Wine for a while. Years. Not that I’m complaining, but… what changed? Have I just been doing something wrong the whole time, maybe confusing layer transparency with frame transparency? I swear it used to not save the alpha channel.
Ever since I got animations working in LÖVE, the sprite animation states have been coupled to actors. I’ve finally moved that junk to another structure, so other parts of the engine (namely UI widgets) can make use of sprite animations in a uniform manner, without requiring an associated “actor” game object.
I’ve been looking at GUI toolkit options for Lua. Most of them either haven’t been updated in a while, or require building from source on Linux. LÖVE has a few 3rd party solutions, but they do not circumvent the framework’s write path limitation, which is the motivation for me looking at toolkits. I did however notice that Python’s Tkinter library has been installed the whole time, and a simple Hello-World program is working. I also found a form editor, PyGubu, for designing Tkinter GUIs. So I guess that’s an option.
More in-game widget work… the work that is never, ever over. Once I’m able to invoke new menus and return to previous ones, I think things should be in a better state. As I mentioned above, there are 3rd party solutions, but I’m stubborn.
Edited the packaging script further to include the version number, release platform / target and project name into .txt files.
Sometimes I revisit a snapshot of the engine in its prototype phase (predating all the Hibernator stuff.) While there’s so much more to get done, I’ve really come a long ways. I admit that the technical decisions I’ve made slowed down my output substantially. It’s been a good experience, though.