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.

Advertisements

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.