[Dev] Early 0.2 "Carthage" Progress Thread

Quintillus

Archiving Civ3 Content
Moderator
Supporter
Joined
Mar 17, 2007
Messages
8,411
Location
Ohio
I was writing an update on what I'd done tonight, and starting thinking, "what's the right place for this?" I could reply to the dev diary thread, but that seems more like a place to discuss those change. I could start a progress thread like Puppeteer has, but I given how uncertain I am about my activity level, I'm not sure a one-developer-centric topic would be great in my case.

But it occurred to me that most of what I worked on related to one of the topics in WildWeazel's proposal document. Thus, for now, I thought why not have threads organized around those?

For those who haven't seen it, 0.2 "Carthage" covers:
  • Launch screen
  • Save and load
  • Select mods
  • Prototype combat
  • Main screen UI
  • Credits
  • UI file conversion
  • Prototype unit media
If others think this is a useful idea, we can create threads for the other early mileposts as well.

-------------------

Status:

I'm trying something new by trying to summarize the status of the objectives in this area. This is subject to interpretation, and will change with time, but having it in one place might help build consensus on where we are milestone-wise. Last updated on November 9, 2021.

DONE
  • None
ADEQUATE
  • Launch Screen. It can't save and load yet, but it can new game for what we support New Game for.

IN PROGRESS
  • Main screen UI. Probably need to define how much of it is done for "Carthage" (does that include the minimap?), but it's coming along.
  • Credits. Have the scene, need to figure out what we're putting there.
  • UI file conversion. Don't have civ colors yet, but we got a nice head start on this one.

TODO
  • Save and load
  • Select mods
  • Prototype combat
  • Prototype unit media, assuming this means "new format" media. If it means unit animation, it'll be In Progress soon given Puppeteer's prototypes.
-----------------

Without further ado, my updates tonight:

---

My updates tonight were around the main menu. I'd created the scene for it in February, but just having that one button that I never figured out how to place correctly was bothering me. So, I figured out a few things, and now we have all the (vanilla) menu items displaying, albeit all of them except "Exit" just go to the new game for now (exit does what you'd expect). Perhaps more useful long-term, I learned how to extract sub-PCX images outside of a tile set context, and used that to get the menu buttons extracted (using TextureButton in Godot to display them). I also learned a little bit about styles in Godot.

All in all, it's not a big update. But I'm hopeful that having something new visually will provide a spark, and it has also lessened the "oh my goodness there are way too many new things to learn in Godot" factor for me. I now have ideas about adding some buttons to the map screen, and registering events for them so even if they don't do anything initially, the can e.g. print "player pressed the build city icon" to the console.

This makes progress towards the 0.2 "Carthage" objective "Main screen UI".

(I still don't really plan to be "the Godot expert" long term, but it seemed like the right place to add something tonight)
 
Last edited:
I wound up adding the Credits page as well, since it was time for a refresher on adding a new scene, and I'd figured out how to import new resources.

I haven't yet added the actual Text/credits.txt file's contents, adding a placeholder instead. This is in part because text IO is another thing to figure out, but as much because this is an area where we might not want to use the original game content.

Still, I'm pleased with how quick it was to add the new scene. It makes me optimistic (perhaps too much so) that it may be relatively quick to add placeholders for other areas as well, such as Hall of Fame, Demographics, and Advisors. Adding graphics is also going quickly, which makes me optimistic for adding more UI elements on the map scene as well.

I'm leaning towards initially adding as much UI as possible as quickly as possible, to increase the immersion factor and make things feel more real. Longer term we'll definitely want to think about resolution independence and not making things 1024x768 forever, but considering how long the code has been idle, having a lot of things be navigable and showing up seems like a good idea for morale. And having a UI in place, even if it's not new-and-improved, means less work when we add features but need to hook them up for player feedback.
 
Oh yeah, target milestones. We have those. Good thinking!

I've also felt initially overwhelmed trying to "eat the elephant" all at once. But nah, then I realized I have *plenty* to do with fleshing out the Civ3 data and media reader code and any intermediate code.
 
Looks great! I recall seeing some tutorials on responsive menu design for Godot. I imagine we'll have our own native C7 main UI eventually, but there will likely be a lot of demand to use existing mods as-is including the interfaces.

But my experience with scaling the FLCs up and down shows me that Godot can pretty well handle scaling. Also, given how predictable the UI backgrounds are, we might even be able to cleverly expand them responsively without scaling the whole thing, but that's a crazy idea for the far future.

Spoiler Video of unit scaling tests with mipmaps enabled :

I discussed in my C# SAV/BIQ reader thread about the flags I set for mipmaps and something else...one helped upscaling and one helped downscaling I think.

I know these are units, but to Godot it's just a texture, and scaling the UI backgrounds will be the same as scaling the animated units.


I also agree that making it look like Civ3 and having clicks do something will help keep interest up. I feel compelled to make it load a real map from a SAV. I apparently more or less did that in my own project, so I just need to get that into the prototype. I was going to say I want to make the intermediate JSON first and have C7 code not touch the Civ3 save directly, but maybe it's better to make it externally pretty now and refactor it to be pretty code later.

Attaching screnshots of Quintillus' changes. The buttons even get the little red/orange highlight when you hover over them.

Why is it 4am?
 

Attachments

  • Screen Shot 2021-11-01 at 3.37.39 AM.png
    Screen Shot 2021-11-01 at 3.37.39 AM.png
    1,002.1 KB · Views: 35
  • Screen Shot 2021-11-01 at 3.37.46 AM.png
    Screen Shot 2021-11-01 at 3.37.46 AM.png
    1 MB · Views: 39
Yeah, "eat the elephant" is a good metaphor. Good point re: scaling. I remember that video, and indeed it does a pretty good job with the scaling. That could definitely be helpful in early stages (which could mean a long time) when what we have are existing graphics - and not necessarily even just the originals, but also modded ones that are the same resolution because they had to be to work nicely with Civ III.

Loading a real map from a SAV sounds like a great step that will also help with interest. And I recall Civ3 SAT being able to do that, so you have a great track record in that area!

Good idea with screenshots, too. It's interesting that your main menu screen has a 2K logo that mine doesn't have; they must have added that after Firaxis was acquired by TakeTwo. I'll try to remember to add screenshots when I add more visual updates and it isn't 4 AM; that will make it easier for WildWeazel to include them in any future dev diaries.
 
Another small update. I've been working on getting the first real "civ" icons in the main game screen, starting with the ones in the upper-left (main menu, civilopedia, and advisors). This proved to be a bit more challenging than expected, as I realized that Firaxis uses multiple methods of PCX transparency, and while Puppeteer's code handles the "last index of the PCX (usually pink)" one great, we didn't have anything for the "combine two PCX files, where one of them is the 'alpha' file" method (and indeed, I don't believe I'd ever added that in my editor, either).

Initial support for this is now in the 'getImageFromPCXWithAlphaBlend(Pcx imagePcx, Pcx alphaPcx, int leftStart, int topStart, int croppedWidth, int croppedHeight)' method in PCXToGodot.cs. It does not yet handle the fact that the alpha files may be smaller than the non-alpha ones, and meant to be repeated across them, beyond that it will stop and not crash if the alpha is smaller, while still applying alpha to the alpha-file-sized area. This is good enough for the menu icon to be alpha, though fleshing that out more fully will be necessary for e.g. the hover state menu icon to be alpha.

I also wanted to call out a utility method I added in Util.cs, 'static public ImageTexture LoadTextureFromPCX(string relPath, int leftStart, int topStart, int width, int height)'. This combines the create PCX function and the getImageTextureFromPCX function, as well as optional cropping (the one-parameter method does no cropping). It seemed like a reasonable utility method to simplify PCX loading in the simple cases. I then immediately found a complex case that can't use it, but a few areas have been changed to use this new utility function.

I believe this falls into the "Main Screen UI" area, and I now realize my earlier menu work may have been part of 0.6 "Greece": Menu and Settings (although some menu work is needed for 0.3 "Carthage" Credits). Main Screen UI probably meant the game screen, not the main menu. Oh well, that main menu work was helpful for this work as well.

Attachment: Game screen with the menu buttons, one of which has alpha enabled. They do not yet function.
 

Attachments

  • MenuButtons.png
    MenuButtons.png
    559.7 KB · Views: 39
Cool! Yeah, I recall having transparency and shadows working to a point (for units at terrain at least) but probably needing more in the future. Frustratingly, palette arrangements aren't particularly consistent across graphics types (unit/terrain/etc). Smoke isn't yet implemented if I recall correctly.

Also I don't think I have civ colors handled yet, but I remember discussing it a lot.

Combining PCX as you describe is new to me.
 
Civ colors is a feature that I implemented, at least for units_32.pcx, in my editor; the crux of the code is here. It uses the ntp##.pcx files to get the civ colors, and replaces palette indices 0-15 and even numbers from 16 through 63 with the palettes of the same index from the ntp##.pcx file corresponding to the civ's civ color. At least, if my re-reading of that code in a few minutes is accurate. (I'm also not sure why that code uses OldPCXFilter, whereas most uses the regular one... I don't recall the difference between those but it may be relevant in that case).

I don't think I've ever looked at shadows. I did add fog of war to my editor, IIRC, though that may not be the same as smoke.
 
Made some more progress on the main screen UI. Specifically, adding the lower-right status box and some items on it (see picture).

The static image doesn't show it, but the light in the upper left of the box will start blinking (alternating orange and blue) after 5 seconds of it being your turn, to indicate that it's time for you to end your turn. Once you end your turn, it will go back to its default, not-orange-or-blue state. While in that non-active state, you can hover over it to make it turn orange. You can also end the turn by clicking on it, just like the "End Turn" button that, for now, remains.

The text in that area is hard-coded for now, but the alignment should be generally correct (they are offset from the right edge of the box, and centered, not hard-coded into the UI as a whole). I think they also offer a tempting area to provide early visual feedback about the evolving game state - most specifically, updating the game year as turns are processed. Even just a base "change it by 50 years every time a turn ends" would provide a more dynamic feedback loop. Though it's worth noting that we do have a feedback loop - enabling and disabling the End Turn button (and I suppose now, making the end turn indicator stop blinking) - the game year would just be tied more to game state, and not solely to UI.
 

Attachments

  • LowerRightBox.png
    LowerRightBox.png
    589.8 KB · Views: 39
I wound up splitting the lower right area into its own node. That saved 83 lines from Game.cs, out of 390 initially. So, significant. It worked, with one exception: signals.

I tried adding a TurnEnded signal in Game.cs, and emitting it from the new LowerRightInfoBox.cs. But despite also having code in Game.cs to connect up with that signal, it never seems to arrive.

I'm not sure whether I'm trying to use signals in the wrong way, or if it's just a silly mistake. There's a TODO near the end of LowerRightInfoBox.cs about it. I'm wondering if @WildWeazel could take a look at it, having written the previous (successful) signal? It seems like we probably will want this sort of work flow fairly often - e.g. you click on the "Build city" button in a child node, and it triggers some logic in the Game node (or some intermediary).

Here's the StartGame code in Game.cs:

Code:
    private void StartGame()
    {
        GD.Print("Game starting");
        TurnCounterComponent turnCntCpnt = ComponentManager.Instance.GetComponent<TurnCounterComponent>();
        Connect(nameof(TurnStarted), turnCntCpnt, nameof(turnCntCpnt.OnTurnStarted));
        Connect(nameof(TurnEnded), this, nameof(OnPlayerEndTurn));
        OnPlayerStartTurn();
    }

We can see my signal right below WildWeazel's signal. I'm a little suspicious that it might not handle "this" well, but we'll see. OnPlayerEndTurn links right up to the intended function, at least in VSCode.

The code in LowerRightInfoBox.cs that tried to emit it:

Code:
    private void turnEnded() {
        GD.Print("Emitting the turn end signal");
        //TODO: This signal is not picked up for some reason.
        EmitSignal(nameof(Game.TurnEnded));
       
    }

The print line is showing up in the console, so it's getting that far at least.

And, finally, the signal declaration in Game.cs:

Code:
    [Signal] public delegate void TurnStarted();
    [Signal] public delegate void TurnEnded();

Something isn't lining up though...

Other than that, I'm pleased with how splitting out the new node went.
 
I remember that same-scene signals are easy, but cross-scene signals require something extra. I don't recall what is if offhand. At a very quick Google it may also or only need to have signal-sharing scenes as children of a common parent scheme, or maybe just a common ancestor.
 
Yeah, from what I've read I am wondering if the problem has to do that my new node is not a descendant of the game node. Although my brain is becoming confused over the difference between child/descendent in Object-Oriented, and child/descendent in the scene. The new node is a child of the Game node in the scene, but the new class is not a child in the object-oriented sense.
 
Yeah, it takes a bit to get used to. Scenes are hierarchically organized, and if affects how signals are passed, and there are scene paths for referencing other scenes.

OO inheritance is also a thing.

In fact, the top-level Node OO class is what has the hierarchical structure. All the scenes are OO descendants of Node. In the Scene tree, you can click add and browse the OO inheritance, and then you place it in the scene tree hierarchy which affects at least the signaling.

Browsing the scene tree is also a little bit like browsing an HTML DOM. Actually a lot like it. Contextually-linked objects which all descend from HtmlElement (or maybe just Element) in the case of the DOM.

That's the technical side. Remember Godot is aimed at game makers of various sorts. They may be artists or such and not programmers. So as a UI the scene hierarchy and the Inspector (which is basically a visual representation of the object's members and methods) let's them tweak each object. And if they feel really advanced they can copy/paste a little GDScript to make something happen you can't via the Inspector.

We're coming at it programmer-logic-first, so it's an odd angle.
 
The DOM similarity is quite true, and it's particularly relevant when I think of modern frameworks like Angular, which let you define your own custom elements, and put them in the DOM, and it all just works magically even though they aren't real HTLM elements. There might be an <AVATAR> element and a <SIGNATURE> element if we were building a web forum with Angular, for example.

It is an interesting thought that our programmer-logic angle may well be the odd one when it comes to the Godot audience. I've found myself almost exclusively using VSCode when working on the project, largely because I've found its editor to be more powerful, especially for drilling down into method and property definitions to help me figure out how they're supposed to be used. And perhaps due to the nature of most of what we've been writing, the Inspector doesn't show a lot about, e.g. the DomesticAdvisor.cs file I just added, even though it is a Node2D. It's probably also considered unusual that we're just loading all of our resources externally instead of having them bundled.

I rather feel like I'm learning how to use Godot the framework/engine, but not really Godot the editor. Although the latter does have some nice features, like the build system for 0.0 "Aztec".
 
I now have the quit button going back to the main menu. According to the following link,
GetTree().ChangeScene("res://MainMenu.tscn") should delete the C7Game scene and free it from memory. So we can go back and forth from the game screen to the main menu repeatedly.

https://docs.godotengine.org/en/stable/tutorials/misc/change_scenes_manually.html

I did hit a snag at first. Quintillus' TurnCounterComponent already exists on the second time C7Game scene is run. Components are completely new to me in the Godot context, so I'm not sure what the right way to handle that is. I just wrapped it in a try/catch, and if an exception is thrown it resets the turn counter via a new method I added to TurnCounterComponent.

I need to learn more about components, though. That looks like it may be how I'd want to handle the persistent game data / logic between scenes.

Agree on learning the engine vs learning the editor. Left to my own devices I tend to do everything in code. It's actually possible to compile out the editor and scene tree and do it all in code. But I figure a basic scene tree should make it clearer in a project like this. Offhand I'm thinking every major UI screen should have its own tscn file and spot in the scene tree browser. Basically for clarity / self-documentation. But I'm really new at this, so what do I know?
 
I moved your info box into a control. Actually I changed it from a Node2d to a TextureRect to make it a control then stuffed it into a MarginContainer.

Then I confused myself for a while and somehow managed to properly anchor it to the bottom-right. Don't ask me to explain how, I couldn't tell you because I'm not sure. But it's controls in controls in controls and anchors and rectangles and negative margins and layouts. (Ok, actually the key seems to be to set the layout to bottom right–which seems to set all four anchor values to 1–and the negative left and top margins because the texture starts at 0,0.)

I also completely broke all the input handling but inadvertently fixed it by moving the new control above the existing toolbar control. I seem to vaguely remember that the scene tree hierarchy impacts input and that order is important, but I don't recall exactly how or why.

It definitely affects draw order.

I "fixed" the signal emission. You're just grabbing the signal and emitting it with a C# call, but you have to go find the right node. You would have needed GetParent().EmitSignal(<yada yada>) and it would have worked. Due to its position in the scene tree I have to get the 3rd ancestor which looks ugly, and there is probably a better "right" way to do it we'll later discover.

The short of it is that the info box stays in the UI lower right corner while the map can resize and scroll all it wants and the window can resize all it wants.

Edit: Incidentally, I don't really expect the current top bar controls to persist as-is. They were my first foray into working with anchored responsive controls and done while I was working on scroll and zoom inputs.
 
Last edited:
I've been thinking about how to make the map repeat around wrapped edges. Unfortunately it looks like the Godot devs didn't build TileMap with that in mind. So far the best idea I have is to use the TileMap node as only a map view i.e. create a TileMap just large enough to cover the screen then fill it in with whatever tiles are supposed to be underneath the camera. In general it would have to be refilled every frame, hopefully that won't be a problem for performance. But the advantage to doing that is it would be easy to duplicate tiles around edges.

Also it would make more sense to move the TileMap node instead of the Player that way everything else just stays in place without any effort to anchor it.
 
I put the other UI elements in the toolbar, and now they are responsive and anchored to the UI window instead of the map. That was actually easier as they were all already Control descendants.

The End Turn button didn't need any modification aside from adding it to the toolbar node instead of the game node. Since we already had a reference to the object and were in the same context as the signal, there was no issue in defining the signal. So I guess that's another way to hook signals up: have references to both nodes in-hand already.

@Flintlock I felt like I was pretty close to figuring something out. The player object seems a weird way to do it, but it for the most part seems the easiest way forward. It's meant to be used as the player position on a 2d side scroller, but for map scrolling it works pretty darn well.

We seem to be only able to have one camera node per Node2D, else I'd have 2 cameras (or 3 for really wide screens) and just warp the off-screen camera. I vaguely remember thinking I might try having a Node2D with a camera within a Node2D with a camera and get two cameras that way, but not sure if I ever got around to it.

Under the Experiments folder I have some scenes where I was trying to get scrolling working, although I think what's there now is in a failed state. I had this idea that an object copy would make references to all the member values, so I could have two views of the same shared tiles.

If we do have to go back to repositioning individual tiles, I recall thinking it might be more efficient to have columns of tiles and reposition the whole column rather than all the tiles individually. But I don't recall how much that really matters.

In any case, if you can make scrolling work in any manner, go for it!
 
I'm working on implementing map scrolling like I described. When I mentioned the camera I wasn't thinking of any kind of official Godot Camera node, I was just thinking of a pair of coords storing the upper left corner of the player's view of the map. IMO that's all a camera should be unless there's some reason to complicate it. The thing with moving the Player object is that it's just as easy to move the TileMap but when you move the TileMap nothing else changes so the problem of anchoring the rest of UI just doesn't exist.
 
I moved your info box into a control. Actually I changed it from a Node2d to a TextureRect to make it a control then stuffed it into a MarginContainer.

Then I confused myself for a while and somehow managed to properly anchor it to the bottom-right. Don't ask me to explain how, I couldn't tell you because I'm not sure. But it's controls in controls in controls and anchors and rectangles and negative margins and layouts. (Ok, actually the key seems to be to set the layout to bottom right–which seems to set all four anchor values to 1–and the negative left and top margins because the texture starts at 0,0.)

I also completely broke all the input handling but inadvertently fixed it by moving the new control above the existing toolbar control. I seem to vaguely remember that the scene tree hierarchy impacts input and that order is important, but I don't recall exactly how or why.

It definitely affects draw order.

I "fixed" the signal emission. You're just grabbing the signal and emitting it with a C# call, but you have to go find the right node. You would have needed GetParent().EmitSignal(<yada yada>) and it would have worked. Due to its position in the scene tree I have to get the 3rd ancestor which looks ugly, and there is probably a better "right" way to do it we'll later discover.

The short of it is that the info box stays in the UI lower right corner while the map can resize and scroll all it wants and the window can resize all it wants.

Edit: Incidentally, I don't really expect the current top bar controls to persist as-is. They were my first foray into working with anchored responsive controls and done while I was working on scroll and zoom inputs.

I just downloaded your changes and studied them, and I'm pleased to say that I think I follow it all! I see you are using Godot and the scene (.tscn area), which is something I had ignorantly ignored previously. But certainly one that makes sense to utilize. And the zooming is so much better with only the map, and not the UI, scaling. The resize-and-it-stays-anchored behavior is also nifty.

I see the signal fix too. It does seem like there's probably a more elegant way that we don't know about (I'm imaging it being nested eight layers deep in GetParent), but as one of my collleagues once said, functionality is king, and now it's functional.
 
Top Bottom