Sprint 10 - Adam-Poppenheimer/Civ-Clone GitHub Wiki
Goals
- The gradual construction of improvements.
- Resource trading, facilitated by roads.
- A visual indicator of the current happiness/unhappiness of the active civilization.
- Gradual movement of units.
- Numeric indicators for the number of turns it'll take for a unit to move to a particular cell.
- Experience.
- promotions.
- The ability to fortify.
- The ability to pillage.
Risks and Mitigations
- Promotions will require a number of passive buffs that apply to certain units, as well as promotion trees for each type of unit. With the current implementation, that'll stand alongside a number of properties inherent to unit templates. That separation might be unnecessarily confusing.
- I already mitigated this issue in Sprint 9. I've got a clear plan for addressing this problem, namely by turning most sophisticated unit properties into passive buffs applied on unit creation.
- Resource assignment is not a very well-designed system at the moment, and resource trading will rely on it. This could combine with a number of edge cases involving trading (particularly what happens if a civ loses a copy of a resource it's trading away) could cause problems.
- This is an important enough part of the sprint that I can't simply ignore it. I can always rebuild resource assignment from the ground up (it's not a very involved piece of logic). I can manage resource trading by using the Command and Memento patterns on some ActiveTradeDeal struct that implements trading. That class can make sure resource assignment and unassignment are synchronized properly. For sudden resource disappearances, I'll probably need to check some ResourceUnassigned signal from whatever class is managing ongoing trade deals, that I can cancel deals to make sure that civilizations aren't trading away resources they don't have.
- This sprint will add several things that'll need to change as turns progress. Implementing this directly through TurnExecuter or GameCore could cause unnecessary coupling between those classes and irrelevant parts of the codebase.
- There's a reason why I added signals for the beginning and end of turns and rounds. My unit fortification state can increment some appropriate field when the RoundBegin event fires. My active trade deal manager can decrement the TurnsLeft properties on its active trade deals and cancel those that are ready. I don't foresee a need to couple these classes to GameCore or TurnExecuter.
- While the guide I've been using to help build this game has gradual movement of units, that movement assumes facts about the terrain mesh that are no longer true. If I can't apply its lessons to my codebase I won't have a clear way of moving units about the map.
- Gradual movement of units isn't a huge priority right now, so I can set it aside if it proves too difficult. But navigation over a mesh is a very, very common need of games. Unity has a NavMesh asset that I can probably apply to my terrain meshes to figure out how to navigate units across the surface of the world. If that doesn't work I'm sure there are other solutions I can find online.
Review
I managed to add promotions, the gradual construction of improvements, the gradual movement of units, and the majority of resource trading, though organizational mistakes have made it unclear how complete resource trading is or whether it was ready for deployment. I've also resolved a number of irritating bugs, though it's becoming clear that my codebase has lots more issues that need to be resolved.
Retrospective
What went well?
- I've finally resolved the gradual construction of improvements, and in a way that seems fairly robust.
- Gradual movement of units turned out to be easier than I'd feared, even though my requirements were substantially different than what the guide offered. I got a reasonable first approximation up without much difficulty.
- I came up with a fairly effective solution for the civilization connection problem that makes good use of existing code. It's not clear how performant it is at the moment, but for now it's a fairly clean solution to the problem.
What could be improved?
- My estimations for task difficulty were way off this sprint. Resource trading and the promotion system both required much, much more time than I expected because I failed to account for sub-components and was trying very hard to be fancy. In the future, I should try to break down my issues into smaller components to get a sense of their scale. If I find a bunch of component issues, I should consider splitting those off into separate tasks, or at least use my inspection to change the task's score.
- My simulation is complex enough that testing new features in integration is taking a lot of time. It can take a while to set things up by running through the simulation manually, and other elements can often interfere with what's being tested. I can make things run faster by improving my map-editing tools and by adding console commands, so that I don't have to play the game or negotiate with the simulation in order to set up tests.
- My codebase seems to be in a somewhat brittle and unstable state, with lots and lots of bugs. My guess is that my Definition of Done is insufficient. I've probably been flagging issues as resolved without having adequate proof of my solution's correctness. I need to spend a big chunk of time, maybe an entire sprint, debugging my codebase to make sure things work as expected even in unusual situations.
- There are pieces of my UI code (most notably the code that runs when a unit is selected) that seem to be a big, almost incomprehensible mess. I had to fight the urge to rebuild DefaultUnitState just because of how messy it was. It might not be valuable to rebuild what I've already made, but I should definitely make sure that future UI code is clean and comprehensible. Unit testing has often been useful in enforcing that requirement, so I might consider covering certain pieces of the UI with tests again.
- My codebase is getting large enough, and some of my decisions distant enough, that it' becoming hard for me to remember how everything is supposed to work. I should commit to documenting certain important design decisions (like when pointer events are supposed to fire) so that I don't have to rely on my memory.
- I think I'm running into the limitations of unit tests. I should take a look at more complete forms of testing (integration tests, acceptance tests) and consider using those to help debug and prevent regression. It's something I should learn how to do, anyways.