Streak Club is a place for hosting and participating in creative streaks.
Watching Michigan thwamp Florida in football left little time for game-dev but to celebrate Florida's terrible performance I decided to complete the game territories that compose the state. I'm using inkscape to quickly draw the outlines of the territories. In the game I just do some clever parsing of the .svg file and pull out the paths I care about/turn it into a render-able mesh.
One oddity is that vertical and horizontal lines are represented weird in the svg format. Instead of programming a solution with extra special case handling I descoped the problem by simply not drawing any vertical or horizontal lines for the tile outlines. It's an elegant solution.
I haven't tried to draw the outlines in game yet, just a flat shaded tile. Maybe I'll try that soon.
Cleaned some code, added a second character, added a second camera for split screen.
I still have yet to decide the most important question if the players are working with or against each other...along with what it is they are doing.
Just a demo to play with ideas. What if the world were inverted and we lived on the inside of the planet instead of the outside surface...
What if it were a world big enough for 100 people to hide, hunt, build, and kill?
A few lines of code and now the troops actually get moved to their respective tile. This is prior to the commitment of the turn to the server for validation and the real movement taking place. So this is just the local visualization of planning out your turn.
There are a few bugs I need to deal with and I need to add a way to "undo" a move by clicking a unit (remove the simulated move from the list of moves this phase of the turn). I'd also like a way to indicate which tile a troop came from. Maybe a line back to where they started the turn?
Another small task finished, I completed the configuration of the invasion zones on the west coast. Meaning the tiles have the right properties, links to their neighbors, troop positions, etc. This is a tedious and boring task but the way I am developing this is one phase of a turn at a time till they are all implemented. Well, in order to make the reinforcements work 100% correct I needed to tackle that now.
I had no motivation to do any gamedev tonight but I saw that we were about to go 3 days in a row with no posts from anybody and that seemed unacceptable. So I did some boring but easy work. I finished tracing the rest of the board tiles to complete the map for the whole country. There is probably about 20 more minutes of work to do in another session to rename the vector outlines so that the game will pull out the appropriate shapes at runtime but this will be an exercise for another day. Once they are in game I also need to do the neighbor mappings for every tile. That will take some time.
Anyways here is what all the tiles look like. Note that the colors are temporary for me to see the region the tiles belong too. The will likely all be the same color in game (with a big fat line showing the different regions).
Continued to develop the show valid moves function by adding in more of the game rules. So things like taking into account that you can't jump across a tile that the enemy has at least 1 unit in...unless you are a bomber or chopper unit type. Also added in the logical check for eliminating tiles that already have the limit of 5 units in them...unless the movement is part of an attack towards an enemy territory in which case you can throw as many units as you want at it. The 5 unit limit logic seems to be working as I started placing a bunch of units into one zone. On the sixth, that tile did not show up in the ugly green indicating that I can't move there.
I also fixed Ohio. I had a theory that polygon winding was the issue and wanted to test it. It seems to have corrected the problem. I still need to finish outlining the rest of the tiles in the center of the board but I figure I'll save that for a day when I have little motivation to write code and just want a mindless task.
One final thing I'd like to do before I continue onto more of the core game logic and the next turns. When a unit is moved but the turn is not finalized yet, I need to indicate this somehow. So if troop A is moving from tile 1 to 2, I'd ideally like him to be placed in tile 2 with a line or something back to the spot he came from in tile 1. It would stay like this until the player hits the complete turn action. This allows him to undo a move he doesn't like and at least see things before committing the turn. For each tile in the unity editor I have manually placed 5 transformations for unit placements in a tile (since the tiles can be wacky shapes and sizes I don't want the units overlapping). This is fine for up to the limit of 5 units at the end of the turn but there is one edge case that can't be supported. A player can attack an enemy with as many units as he likes. So let's say the defender has 4 units in a tile and the attacker is moving troops to declare battle with 8 units. Like before, I'd like to have these units "staged" at the tile they would be attacking as the player is constructing the turn but this would mean I have to have 12 locations for units in a single tile (until the battle is resolved). I thought about a single position per tile for "attacking" units but then the player can't pick a specific unit in the pile if he decides he doesn't actually want to engage a particular unit. It is also quite a painful and tedious process to even place 5 positional transformations for each tile. I can't imagine having to place 20 or 30 per tile. I haven't solved this problem yet and can't think of a solution I like. Ideally there would be a procedural way I could place them but unfortunately the tiles are all shapes and sizes. I wonder if given a set of points that represent a concave polygon there is an algorithm to pick random points within said polygon that are X distance apart from each other???
In the picture below I have moved 5 units into the lowest western invasion zone. The units aren't actually shown in there because...well did you read the last paragraph? I haven't implemented it yet. I have clicked a sixth unit and I see that the full invasion zone is no longer a valid move.
When you click a unit to move them, the valid tiles that can be moved to are now highlighted. This took a little bit of clever logic but seems to work quite well and was relatively easy to implement. A while back when I defined the properties of tiles I was thinking ahead of this issue (finding and validating unit movement against game rules). So each tile needs to know it's neighbors and has a reference to them. Thus if you have a starting tile and a max distance in number of tiles then it becomes easy to use a few for loops to "walk" from neighbor to neighbor and find all tiles within X number of jumps.
But wait! There's more! This system allows me to do something even more clever with reinforcements coming in from off board. For normal tiles on the map two adjacent tiles both have references to the other in their neighbors list. Since you may be moving in either direction. I have reinforcement staging tiles for each army. These staging tiles have their neighbor references set to the valid places that reinforcements can be placed but more importantly, those neighbors DO NOT have a reference back to the staging tile. This will essentially create a directional graph and make it so troops can come onto the map but not back off.
Anyways. The image below I have selected a US unit for reinforcement. The valid places the unit can be placed (cities) are changed to be highlighted in the ugliest green you've ever seen. Ignore Ohio for the moment. Not sure why that mesh isn't showing but I've got bigger fish to fry than worry about that dumpster of a state.
Right now it is only finding the valid tiles within a number of jumps from the starting tile. I need to also apply more game rule constraints like territory occupation.
Quick update, didn't work too much on it this weekend.
The attached photo is a panned and zoomed camera (hard to tell from a still photo)
And for a bonus since we are talking about clever camera things
Refactoring code to make it not just a bunch of gigantic static classes with a million static functions. Breaking apart code into smaller chunks for clarity. I realized with how asynchronous this game is it will quickly get out of hand if I can't keep everything organized. So-far, so-good. I think I'm on the right track.
I'm out of room in the board area for troop reserves and killed units. Thus I need to bring the camera back a bit which I think is going to force me to make camera movement the next priority before any more game logic.
Didn't have much time so I traced some more tiles. The entire eastern coast is done. I realized afterwards I really should have been working on the West since that's where the next turn will be played out and I need some tiles to move to for testing. So that's what I'll work on next.
I did a little backend work 2 days ago but didn't feel I had enough to show. Tonight I finished up one of the first major breakthroughs for the game!
The U.S. player can make his first move! By selecting the units and then the tile he wants them to go to he can construct his "turn". The first turn of the game for the US player is to simply place his reinforcements in the city tiles. While this is happening, logical rules are preventing the player from...well...breaking the game rules of only placing them in cities, and only 2 units per city.
Once the player has his turn, he hits the complete action button and the commands are sent to the server where they are checked for validity against the rules and if all is well, the moves are executed by the server. At this point the clients receive one of the periodic broadcast messages and realize that they are stale and request the board state from the server and bingo! The clients see the moves made by the U.S. player.
It all seems to be working and this is a major step in the right direction. I think the best way for me to keep developing the game is to continue implementing a single phase of a turn at a time until the game can be fully played. Next up, is the western, southern, and eastern invader reinforcement placements. The good news is this is mostly the same as the US and I can reuse most of the code with a few changes to the logical rules of what is valid.
A few things I don't like. The rats nest of code continues to grow. I'm at a critical juncture of press ahead and hope I can keep it all straight till the end or see what if anything can be done to clean it up before I move on.
Either way, it's great progress and encouraging!
Completed:
Things to figure out:
Drawing the game pieces has been quite fun. A nice change from the coding. I'm not 100% satisfied but they turned out much better than I anticipated. They will at least work for the initial game. I didn't really have an art style in mind but I do like the flat color and clean lines (the troop kinda breaks this a bit but still feels like it fits in with the others). I honestly don't want too much detail for the pieces as there will already be a lot going on with the board and I don't want a bunch of rendering artifacts when zoomed way out.
Completed:
What I don't like:
Things I need to think about:
Coming next:
Accomplishments:
What I don't Like:
What's next:
Rolling on with the new project. Instead of long blog posts I think I'm going to go for shorter lists of things completed. Feels like less of a chore.
What I completed:
What I don't like:
What's next:
Nothing visible to show today. Worked on a a bit of UI code which then drove me to the task of font and text rendering. I struck out with getting the freetype2 library to compile so I went on to doing some research reading. Need to sleep on this one and figure out my next move.
After a few days enjoying the weekend and not working on the game it's time to get back in it. I want to start slow and pick up speed to not burn out. Didn't get a whole lot done today but mostly played around with a few tools. Namely, looking at a few 3d modelers (although I'll probably stick with my tried and true 3ds max) and a few online tools for generating noise patters. I want the polygons of the game to have an almost faded, dirty construction paper look to them. Based on some inspiration images I changed the background color to a dark purple as opposed to black. I want to play around with some ideas of doing different gradients but I'm not sure yet how I want to pull that off.
My "game" now has two of those three components with the addition of some camera logic. Meshes now "subscribe" to cameras that render them. This way things like UI graphics will only get rendered by an orthographic camera whereas the world stuff gets rendered by a camera that can zoom and spin. Next up might be a nice star background with a sun. This should give a better reference of rotation of the world in space. A quick demo moving the camera around seems to work just fine.
Today's work was all in the head. Namely solving one of the bigger algorithm challenges for my game. At least for now I want to avoid using any physics engines. I want to keep the game relatively simple. If at some point ragdoll or complex collision detection is needed I'll bring in an engine but for now I think I can pull it off with simple vector math. One of the things that will have to be implemented is a way for me to know what world tile a person, object, or point is over. This will be needed for things like who controls a land tile as well as where to position characters in 3d space so they appear on the surface. These are all derivatives of a common piece of logic. The problem space is this: Given a point in 3d space, what is the tile that is "below" that point (where below means a vector towards the center of the world). In other words there exists a function f(x) that when given a 3d point in space x finds the tile under it and I need to write that function. First I should say that if my world were divided in a simple longitude-latitude fashion the problem would be trivial. But who doesn't like a challenge. The nature of an icosphere is that the triangles that make it up are at weird angles. There may be some O(1) function but I can't come up with it in my head.
Instead I came up with two methods. The first method is actually quite simple. If I calculate the sum of the distance from each face vertex to the target point I can give each tile a "score". The tile with the lowest score should theoretically be the tile under the point. This is pretty fast and pretty easy to implement but there are a few downsides that rule it out as my implementation choice. First, this method only works if all faces have the same shape and size. That is mostly true for an icosphere and I could probably live with the results and tiny errors. The larger problem however is that the vertices that make up the faces must all be equidistant from the center of the sphere. Think of the case where the point is just off the edge of a plateau, the "score" to the flat tile at the top will be small compared to that of the face that has vertices way down low (which raise that faces score super high). In such an edge case the wrong tile will be selected. This is actually a subset case of the all same shape and size requirement.
So here is what I came up with and plan to implement. Given any world face (made up of 3 verts), there exists 3 planes that extend forever. Each plane is made up of three points that lay on the plane. Those 3 points are the center of the world and 2 of the 3 points that make up the face. A point is above a face if and only if it falls within the 3 sided "inverted pyramid" made up by these planes. There are a few technical details. First, I need to be consistent with polygon winding for these 3 imaginary planes. Not hard to do as I am already consistent with the ordering of the vertices that make up the face. I somewhat lied when I said we are going to make a plane...in fact all we really need out of these three planes is each of their normals (I'll explain why position is irrelevant in a minute). Calculating the normal is easy, just the cross product of two vectors constructed from the 3 points of the plane. So now we have 3 normals (1 for each imaginary plane) all pointing inward towards each other. Here is where the clever part comes, each of these constructed planes passes through the center of the world. We simply take the position we are testing and treat its position as a vector. By computing the dot product of this vector against the normal of each plane, we can quickly determine if the point is on the positive or negative side of the plane (and we don't have to worry about position of the plane because the vector to the point we are checking is already relative to a point on the plane (center of the world)) . If it's on the positive side of each of the 3 planes then we've found our tile! This method places no constraints on size or shape of the faces relative to each other. In fact they can even overlap and if a point is "above" more than one tile we can find them all! Although in my case I don't really plan to have any overlap so I'll optimize with an early exit out of the routine. There is also another huge optimization I would like to implement. The naive approach is to just start iterating over every face. Instead, I'm going to take advantage of the fact that the sphere is constructed from subdivided triangles. Essentially I have a tree structure. If I run the above algorithm at the root level I can determine the "hemisphere" to start looking in and repeat the process at each level until I find the face. The base icosphere has 12 traingles and each subsequent subdivision produces 4 traingles per triangle. So take a world that is subdivided 3 times. In a worst case scenario I will only have to do the above algorithm on 12 + 4 + 4 + 4 = 24 faces.
joined 3,139 days ago
Post a comment