While I think of what to do with A. CYBORG, time to switch gears. I had a brill idea for a graphics trick to do with my old landscape engine thingie and have been working on it fairly obsessively this weekend. This is only a proof of concept, but I can’t get over how well it came out.
The executive summary: notice the nice, soft lighting on this chunk of land? How it’s darker in valleys, a little dark around the edges of the mountains, and so forth? And that, in turn, makes it look like much more of a real object than a computer-generated one? That’s called ambient occlusion, my friends. A point at the bottom of a valley is only going to see a small chunk of the sky, and will therefore be darker than a point at the top of a hill which has a full view of the sky. And that’s what’s going on here.
To implement this, I added a step to landscape generation. For each point of landscape geometry, we plant a camera at that location looking directly up and with a wide field of view, and render the environment colored solid black against a solid white background. That gives us an occlusion map at each point, where the white pixels indicate how much of the sky is visible and in what directions. In order to test out how this looks, I am sampling the occlusion map down to a single pixel, whose level of brightness indicates how much sky is visible overall; that gives us the ambient occlusion level at each point, and thus the nice results above. (The old version of Air manually calculated occlusion by raytracing across the terrain in a couple of cardinal directions. It sort of worked, but wouldn’t catch obstructions that weren’t located along a main axis and so you’d get noticeable artifacts. By contrast this technique could handle anything — spires, walls, even bridges or other obstructing objects floating in the air.)
However, remember that we actually have a relatively detailed occlusion map available, not just one pixel. If, when we render, we also draw a picture of the sky (including the sun, clouds, sky color blend, and anything else going on up there) from a camera sitting on the ground and with the same wide field of view, multiply the occlusion map at each point by that sky map, and filter that down to a single pixel per point… suddenly we know the full illumination of each point on the map. Realtime landscape shadows fall out of that literally for free, as would cloud shadows, changing environmental lighting, and a whole lot of other things.
Now, in order to really see all this working, I’d need to make it so the vertex shader can examine the whole occlusion map for each point — not just one pixel — and occlude the sky map with it. The latest bleeding-edge shader models have a facility for launching subsidiary renders while executing a shader, but I doubt my computer has that support or that it would be efficient enough to use so intensively anyway. I think the vertex shader is just going to have to do a long list of unrolled multiplications of the two maps. With the 8x8 resolution that I’m currently using, that’s 64 multiplies and adds. Feels kind of excessive to me, but by today’s standards that’s not really a big deal. And since it’s in the vertex shader, it just runs once per visible point in the scene instead of once per pixel as a pixel shader-based system would do.
The other other tweak that occurred to me is that I could render the original occlusion map with the actual color values of the landscape. Filtering that down to a single point would tell me the color of light reflected from the surrounding obstructions, and could thus be used for more accurate ambient lighting. I’m not sure how noticeable that would actually be, but it wouldn’t be hard to experiment with and find out.
Lodestar: Don't Write a Game Engine -
When I first started writing Lodestar, I had no idea what I was doing. I read everything related to first-time game creation that I could get my hands on. One of the recurring themes that was thrown at me was: if you want to make a game, don’t write a game engine.
When I read, “Don’t make a game…
It really depends on your goal. For the stuff I’m working on here at Mayfly Studio, equal with my goal of “make some original games” (something which often seems as far away as the day I started) is the goal of staying current with tech I’m not using at my day job. While my success rate at getting titles out the door is dubious, I am at least keeping my skills broader than they would be otherwise and having a good time doing it. So I’ll count that as a win.
That being said, if I was making these games to pay the rent as opposed to just as a hobby… yeah, it would be wise to ditch the custom engine code and go with a mature third-party engine. Reinventing the wheel is fun, but it’s not a productive use of one’s time.
At this point, I feel as if I have the technical and artistic questions behind A. CYBORG sorted.
There are various other technical things I’d like to do, but these were the big open questions. At this point, I really need to nail down the design of the game. It’s wobbled around a bit — originally it was a much more wordy tale of our doughty heroine confronting both her loopy, troublesome creator Dr. Grand-Mal and a suspiciously nonspecific alien invasion, then I sort of pared it down to a virtually story-free After Burner clone since it felt like creating all those story sequences would get in the way of playing a game that’s maybe ten or twenty minutes long at the absolute most, then I got all like “meh, I dunno” which is where I stand now.
I would like to do something with a bit of character and dialog, especially since that’s the kind of game I like the most and Neon Galaxy had none of that. Deep down though this is just a very simple arcade game and I don’t know if that’s plausible without totally overwhelming the game itself.
There are some interesting things I could do with the engine. The obstacle system could be used to make a hand-designed stage for the player to dodge through or pretty much any kind of crazy obstacle course a la Sega’s Galaxy Force. And there’s nothing keeping enemies in the air, either — a trivial “flight plan” could place installations on the ground, and setting up multi-part boss enemies wouldn’t be all that tough either. I can picture a 3-D Super Scaler take on 1943, say, attacking aircraft and then descending to the surface to take on warships with lots of gun turrets and whatnot.
And then of course there’s crossing these with the concept of a world map and multiple environments, which the whole engine is based around. There could be a branching tree of stages like Outrun, or it could be linear and more story-focused, or even have a map of stages that you could freely move around.
Too many choices! Like I said, I dunno. Before I do any more work with this concept I’m going to have to really sit back and nail one down.
New smoke trail particle behavior in A. CYBORG. I think I’ll keep it.
I’ve checked in the new enemy management code and am pretty happy with it. I can come up with arbitrary enemy movements, spawn them whenever I want, and even have them fire missiles when ordered to by the flight plan. The old code managing enemies in waves and trying to spawn different types is gone and good riddance to it.
It might actually be worth breaking Pixen out again now to draw some better enemies and fix up the kinda hideous cloud sprite I use everywhere.
Tch, not gonna have anything flashy worth posting for Screenshot Saturday this week. I’m finally buckling down and sorting out enemy behavior in A. CYBORG, and pretty much throwing out all the stuff I’d implemented up until now with “wave” objects that controlled spawning, a variety of C++ classes defining different behaviors, and so forth. Instead I’m following something like this plan:
I have to decide what’ll govern enemies’ decision to fire at the player, but it’s quite possible that can just go in the cFlightPlan as well. Again, there’s nothing sophisticated about these guys; they just need a simple scripted motion and that’s it. There are going to be a few genuinely sophisticated enemies — bosses, if nothing else — but those guys are going to have unique, hand-crafted behavior so I’m okay with giving them unique, hand-crafted code as well.
I kind of wish that Screenshot Saturday was Screenshot Sunday, since I usually don’t have anything that isn’t totally programmer art hackage by the end of Saturday. But anyway, I’ve implemented a fairly robust obstacle system in A. CYBORG. These will be used for bonus stages, not dissimilar to how it works in After Burner, although as per the world map I posted a while back you’ll only traverse one obstacle stage (out of four possible) in any single playthrough.
Oh, and, uh… I finally got around to updating the game window’s title bar. Yeah.
That should do for now.