Not Nano Day 12

After having gotten basic OpenSimplex noise working, I started working to make it more like real terrain on the scale I was looking at. This involved taking integer x/y coordinates, which are based off of the hex’s offset coordinates rather than cubical coordinates I use everywhere else, and then some factor apart that’s less than 1. I’m calling this a damping factor, because it’s damping how often the noise is sampled. Maybe this is a bad name, but naming things is hard.

Below, I included 4 images showing different damping factors. I’ll need to play around with this a bit more, but I think at the scale, something around 0.05 is going to be the right amount. I’m also going to need to make sure city cores (especially the start core) aren’t drawn underwater, because I don’t intend building to be able to take place underwater. I’ll also probably tweak my transitions between the different terrain hex sprites. I’d like this all to be configurable at some point, and the settings are exposed in the file right now.


I also fixed fog-of war drawing. I’d accidentally put the the actual draw call inside my for loop, so it was drawing every hex one at a time, rather than a all together in one batch. And once that was fixed, I could move on to further implementing it. Buildings can’t be built under the fog of war, and things that are under the fog of war lose their information. There are a couple minor bugs with redrawing things under the fog.

I’m not sure I’m going to keep this. Protection towers still run and protect the area if they’re being supplied energy, but other than seeing the protected area disappear, there’s no other way to know if they’re working. I might also go the other way and hide the safe area, or not allow it to update its status in fog-of-war areas. It’ll depend on what’s actually fun to play.

cocos2d fog of war.PNG
Buildings and networks under the fog-of-war, they look like they’re all in their powered state, even though they aren’t. Also visible: one of the annoying seams I can’t seem to make go away.

Not Nano Day 11

I got the new form of chunk generation working in my terrain-test branch. I’m probably going to bring this over into the main branch, but what I wanted to work on was the actual terrain generation. The first chunk generated (hexagon coordinates q=0, r=0, s=0) for it’s “center” or anchor will always have the starting city core at it, but I also want other city cores spread across the map. At what distances apart they spawn will need to be determined experimentally by playing, and if I add difficulty settings, they could affect this distance calculation.

The first thing I tackled was enemy core generation, and my first pass at an algorithm showed the I need to make things more random. I’m using a hash function with a seed appended to it, but the results were a little too deterministic for my liking.

terrain test cores.jpg
Start core circled in pink, 4x enemy cores (red) circled in orange.

This is exactly why I wanted to create something to give me a larger view of the terrain map, because I might have missed this regularity otherwise.

I’m using Python’s hash function on a tuple containing the hexagon coordinates (q, r, s + seed) and then checking if a hex should maybe have a core added to it if the hash is % some number. Obviously this isn’t working yet, but it’s a fine first pass.

I also started working on terrain hex generation. Ideally I’d like blue hexes (water) to cluster together a bit to give water bodies, and the other colours to have some other nice distribution. The first pass uses OpenSimplex to generate the noise, due to Perlin noise having some artifacts, and then binning the values directly to sprites. I also spent too much time reading about procedural terrain generation and not programming.

OpenSimplex noise generation of terrain hexes. Compare to the purely random map above.

Again, the first pass here was less of what I was looking for, but it at least works and I can tweak the normalization function until I’ve got something better to look at with the correct proportions of water hexes. I do plan on having water be a barrier of movement to certain units, and stop building of normal networks.


Not NaNo Day 10

I didn’t make very much progress today, especially not as much as I’d hoped. I needed some offline time, so less development happened.

I’d like an overview of a much larger map to test terrain generation algorithms on, so I decided to make something that could show me much larger maps. Cocos2d is just too slow with this many sprites being displayed, so I decided to write a simpler version using PIL (actually Pillow).

Because I wanted to keep the chunk size the same, but have a much larger viewport, my chunk generation code doesn’t work properly anymore, it generates the 9 chunks centered in the middle and that’s it. Getting chunk generation to fill the a much larger took more work than I’d anticipated due to bugs in my existing chunk generation, which I’d have needed to fix if I end up wanting a full screen view, rather than a windowed view.

new hex tiling test.png
New tiling test. This tiles the hexes much nicer, but it means the the center hex is not longer in the center.

So I experimented with hex tiling, finding one that worked really nicely, but means that the center hex is no longer in the center of the chunk. If I decide to go forward with this, I might start indexing the hexes based off of their top left hex.

Today sort of felt like a bit of Yak Shaving, after making good progress on other areas. But I want the terrain to be more than a call to randint(), and getting the chunks nailed down will allow me to move on to proper procedural generation of the terrain.

huge terrain test.png
There are 56,079 8×8 hexes being drawn in this image.

At the end of the day, I hadn’t even got the drawing working for this properly. Chunk generation wasn’t working properly, so it was commented out. But at least I could draw ~56k hexes in under a second. Once I get this working properly, I can use it to refine my procedural generation algorithms for the terrain, which will include enemy spawns (enemy controlled cores) and varied terrain types. I’d like the terrain hex colours to actually mean something by using them to indicate different types of terrain.

I’ve committed the work in progress code to a branch.

Not Nano Day 9

As it turns out, the major issue with chunk generation producing wrong chunks was an off-by-one error, and it only happened in one chunk generation direction, which is why it appeared to intermittent. The fix was simple, just mirror what I’d done for the other direction.

With that out of the way, on to updating the various draw functions to only draw what’s inside the viewport. The first task was a fix for guessing at a viewport before it has already been created, because that’s how my code works with cocos2d.

Only drawing in the active viewport turned out to be relatively easy, save for a silly mistake in copying and pasting code that left me wondering why it wasn’t working properly. Normally this is the sort of thing I’d have amended the commit to be the fixed version, but that seemed like it wasn’t in the spirit of what I’m doing.

cocos2d viewport pruning.png
Cyan rectangle is the viewport, everything drawn is the only things being drawn.

Above is an image demonstrating this pruning in action. There are more buildings, more terrain hexes, more network connections and more safe area outlines off the bottom of the image that aren’t being shown. This uses the code I wrote yesterday to determine a superset of hexes covering the viewport, draws the hexes from that layer that are in the set, and prunes the rest. This means that the game can scroll more than a few chunks without slowly to a crawl.

Other than some alignment issues on certain chunk boundaries creating a visible seam, which is certainly yet another rounding error, I think most everything I need to get done on the base display side is done. Now to start implementing things that require the basics be working.

I decided to implement fog-of-war next. It sort of works, but slows the game down to a crawl when it’s actually being drawn. I don’t know if I’m doing something wrong, or if I’ve hit a maximum number of layers that cocos2d performs well with, so I disabled it for now. Not being able to build buildings and networks in areas that aren’t visible has not been implemented yet.

cocos2d fog of war sensor tower.gif
Sensor tower extending the area that can be seen.

From a design standpoint, I’d like the fog of war to be partially transparent, so that things underneath can be seen, but setting opacity for the fog sprites didn’t seem to do anything.

Not Nano Day 8

I decided to tackle the chunk generation issue today. But first I looked into making text draw on the screen so I can debug easier without needing to refer to the console. This will also mean when it comes time to draw the amount of resources, for example, on the screen that I’ve already gotten the hard part figured out.

cocos2d text test.PNG
Info output showing details of a hex.

On to the actual hard part, chunk generation. Somewhere in my arithmetic I’ve got an error, which is causing chunks to be generated (and draw overtop of) existing chunks. I fixed one small bug I saw, but it was minor and didn’t seem to actually fix the issue. Dang.

While working on a fix, I implemented a way to determine all of the hexes inside the viewport, and I’ll probably update all of my drawing code to only draw the hexes that are actually inside the viewport. The algorithm finds the corners, draws a pair of line between each of the top two and bottom two corners, and then iterates over those two lines drawing lines in between.

cocos2d viewport hexes.png
Viewport is cyan rectangle, hexes outlined in magenta are the calculated ones visible from the viewport. 

The image above shows the hexes calculated to be inside the viewport. There’s some extra hexes on the sides and top/bottom, this was done to make sure that these hexes completely cover the viewport. Why does it look like a little too much extra? Because I applied the same amount to the vertical edges as well as horizontal edges, but the top and bottom should be half of the sides. For my current implementation, this would mean drawing 483 hexes instead of 1089 for the 1280×800 window I’m testing with.

Unfortunately, I wasn’t able to find the arithmetic error in chunk generation. The code all looks correct, but something is very obviously wrong. It’s probably a simple off-by-one error, but finding it has proven to be challenging.

As a very quick fix for the worst of the issue, I made it so that terrain tiles can’t be updated, only created. It doesn’t solve the root cause, but it does make the bug have a lot less impact. It’ll still be an issue when terrain chunks aren’t randomly generated but represent part of a larger land form.

Not NaNo Day 7

I decided to put off fixing the serious issues around chunk generation and scrolling and instead work more on the networks. I created a set of white (as opposed to the orange) network sprites to use for the un-powered networks.

I implemented the A* algorithm, though in the future I may need change it to a Dijkstra’s as there will be multiple energy sources that can all supply a network. This worked fine, but I realized that I have no way of rechecking a network to see if it has been connected. The sprites don’t know how to update. This might be a good time to figure out how cocos2d’s event handling works, and have a network node whose status has changed have a way to tell others to update, though I’m not sure what the best route to take here is.

My first implementation can properly determine if a energy network node is connected when it’s built and draw it as powered/un-powered, but it doesn’t support updating yet.

cocos2d energy network status test.PNG
Un-powered energy network in white, powered in orange. Next up, redrawing the network on state changes so things can become powered and un-powered.

With the basics working, I moved on to making the network update when connections were added or removed. I did this by finding all of the nodes connected to an energy source, in this case the one city core, and powering them. If they’re not connected, they’re not powered. It works, but it starts getting really slow after about 50 nodes, so I’ll need to put some time into optimizing the graph traversal algorithm to make it usable with large networks, perhaps storing each disconnected sub-graph and only updating as needed.

cocos2d energy network redraw.gif
Networks now properly propagate whether or not they’re powered.

After that part was working and networks now properly deliver (or don’t deliver) energy to sinks of energy, I implemented protection towers switching on or off, including their safe areas when they lose energy. From a UI perspective, I should also give an indication on the tower that it’s off, not just have the safe area around it disappearing. Network propagation is still slow, taking nearly a second to switch the energy on and off in the below gif. I may need to address this sooner rather than later.

cocos2d energy network protection test.gif
Enabling and disabling safe area from protection towers by breaking their energy network connection. 

Things are continuing to look more and more game like as I add mechanics, but some of the potential serious performance issues may need addressing sooner than I’d like. Network changes are slow. The issue with chunks is currently less of a problem, as it seems to be more likely to be an arithmetic error than something more serious.

I also tweaked buildings to swap sprites when they’re on or not, giving a visual indication of whether or not they’re receiving energy or not. I also created sprites for off as well as on. Art is still placeholder art, because I don’t want to focus on art until I can properly display it.

cocos2d building energy toggle.gif
Buildings now visually change when they’re not receiving energy.

Not NaNo Day 6

Sometimes you do need to be away from a problem to realize what the solution is to it. Within five minutes of sitting down to figure out why I couldn’t remove sprites, I’d figured out a solution. I realized that I was already doing it with the selection cursor that followed the mouse around. Why I didn’t realize that when I went to try to remove buildings, I’m not sure. Name the sprite something meaningful, and them call remove() on it. Simple, and I spend way too much time yesterday not realizing what I needed to do.

cocos2d remove buildings.gif
Adding and removing buildings.

Next I worked on removing the safe area overlay hexagons. This was relatively straightforward, once I finally realized what an error message was trying to tell me.

cocos2d remove safe overlay.gif
Removing protection towers now visually removes the safe area around them. After initially writing this, I noticed a bug in the removal.

The algorithm I implemented is probably going to be pretty slow with more than a few chunks, so I need to figure out how to mark only specific tiles as dirty so that only they can be updated when it’s time to re-render the scene. I also still need to limit drawing to the viewport.

One thing I may need to figure out before is how to merge sprites. There are 6 edges to a hexagon, and that means that there are 26 (64) possible combinations of anywhere from 0 to 6 edges. I’m probably not going to draw (definitely not by hand) all of the combinations, so I might generate them dynamically and runtime. I say “may need to figure out” because drawing up to six sprites on a hex might also continue to work fine. We’ll see.

I also noticed that I’d inadvertently made removing a protection tower made safe areas that weren’t around a city core unsafe, even if another protection tower was making that area safe. Now adding a tower makes the area +2 safer, and removing it makes it -2 safer. I doubt there’s going to be any game mechanic around it, but it was a quick code fix.

cocos2d remove safe overlay fixed.gif
Safe area being properly added, and now, removed.

In testing this, I noticed that I have some serious issues with scrolling and chunk generation. Chunks generated at the beginning align properly, but after that, everything seems to go off the rails. Something in my math is wrong and coordinates aren’t lining up with each other properly. I’ll need to fix this soon.

I decided to work on something fun, and getting new things drawing (or not drawing) is more fun than figuring out why existing things aren’t drawing properly. So I created a test sprite for the energy network. It doesn’t quite align as nicely as I’d like, but call it placeholder art for now.

energy network sprites test.PNG
First pass at an energy network sprite.

Having already worked out the hard part of adding and removing sprites that depended on their neighbours, adding and deleting the networks was relatively straightforward. The only wrinkle was that neighbours needed to have their connection removed. My implementation removes all of the connections from the neighbours right now, but I’ll try to fix that later.

cocos2d energy network test.gif
Energy network adding and removing. Again, I’m using a held key until I figure out a menu system.

Next, I want energy networks to be connected energy networks. Right now a disconnected network is the same as a connected network, but energy shouldn’t flow to networks that aren’t connected to an energy source. Adding this is going to take some work, and I’m going to need to run a graph traversal algorithm to find out if all of the network pieces are reachable from the source (and multiple sources in the future), and if not to power them off. This will change the sprite, but weapons and protection towers should shut off as well. Right now protection towers are always on.

I’ll also work on implementing the control network next. I haven’t decided if I want networks to overlap. I think so, otherwise building networking will be a nightmare or impossible, but I might limit how they cross, depending on how it feels to play. I’m happy to be getting into subjective things such as how building networks actually feels.

The header image, shown below as well, is sort of the sum of the progress right now in terms of building. There are a couple things I’d like to tweak if I’ve got the time, because I don’t like how the networks form triangles at junctions. It makes sense, of course, but it doesn’t look good. I also don’t like the jagged path vertical networks take, but there isn’t really anything I can do about that with my hex limitations.

header building progress
Current building progress. Even with my placeholder art, it’s actually starting to look like a game. I can imagine the half red/half blue hexes as weapons protecting the area from creeps.

Not NaNo Day 5

My first task for the day was to get chunk rendering working, so that I could draw new chunks as the screen panned. I found a solution for it, but it feels pretty hacky. I’m definitely generating way more chunks than I probably need, but I want to make sure there’s always map on the screen and not a jagged black area where terrain hexes haven’t been generated.

What I’m doing is finding all of the bordering 8 chunks around the one the screen is currently centered on, and if they don’t already exist, generating them. In the future, this’ll need to add enemy spawns, city cores, creeps, etc, but that hasn’t been implemented yet.

cocos2d redraw on scroll.gif
Contrived example showing new chunks being generated on a scroll. Purple hex is the “key” or center hex for the chunk.

One problem that I’m having is that it’s slow. I’ve added a couple of workaroundsto improve speed, but it seems like it’s drawing all of the hexes because it slows down the more I scroll. I thought that cocos2d didn’t draw things outside of the viewport, but this doesn’t seem to be the case.

One thing I noticed was that the rendering batches I was creating were sticking around, so each time things were redrawn, they were all getting drawn, even overlapping terrain hexes. I couldn’t figure out a good way to fix this, so I hackily removed the child BatchNodes from the ScrollingManager subclass I have. Yuck, but it seems to help performance some.

In my quest to make things go faster, I also changed loading of assets. Instead of loading the images every time I’m generating a sprite, I now load the images and convert them to sprites as needed. This didn’t have the speedup I’d hoped for. Setting the chunk size lower seemed to help because huge chunks aren’t being generated, but it still pauses when a chunk is added. I think I’m shelving looking at performance issues for now to move on to more game related stuff. Like getting the starting core back.

Next I revamped adding buildings (again), and now not only can I add the starting core, but also place buildings. This is the start of the all important base-building part of the game.

cocos2d building plop.gif
Building buildings! Right now it takes holding a modifier key to get them to build, but at some point I’ll code a proper menu system.

My next task was to attempt to get buildings to go away, which was unsuccessful. The datastructures properly removed the buildings buildings, but somehow the sprites were still being rendered. Obviously I’m missing something in how cocos2d handles rendering.

So I moved on to actual game things. One of the mechanics is safe areas where enemy creeps can’t spawn, so I implemented tiles being able to be safe and be made safe with a tower that projects a protection field. It feels good to finally be getting out of laying all of the groundwork, though there’s still more groundwork to lay, and into actually implementing the game mechanics.

cocos2d protection tower plop.gif
Protection towers being added to the already protected area around the starting city core. As I can’t figure out how to remove existing sprites, I can’t make the area expand by removing the redundant inner border.

This is the start of the mechanic where you expand by building protection towers and expanding, supplying them with resources and protecting them with weapons. The above animation doesn’t show the networks, because they haven’t been implemented yet. I want to dynamically change the sprites as connections are added or removed, but I can’t yet remove sprites.

I’m also starting to look at the scale of what I’ve done, and I’m wondering if being able to see more hexes at once would be better. Not necessarily from a bigger window perspective, but from a using 48×48 or even 32×32 hexes instead of 64×64 ones.

Not NaNo Day 4 – Part 2

As the last post was getting quite long, I decided to continue it in a second post.

I spent quite a bit of time refactoring the code I’d written around hex chunk generation and building plopping. The goal with chunk generation is so that scrolling the viewport can generate chunks that don’t exist just outside the viewport, so that the map can be seamless. I also added code to store the corners of the generated hex chunk. I’m not sure if I’ll need it, and I can always remove it if I don’t.

It didn’t quite work when I finished the day, but I did at least get the mouse to follow the hexes when I scrolled properly. I’m still not sure why it seems vertically offset in selecting hexes, and I had hoped that fixing this bug might have fixed that too.

cocos2d hex scrolling fixed mouse.gif
Scrolling with the selection indicator following the mouse. The bug around the vertical offset of the selection still exists, however.

The fix was relatively straight forward. I needed to offset the mouse’s coordinates against the changed viewport and world coordinates. I’m not sure why cocos2d requires this.

Not NaNo Day 4

Success! I’m using a modified version of the Python library from RedBlogGames’ excellent page on hexagons (seriously, it’s worth a read if you’ve ever wondered about hexagons and programming) to do a bunch of the annoying math with hexagons, and I went back and read the page to figure out why my hexes weren’t aligning properly. One of the comments was talking about a similar problem, leading me to see that the author had already thought of it and included fixes for it.

cocos2d hex alignment fix.png
Look at all those pixel perfectly aligned hexes!

I had a floating point error in my code. Part of the code calculates the distance from the center of the hex to the corner. Initially, I was using Python’s integer division when calculating this, but it rounds down, even though the value I was rounding was ~36.95. Using the round() function got me 37, which was the result expected, and results in proper alignment of the hexes. This is because the ideal hex doesn’t have perfectly matching integer boundaries, so I’m actually deforming the high slightly from ideal to match the display’s pixels.

I was hoping this would also fix the mouse offset I was having, but I’m still seeing an ~21 pixel vertical offset upwards. I’m going to try to shelve this issue and move on with actually getting more game stuff working, including starting to implement game systems and mechanics.

After fixing the pixel alignment issue, I found the bug causing the buildings to not draw properly. I realized that since transparency was working elsewhere that my issue probably wasn’t with transparency. I had accidentally been drawing the buildings in the terrain layer, instead of the terrain, and then drawing buildings on top of them. Perhaps I should have set a different background colour other than black to help catch the issue.

cocos2d buildings.png
Buildings (placeholders) rendering correctly!

I also had another minor bug where I was adding to my rendering batch, but had the actually rendering being done inside the loop. I wondered why it took several seconds to render the scene before I realized, but it was an easy fix.

I also worked on refactoring the terrain rendering code. I want to be able to render chunks and also not have building stored directly on the hex tile, rather have a building both be associated with a tile and a dictionary of building attached to the whole terrain map. I also switched to “rectangular” chunks because they’re about the same aspect ratio as the viewport is.

cocos2d hex chunk start core.png
Here’s a 15×15 rectangular chunk with the start core showing at the center.

I haven’t gotten more than one chunk added and drawn yet because I got sidetracked adding scrolling so I could see my different chunks. Scrolling itself works, but thouse mouse is offset from where it should be.

cocos2d hex scrolling broken mouse.gif
Sort of working scrolling. The mouse gets more and more offset as things scroll.

Continued in Part 2.