Today I polished the map some more. I simplified the algorithm so that instead of the four cameraTileX/Y & cameraPixelX/Y member variables there is now only a cameraLocation variable which tracks the total offset of the camera from the origin. The cameraTile and cameraPixel vars are computed as needed in RefillMapView. This let me adjust the map to also work in cases where edges don't wrap, which should be easy but wasn't before the simplification. Since I think it's in a good place now I'll merge the repeating map branch into Development soon unless there are any objections.
It's in a good place but the map movement is not yet perfect, there are two things left to do:
1. Clamp scrolling around unwrapped edges. Right now you can still just scroll off the edges. This is easy for the top and left since the boundary is zero but it will require some thought for the bottom and right edges.
2. Keep the map centered on the same tile as the zoom level is changed or the window is resized. Part of the problem here is the Godot camera is still a factor and it moves when the window is resized so we could either recenter the map on the camera or anchor the camera in place and center the map on the window. I prefer the second option.
I have no objections. I've been taking the backseat on the map, and it's been progressing well.
I agree it's time to add a Tile object. I've also been thinking about factoring out a Map object from Game, that would make the code neater especially once we have multiple map layers. A simple and natural first step would be to convert the game map into a 2D array of Tiles instead of an array of ints (specifying terrain) like it is now. I don't know about the toolbox architecture, I'll have to read up on that, and I'll admit I don't know how the event architecture is supposed to work or even what problem it's supposed to solve. None of this would conflict with what I've been doing with repeated tile maps since the MapView is a step removed from the map itself.
My understanding of the event architecture direction is that by emitting events in certain areas, and receiving them in others, it should help avoid tying the code too tightly together (which could make modding or modifying it more difficult), and perhaps also make it easier to separate the UI from the back end. Although I'm a little fuzzy on the event driven versus simply separating the UI logic from the core game mechanic logic (probably a C# "server" as Puppeteer mentioned, although I'm not sure I like the term "server" since it would be running locally in single-player).
So what I'm thinking now is that in the near future, we should probably add a could more sub-modules to our existing C7, ConvertCiv3Media, and QueryCiv3. One would be the C# server, or back-end, which will handle the mechanics. It will handle things like checking whether you can move a unit from Tile A to Tile B, calculating combat, and AI, if AI doesn't wind up in a separate module. Another would be a data model. This could be in the C# server, but I'm leaning towards keeping it separate so it's easier to keep the high-level mechanics separate from low-level data.
The front-end C7 Godot project would then call the back-end C# Server and say, hey, the player would like to move this unit here, or, the player changed which item they're building in Tokyo. The C# server could respond with an appropriate status, perhaps the unit is moved to a tile with another unit, and it responds with the results from the combat. Hypothetically, let's say your Regular Archer attacks my Veteran Spearman, maybe it responds with something like:
result = attack
target = spearman, position 24, 17
combatRounds = win, win, lose, win, lose, win
(Probably formatted differently)
The Godot UI could then play the appropriate animations based on that response, and the game state would already be updated for the end of combat on the server.
Also, have any of you given any thought to implementing multiplayer? IMO that's the biggest open architectural question. We should plan for that before we start working on the gameplay code because it would be very difficult to patch in after the fact. That's what Firaxis did for Civ 3 and is why its multiplayer is so buggy and crashy.
Not a lot specifically about multiplayer. But you're right, patching that in after the fact would be a challenge.
I think it would be a reason to make sure the UI and back-end mechanics piece are separate. And in theory what I described above could even be done across a network. But I also really don't know about things like synchronization between multiple players. E.g. while your Archer attacks my Spearman, Puppeteer's Swordsman moves into the area. In web programming, the thing that comes to mind is WebSockets, an example being you have a metro tracking application, and one of the trains move, you can broadcast its new position to all the clients really easily. But how that would translate to a desktop Godot game in C#, I don't know.
The other thing that I am reminded of is Civ4's infamous Out of Sync errors (and to be fair, it's not just Civ4 that has those, it just had a lot of them). There is probably a lot of complexity is synchronizing state across machines that may be across the world and may not have great network connectivity. I'm wondering if it would make sense to have an incoming action queue? So you move your Archer, the server locks an "update" resource, and if Puppeteer's Swordsman request arrives at the exact same time, it'll wait until the Archer update is processed, so e.g. if his Swordsman is trying to move to the same tile, we won't wind up with two units on the same tile (or my Spearman losing to your Archer but somehow defeating his Swordsman), but instead the server will reply something to the effect of "invalid move". The server could also send out an update to all the clients after your Archer defeats my Swordsman, although at that point we're getting into questions such as, "if Ozymandias's client is viewing a different part of the world, does it care about that update? if not, what about when he moves the map to view that part of the world?"
Yeah, that sounds complicated the more I think about it. I'm thinking maybe each client keeps a copy of all the data, so the Godot UI can request things for the map directly from its copy of the data. But to make any changes to the data, it has to go through the server. Which leads to questions about how the "C# server" would behave differently on the "real" server versus a networked player's server. Maybe if a networked player moves a unit, it calls the "move unit" method on their local C# server, but that in turn calls the "real" server and awaits a response, whereas if you're playing single player, it just makes the update.
No wonder things could get a bit laggy in multiplayer in Civ III and Civ IV.
And that's also not covering things like port forwarding, or alternatives to that.