www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Reworking the control flow for my tactical role-playing game

reply Liam McGillivray <yoshi.pit.link.mario gmail.com> writes:
As many of you know, I have been trying to write a tactical 
role-playing game (a mix of turn-based stategy & RPG) in D. This 
is the furthest I have ever gotten in making an interactive 
program from the main function up. Right now, it is not yet 
playable as a game, but you can interact with it and get a rough 
idea of what I'm going for. Feel free to download and run it to 
see what I have so far.

https://github.com/LiamM32/Open_Emblem

I'm now at a point where I have trouble figuring out the next 
step to making the game playable. The complexity may have just 
reached a point where I find it harder to keep track of 
everything that I have written. There is probably a fair amount 
of unused code that I abandoned after deciding on a different 
solution, but forgot to delete. There are probably also some 
amateur decisions I've made in structuring the program, given 
that I largely figured it out myself.

For some time now I've thought that I may later want to overhaul 
how the whole rendering and UI system work. Perhaps now is a good 
time since my productivity under the current system is slowing 
down.


The code for Open Emblem (name subject to change) is split 
between a source library, which handles the internal game logic, 
and a graphical front-end program which uses that library, but 
makes it usable.

When starting, I decided to structure it this way so that I can 
experiment with different graphics and UI libraries. This may 
have been a good move, even if it complicates some aspects, as 
the first library I tried wasn't the one I've stuck with. I also 
thought that this library may also be usable as a platform for 
others to make their own tactical RPG games, though that's 
unlikely with the current direction of the project.


The most important modules here are `map`, `tile`, & `unit`, 
which contain the classes `Map`, `Tile`, & `Unit`. There is 
nothing here specific to any particular graphics or game library.

Well, `Map` is now longer actually a class, as it's been replaced 
by the `Map` interface and `MapTemp` template which implements 
it, but for simplicity, I'll refer to `Map` as a class. This 
class is meant to serve as the master that controls the flow of a 
single game mission. Only one instance is meant to exist at a 
time. It holds a 2-dimensional array of `Tile` objects which 
represents the grid that the game is on (like a chessboard) and 
an array of all `Unit` objects.

`Unit` represents a character in the game that can be moved on 
the map (like a chess piece). It has some stats stored as 
variables, and some functions to do various things a player (or 
AI) may ask the unit to do during their turn. Each unit occupies 
a tile object.

`Tile` is a square on the map, which has it's own *x* & *y* 
coordinate.

The `Faction` class currently only serves to store a set of units 
belonging to a certain player or AI, but is planned to play a 
bigger role later.


After looking at many libraries and taking a shot at 
[ae](https://github.com/CyberShadow/ae) & 
[godot-D](https://github.com/godot-d/godot-d) but not really 
figuring it out, I was recommended 
[raylib-d](https://github.com/schveiguy/raylib-d), a binding for 
[raylib](https://www.raylib.com/) by  Steven Schveighoffer. 
Raylib is a rather simple graphical library written in C. I ended 
up sticking with it because the website has so many 
easy-to-follow examples that make it easy as my first graphical 
library. They're written in, but I adapted them to D rather 
easily. Of course, being written in C has limitations as it isn't 
object-oriented.

This is front-end is in the 
[`oe-raylib/`](https://github.com/LiamM32/Open_Emblem/tree/master/oe-raylib)
directory.

For this front-end, I've made the classes `VisibleTile` and 
`VisibleUnit`, which inherit `Tile` & `Unit`, but add sprite data 
and other graphics-related functionality.

I then have the `Mission` class which inherits the `MapTemp` 
class. This class dominates the program flow in it's current 
state. It handles loading data from JSON files, switching between 
different game phases and does most of the function calls related 
to rendering and input.

The way I have it currently, there's a `startPreparation` 
function and `playerTurn` function, each of which run a 
once-per-frame loop that renders all the necessary objects and 
takes user input. They each have a rather messy set of 
if-statements for the UI system. Any UI elements that may pop-up 
are declared before the loop begins, with if-statements to 
determine whether they should be visible this frame.

For UI elements, I currently have `version` flags for either 
`customgui` (which I started writing before discovering raygui) 
and `customgui`, which you can select between using `dub 
--config=`. Having both makes the code messier, but I haven't yet 
decided on which I prefer. They are both currently achieve 
equivalent functionality.

Everything here is single-threaded. Despite that, I still get 
thousands of frames-per-second when disabling the cap on 
framerate.

To get a glimpse of a flaw with the current approach (which may 
be simpler to fix with an overhaul), try asking one of the units 
to move during your turn, but then try moving the other unit 
while the first one hasn't reached their destination. The first 
unit will stop.



So now I am thinking of reworking the rendering system, but also 
changing some of my approach to how the Open Emblem library works.

I've been thinking of adopting an event-driven approach, using 
signals and slots, for both the library and the front-end (and 
between the two). I'm curious if more experienced programmers 
think this is the right approach.

Play Fire Emblem. When you command one of your units to move and 
attack an enemy unit, you don't just see them teleported to their 
destination and the enemy dead (or lower in HP) as soon as next 
frame. Instead, it will start an animation of your unit 
attempting to attack the other, and after ~3 seconds you find out 
whether they hit or missed (which is based on probability). In 
contrast, under my current approach where a game event happens by 
calling a function, everything will happen instantly. One way to 
solve this would be to have the rendering object not look 
directly at the underlying variables, but some cached variables 
that get updated less quickly. In Fire Emblem, it's likely that 
the game has already determined whether an attack succeeds or 
fails immediately after it's selected, even if the player has to 
wait 3 seconds before being shown. This is a little bit like how 
my `Unit` objects have a variable for their grid location which 
gets changed by the `move` function, but then there's another 
variable to represent screen location, which gets updated more 
slowly as they walk across the screen. The other option is to 
have these functions happen in a separate thread, with parts 
where they must wait for a signal to continue further.

Another use of signals and slots is that I can use 
multi-threading for things that happen once-per-frame. When I 
added the feature to make units slowly move to the destination 
selected by the player, I thought I would use a separate thread, 
but then I realized it would need to be synchronized with the 
frames, which happens in the main thread.

If I redo the rendering and UI system, I will probably start 
using [`Fluid`](https://git.samerion.com/Samerion/Fluid), which 
is a Raylib-based UI system written in D.

As for the rendering loop, how should that work? I don't know how 
it works in other 2D games. Should it be much like the current 
approach, with a loop for every game phase containing everything 
it might need to render during that phase, and using logical 
statements for things that only *sometimes* appear? As an 
alternative, I was thinking of making a `Renderer` object that 
runs the rendering loop in it's own thread, and it has variables 
to keep track of what's currently visible. Another thread would 
access functions of this object to change what must be rendered. 
I don't know what's the best approach.

To anyone who made it this far, thank you very much for reading 
all of this. Is my current approach to rendering bad, or actually 
not that far off? Would signals and slots be a good thing to 
adopt?
Mar 16
next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On Sunday, 17 March 2024 at 00:14:55 UTC, Liam McGillivray wrote:
 As many of you know, I have been trying to write a tactical 
 role-playing game (a mix of turn-based stategy & RPG) in D. 
 This is the furthest I have ever gotten in making an 
 interactive program from the main function up. Right now, it is 
 not yet playable as a game, but you can interact with it and 
 get a rough idea of what I'm going for. Feel free to download 
 and run it to see what I have so far.

 https://github.com/LiamM32/Open_Emblem
I got it to run on my mac, I had to do a few updates to the dub.sdl file, but it did work, though I couldn't figure out how to make attacks work.

 The code for Open Emblem (name subject to change) is split 
 between a source library, which handles the internal game 
 logic, and a graphical front-end program which uses that 
 library, but makes it usable.
This is kind of cool, I like the idea!

All sounds good

 After looking at many libraries and taking a shot at 
 [ae](https://github.com/CyberShadow/ae) & 
 [godot-D](https://github.com/godot-d/godot-d) but not really 
 figuring it out, I was recommended 
 [raylib-d](https://github.com/schveiguy/raylib-d), a binding 
 for [raylib](https://www.raylib.com/) by  Steven Schveighoffer. 
 Raylib is a rather simple graphical library written in C. I 
 ended up sticking with it because the website has so many 
 easy-to-follow examples that make it easy as my first graphical 
 library. They're written in, but I adapted them to D rather 
 easily. Of course, being written in C has limitations as it 
 isn't object-oriented.

 This is front-end is in the 
 [`oe-raylib/`](https://github.com/LiamM32/Open_Emblem/tree/master/oe-raylib)
directory.

 For this front-end, I've made the classes `VisibleTile` and 
 `VisibleUnit`, which inherit `Tile` & `Unit`, but add sprite 
 data and other graphics-related functionality.

 I then have the `Mission` class which inherits the `MapTemp` 
 class. This class dominates the program flow in it's current 
 state. It handles loading data from JSON files, switching 
 between different game phases and does most of the function 
 calls related to rendering and input.

 The way I have it currently, there's a `startPreparation` 
 function and `playerTurn` function, each of which run a 
 once-per-frame loop that renders all the necessary objects and 
 takes user input. They each have a rather messy set of 
 if-statements for the UI system. Any UI elements that may 
 pop-up are declared before the loop begins, with if-statements 
 to determine whether they should be visible this frame.

 For UI elements, I currently have `version` flags for either 
 `customgui` (which I started writing before discovering raygui) 
 and `customgui`, which you can select between using `dub 
 --config=`. Having both makes the code messier, but I haven't 
 yet decided on which I prefer. They are both currently achieve 
 equivalent functionality.

 Everything here is single-threaded. Despite that, I still get 
 thousands of frames-per-second when disabling the cap on 
 framerate.
Note that disabling the cap on framerate just avoids the sleep-per-frame that raylib does. I always recommend setting a cap of something like 60 unless you are going to use vsync.
 To get a glimpse of a flaw with the current approach (which may 
 be simpler to fix with an overhaul), try asking one of the 
 units to move during your turn, but then try moving the other 
 unit while the first one hasn't reached their destination. The 
 first unit will stop.
So when doing video game development with a main loop that needs to refresh the screen every frame, you need to componentize long-running operations into frame-size bits. So for instance, an animation that needs to move an object from A to B, should be captured into a temporary item (class object, struct, member of the sprite, etc), where you tell it every time you are drawing a frame (or even better yet, each game tick), and let it make the changes necessary for one tick of time. For instance, build an object that takes start position, end position, time to animate, and maybe a path function (like linear, ease-in/ease-out, etc), and then each frame calculates where the position should be based on the current time vs. the start time. Encapsulating all this into an object makes things easy to deal with. Then you just need to call it every frame/tick.


 So now I am thinking of reworking the rendering system, but 
 also changing some of my approach to how the Open Emblem 
 library works.

 I've been thinking of adopting an event-driven approach, using 
 signals and slots, for both the library and the front-end (and 
 between the two). I'm curious if more experienced programmers 
 think this is the right approach.
I'm not sure if you want to do event driven here. It's a possibility. But I find a game-tick system, where each tick, you update each object according to its wishes to be pretty easy to develop with. I will add the caveat that I am also a pretty novice game developer, and have never actually built a complete game. If I were to recommend a system here, I'd create a linked list of items to "tick" every frame, with something like: ```d interface GameObj { // returns false if this object is done bool tick(); } ``` Then basically, you go through your list every frame, and call the tick function, which will make needed changes, and if it returns false, then you remove from the list while iterating. This means you can do N things at once, and you don't need multiple threads to do it.
 Play Fire Emblem. When you command one of your units to move 
 and attack an enemy unit, you don't just see them teleported to 
 their destination and the enemy dead (or lower in HP) as soon 
 as next frame. Instead, it will start an animation of your unit 
 attempting to attack the other, and after ~3 seconds you find 
 out whether they hit or missed (which is based on probability). 
 In contrast, under my current approach where a game event 
 happens by calling a function, everything will happen 
 instantly. One way to solve this would be to have the rendering 
 object not look directly at the underlying variables, but some 
 cached variables that get updated less quickly. In Fire Emblem, 
 it's likely that the game has already determined whether an 
 attack succeeds or fails immediately after it's selected, even 
 if the player has to wait 3 seconds before being shown. This is 
 a little bit like how my `Unit` objects have a variable for 
 their grid location which gets changed by the `move` function, 
 but then there's another variable to represent screen location, 
 which gets updated more slowly as they walk across the screen. 
 The other option is to have these functions happen in a 
 separate thread, with parts where they must wait for a signal 
 to continue further.
I think you are better off not using threads. Threads make things very difficult to synchronize, and you have no guarantees that your animations will run at any specific time. I don't think you would like the results.
 Another use of signals and slots is that I can use 
 multi-threading for things that happen once-per-frame. When I 
 added the feature to make units slowly move to the destination 
 selected by the player, I thought I would use a separate 
 thread, but then I realized it would need to be synchronized 
 with the frames, which happens in the main thread.
Yep!
 If I redo the rendering and UI system, I will probably start 
 using [`Fluid`](https://git.samerion.com/Samerion/Fluid), which 
 is a Raylib-based UI system written in D.

 As for the rendering loop, how should that work? I don't know 
 how it works in other 2D games. Should it be much like the 
 current approach, with a loop for every game phase containing 
 everything it might need to render during that phase, and using 
 logical statements for things that only *sometimes* appear? As 
 an alternative, I was thinking of making a `Renderer` object 
 that runs the rendering loop in it's own thread, and it has 
 variables to keep track of what's currently visible. Another 
 thread would access functions of this object to change what 
 must be rendered. I don't know what's the best approach.
One thing to consider is doing game ticks separate from frames. That is, your game tick timer is not locked to the frame rate. This way if you drop frames, the game doesn't change its timing. The gui stuff is typically one call per frame loop, and I think it does all drawing and processing of inputs there.
 To anyone who made it this far, thank you very much for reading 
 all of this. Is my current approach to rendering bad, or 
 actually not that far off? Would signals and slots be a good 
 thing to adopt?
No, I think you are in pretty good shape! I don't know much about signals and slots, so I'll leave that unanswered. -Steve
Mar 21
parent Liam McGillivray <yoshi.pit.link.mario gmail.com> writes:
On Thursday, 21 March 2024 at 16:48:39 UTC, Steven Schveighoffer 
wrote:
 On Sunday, 17 March 2024 at 00:14:55 UTC, Liam McGillivray 
 wrote:
 As many of you know, I have been trying to write a tactical 
 role-playing game (a mix of turn-based stategy & RPG) in D. 
 This is the furthest I have ever gotten in making an 
 interactive program from the main function up. Right now, it 
 is not yet playable as a game, but you can interact with it 
 and get a rough idea of what I'm going for. Feel free to 
 download and run it to see what I have so far.

 https://github.com/LiamM32/Open_Emblem
I got it to run on my mac, I had to do a few updates to the dub.sdl file, but it did work, though I couldn't figure out how to make attacks work.
Great. You may be the first person to download and run it. I would appreciate if you committed and pushed the changes to the `dub.sdl` file. So far I've only tested it on Linux. Attacks don't fully work yet. When selecting "Attack" in the menu, you should see the tiles in range marked in red, but clicking one will as far as you can tell, do nothing but bring you back to the previous menu. Right now it's programmed to lower the enemy HP on attack, but there's no way for the player to see that it worked. Nothing currently happens when HP goes to zero or lower.

 The code for Open Emblem (name subject to change) is split 
 between a source library, which handles the internal game 
 logic, and a graphical front-end program which uses that 
 library, but makes it usable.
This is kind of cool, I like the idea!
Good to hear. It makes some things difficult when I don't allow myself to put anything specific to any graphics or UI library in the library, but it also may make it easier if I rework the graphics and UI.
 Everything here is single-threaded. Despite that, I still get 
 thousands of frames-per-second when disabling the cap on 
 framerate.
Note that disabling the cap on framerate just avoids the sleep-per-frame that raylib does. I always recommend setting a cap of something like 60 unless you are going to use vsync.
The "framerate-test" configuration only exists as a benchmark to give me an idea of how far I am from the CPU's limit. It's not for playing. In the default configuration and the others, it currently uses the `getRefreshRate` function to set the target framerate to the monitor's refresh rate on Linux. It's supposed to do that too on Windows, but I haven't tested it. On Mac it just sets it to 60 FPS.
 So for instance, an animation that needs to move an object from 
 A to B, should be captured into a temporary item (class object, 
 struct, member of the sprite, etc), where you tell it every 
 time you are drawing a frame (or even better yet, each game 
 tick), and let it make the changes necessary for one tick of 
 time.

 For instance, build an object that takes start position, end 
 position, time to animate, and maybe a path function (like 
 linear, ease-in/ease-out, etc), and then each frame calculates 
 where the position should be based on the current time vs. the 
 start time. Encapsulating all this into an object makes things 
 easy to deal with. Then you just need to call it every 
 frame/tick.
Interesting. This is a different approach from how I imagined it. I never thought I would add a whole new object just to move another object around. Instead I was thinking of having a function in `VisibleUnit` that moves itself to the next location on a path (represented as an array of either directions or locations). Either this would be called for every unit every frame (but it would do nothing if they don't have a path), or there would be an array of moving units in which this function would be called in the rendering loop. Perhaps if I had just used the plain `Unit` class from the library instead of making the derived `VisibleUnit` class, I would consider this approach.
 I'm not sure if you want to do event driven here. It's a 
 possibility. But I find a game-tick system, where each tick, 
 you update each object according to its wishes to be pretty 
 easy to develop with. I will add the caveat that I am also a 
 pretty novice game developer, and have never actually built a 
 complete game.

 If I were to recommend a system here, I'd create a linked list 
 of items to "tick" every frame, with something like:

 ```d
 interface GameObj {
    // returns false if this object is done
    bool tick();
 }
 ```

 Then basically, you go through your list every frame, and call 
 the tick function, which will make needed changes, and if it 
 returns false, then you remove from the list while iterating.

 This means you can do N things at once, and you don't need 
 multiple threads to do it.
Well this sounds not so different from signals and slots. My current understanding is that every time the signal is called, that same thread goes through a list of functions connected to that signal. Back when I wrote this post, I had a worse understanding of signals and slots, and thought that it might be a thing for inter-thread messaging.
 I think you are better off not using threads. Threads make 
 things very difficult to synchronize, and you have no 
 guarantees that your animations will run at any specific time. 
 I don't think you would like the results.
Yeah. I can see how it may make things unpredictable. My current thought is to have only one general-purpose thread. If I experiment with others, they will probably be created just for one particular task before being ended. It might still end-up being single-threaded until things start to slow down. But even with single-threading, I will need to figure out a way to make animations happen at the right times without the library dictating when the animations happen.
 If I redo the rendering and UI system, I will probably start 
 using [`Fluid`](https://git.samerion.com/Samerion/Fluid), 
 which is a Raylib-based UI system written in D.

 As for the rendering loop, how should that work? I don't know 
 how it works in other 2D games. Should it be much like the 
 current approach, with a loop for every game phase containing 
 everything it might need to render during that phase, and 
 using logical statements for things that only *sometimes* 
 appear? As an alternative, I was thinking of making a 
 `Renderer` object that runs the rendering loop in it's own 
 thread, and it has variables to keep track of what's currently 
 visible. Another thread would access functions of this object 
 to change what must be rendered. I don't know what's the best 
 approach.
One thing to consider is doing game ticks separate from frames. That is, your game tick timer is not locked to the frame rate. This way if you drop frames, the game doesn't change its timing.
I thought about that, but if I do this, then I would probably want to make it multi-threaded. The thread that updates things once per tick would be separate from the one that updates things once per frame. It would be easier than doing this single-threaded. An update on Fluid; I realized that it doesn't have a feature to do scrolling. I also don't see anything for buttons with images. I have an idea of how I can implement these things with Raylib. I'm not sure if it would be better/easier to just do that with my custom GUI system, or to make derivatives of Fluid classes, and possibly make a contribution to Fluid. There's also the issue that the theme system in Fluid is going to be overhauled. Right now I'm going through a trilemma of doing a fully custom GUI, using raygui, or Fluid. This becomes of quadrilemma if I add a fourth option of ditching Raylib, switching to SFML, and using one of their GUI libraries (TGUI or DIMGUI). You might notice that in the current "raygui" configuration, the menu at the bottom of the screen in the preparation phase isn't using raygui. That's because I don't know how I would make the Unit cards with raygui. The rectangle around it doesn't use the raygui theme, because the `GuiDrawRectangle` function that raygui uses is private. While in some ways it's more appealing than the custom GUI system I have, it still isn't capable enough that I've decided to ditch my custom GUI system. Trying to load in a style from RayGuiStyler resulted in the buttons being invisible, so I used a different method to make and load a style. Perhaps it would be nice to have a GUI system that uses SVG or HTML to make things customizable. I don't know if such a library exists. I've thought about trying to make something like that with SVG, but only after getting more experience with programming in D. Of course, it may be hard to not make it very heavyweight.
 No, I think you are in pretty good shape! I don't know much 
 about signals and slots, so I'll leave that unanswered.

 -Steve
Thank you. Making the enemy AI is difficult, but overall things aren't going too badly. This is still a very amateur project by someone who has never made a GUI application from the main function up, so there may be some amateur design decisions that haven't been pointed out to me.
Mar 21
prev sibling parent reply harakim <harakim gmail.com> writes:
I am not an expert but I would second the tick system. That is 
pretty solid advice. Just iterate through your events or, in your 
case, units and such objects and update them all. Then draw. Then 
go to the next tick.

You should engineer the system in a way that makes sense to you. 
The currency of finishing programs is motivation and that comes 
from success and believing you will succeed. If you're 
implementing XYZ pattern from someone else, if you don't get it 
then you will get unmotivated. I have seen some pretty horrible 
programs make it to all the way done and have almost never seen 
someone's first run at a problem be both pretty and get finished. 
Don't beat yourself up about keeping it clean. If you feel like 
it or it's getting out of control where you can't understand it, 
then you should go look for a solution. The motivation is in 
moving forward, though. This is probably the piece of advice I 
wish I had in the beginning! You can always refactor later when 
it's done.

Solicited advice:
* Move to the tick system. You make a loop and update each object 
based on the time that has passed. If your tick is 1/60th of a 
second then you make a loop. In the loop, you update the map 
state knowing 1/60th of a second has passed. Then you update all 
the items and move them or deplete them or whatever however much 
would happen in 1/60th of a second. Then you update all of the 
units. Then you can update the factions or check win conditions. 
At the end of the loop, you draw everything. (maybe raylib just 
draws whenever it wants, which is fine) In order to know what to 
update, you will have to save what action they are doing. ex. an 
arrow is flying toward a target. you will need to keep track of 
what it is doing so when you iterate, you can continue that train 
of thought. This will require a bit of a rewrite but I have 
worked on a game server that was used by thousands of people for 
years and it was based on this simple system. It scales really 
well and is pretty easy to understand.

Unsolicited advice:
* Your verifyEverything method is awesome. I call that strategy 
fail-fast. It means you fail right away when you have a chance to 
identify what went wrong.

* Construct the unit and then call map.setOccupant(unit) after 
the unit is constructed. I would not do anything complicated in a 
constructor. It's also generally frowned upon to pass a reference 
to an object to anything before the constructor completes. Most 
of the changes I mention are things to think about, but this 
specifically is something you ought to change. I would also 
remove the unit from the map and then delete the unit rather than 
removing the unit from within the map class.
unit.d:44 map.getTile(xlocation, ylocation).setOccupant(this);

* Another reason I would switch that line is that it's best to 
avoid circular dependencies where you can. It will make it hard 
to reason about either in isolation. It relates to that line 
because your map has units in it and your unit takes Map in the 
constructor. That is a red flag that you are too coupled. That 
concept is not a rule but just something to think about when you 
get stuck. This comment points to a symptom of the circular 
dependency: //Always set `destroy` to false when calling from the 
Unit destructor, to avoid an infinite loop.

* In your game loop, I would keep track of the units separately 
from the map, if you can. Go through the map and do updates and 
go through the units and update each one. If the logic is too 
tied together, don't worry about it for now.

* I would break the json loading into separate classes (eg 
FactionLoader, Unit loader) instead of being included in the map 
and unit class. I like to have code to intialize my programs 
separate so I don't have to look at it or think about it or worry 
about breaking it when working on my main code.

* You said
//Change this later so that the faction with the first turn is 
determined by the map file.
Comments like that are perfect. Jot down all your ideas while 
you're working on the main functionality. Once you have something 
working, tweaking it will be so much fun. Take side quests when 
you want to stay motivated, but I would stray away from the 
bigger ones until you have the basic functionality working. It's 
often the fastest way to get the side quest done anyway since you 
can test it.

* You should probably not do this, but it might give you some 
ideas for later. What I would do is make a separate thread for 
managing the UI state and push events to that thread through the 
mailbox. I have done this once (on my third version of a program) 
and it was by far the cleanest and something I was proud of. The 
benefit is you can publish those same events to a log and if 
something in your UI goes wrong, you can look at the log.

Better than that is the ability to replay your log. Instead of 
sending the events from a game engine, you have a module that 
just reads from the file and sends the events. Then you can debug 
where it went awry. And you can have a feature for players to do 
that to rewatch their game. You can also replace your game engine 
with a module that reads from the network for a multi-player game 
and it uses the exact same UI logic. In that case, you can save 
the network traffic in a log the same way to replay to diagnose 
network packet processing errors.

That method does not require any synchronization or any thread 
complexity because the communications are one way. However, you 
will not need it so I would put thinking about this and doing it 
on the list after everything that is motivating for you.
Mar 22
next sibling parent reply Liam McGillivray <yoshi.pit.link.mario gmail.com> writes:
On Saturday, 23 March 2024 at 04:32:29 UTC, harakim wrote:
 You should engineer the system in a way that makes sense to 
 you. The currency of finishing programs is motivation and that 
 comes from success and believing you will succeed. If you're 
 implementing XYZ pattern from someone else, if you don't get it 
 then you will get unmotivated. I have seen some pretty horrible 
 programs make it to all the way done and have almost never seen 
 someone's first run at a problem be both pretty and get 
 finished. Don't beat yourself up about keeping it clean. If you 
 feel like it or it's getting out of control where you can't 
 understand it, then you should go look for a solution. The 
 motivation is in moving forward, though. This is probably the 
 piece of advice I wish I had in the beginning! You can always 
 refactor later when it's done.
Alright. I suppose this is largely what I'm doing. Thank you very much for looking through my code and making the effort to understand it. So far you are the first person to comment on my code, beyond the little excerpts I've pasted directly onto this forum.
 Move to the tick system. You make a loop and update each object 
 based on the time that has passed. If your tick is 1/60th of a 
 second then you make a loop. In the loop, you update the map 
 state knowing 1/60th of a second has passed. Then you update 
 all the items and move them or deplete them or whatever however 
 much would happen in 1/60th of a second. Then you update all of 
 the units. Then you can update the factions or check win 
 conditions. At the end of the loop, you draw everything.
When you said "tick system", I thought you meant that it would be asynchronous to the framerate, but then you say "At the end of the loop, you draw everything". Right now the function that moves units across the screen moves them each frame a distance proportional to the duration of the previous frame. I was thinking that a tick system would go hand-in-hand with making animations happen in a separate thread, but it sounds like you're talking about the same thread. Are you suggesting a fixed framerate? Because this is a turn-based game, I don't need to update the factions and win conditions every frame, but at most every time a unit makes a move or when a new turn starts.
 Your verifyEverything method is awesome. I call that strategy 
 fail-fast. It means you fail right away when you have a chance 
 to identify what went wrong.
That's nice. I thought it might be an amateurish solution to something that better programmers would do differently, similar to how I use `writeln` to print variables for debugging. It looks like I don't yet have any calls to this function, so perhaps I should add one under the debug configuration.
 Construct the unit and then call map.setOccupant(unit) after 
 the unit is constructed. I would not do anything complicated in 
 a constructor. It's also generally frowned upon to pass a 
 reference to an object to anything before the constructor 
 completes. Most of the changes I mention are things to think 
 about, but this specifically is something you ought to change.
I didn't immediately understand what you were saying, but then I looked at what line `unit.d:44` was at the time you wrote this. ``` map.getTile(xlocation, ylocation).setOccupant(this); ``` This is during the Unit's constructor, where it gives the `Tile` object a reference to itself. What exactly is wrong with this? Can memory addresses change when a constructor completes? I assumed that objects come into existence at the beginning of the constructor function. Anyway, I can change this by calling `Unit.setLocation` after creating a new `Unit` object. That's unless if there's a particular reason why you think I should make this a function of the `Map` object. I suppose the current system for setting up objects from a `JSONValue` is messy because much of the data applies to the base `Tile` & `Unit` objects, but then some of it needs to be in `VisibleTile` & `VisibleUnit` because it has sprite information.
 I would also remove the unit from the map and then delete the 
 unit rather than removing the unit from within the map class.
Sure. I'll change that. Even when I wrote the Unit destructor I was thinking that perhaps this was a bad way to implement this. I suppose I should just call the `Map.deleteUnit` whenever a unit should be deleted, right? I was also thinking of replacing `Map.deleteUnit` with a function that removes all null references from `this.allUnits` which can be called after destroying a unit, but unless if I need to hyper-optimize, that probably won't be any better than the function I have.
 Another reason I would switch that line is that it's best to 
 avoid circular dependencies where you can. It will make it hard 
 to reason about either in isolation. It relates to that line 
 because your map has units in it and your unit takes Map in the 
 constructor. That is a red flag that you are too coupled. That 
 concept is not a rule but just something to think about when 
 you get stuck.
I don't quite understand. Are you saying that I shouldn't have objects reference each-other, like how a `Unit` object has a reference to a `Tile` object called `currentTile`, and that tile object has a reference back to the unit called `occupant`? I see how bugs may happen if there's ever a case where the references aren't mutual, which is the reason for the `verifyEverything` function that you praised. But I imagine things getting more complicated if I can't determine a unit's current tile just by looking at a reference in it. Do you really think it would be better if I removed `Unit.currentTile`, and just used `Unit.xlocation` & `Unit.ylocation` as parameters for `Map.getTile` instead?
 In your game loop, I would keep track of the units separately 
 from the map, if you can. Go through the map and do updates and 
 go through the units and update each one. If the logic is too 
 tied together, don't worry about it for now.
I'm not sure what you mean by "keep track of the units separately from the map". Do you mean to not rely on the `Map.allUnits` array? I have considered doing a rewrite of the rendering system, in which all the rendering, and possibly input during game are handled by a new `Renderer` object, which may have it's own array with all the units in it.
 I would break the json loading into separate classes (eg 
 FactionLoader, Unit loader) instead of being included in the 
 map and unit class. I like to have code to intialize my 
 programs separate so I don't have to look at it or think about 
 it or worry about breaking it when working on my main code.
Is this a matter of not having all that JSON-related code cluttering the top of the file? Does putting too much of it in the objects themselves make them take up more memory? Or does it really make bugs less likely? Before going with the current approach, I intended to have a module called `loadData` which would read JSON files and make objects out of them, but then I figured it was easier to have the JSON data read directly in object constructors so that private and protected variables can be set. I've thought about going back to this approach, but I haven't because I couldn't think of a reason to. If I do, perhaps they should be placed in the same modules as the objects being constructed, instead of being placed together in the `loadData` module.
 Take side quests when you want to stay motivated, but I would
 stray away from the bigger ones until you have the basic 
 functionality working. It's often the fastest way to get the
 side quest done anyway since you can test it.
Yep. At this very moment I have two feature branches on my local copy. I'll have to figure out how to merge them when complete, but I did this for motivation-management, so that I don't need to finish one feature when I feel like working on another.
 You should probably not do this, but it might give you some 
 ideas for later. What I would do is make a separate thread for 
 managing the UI state and push events to that thread through 
 the mailbox. I have done this once (on my third version of a 
 program) and it was by far the cleanest and something I was 
 proud of. The benefit is you can publish those same events to a 
 log and if something in your UI goes wrong, you can look at the 
 log.
This sounds a little like my idea of the `Renderer` object, in which the state of what's on screen would be updated by calling it's methods, but having a log of the UI wasn't what I had in mind. That being said, I've thought about the possibility of having a log of events that can be used to rewind, replay, or possibly save the game. I agree that this should be further down the line. Even the ability to save a game is not very high on the priority list now. I wasn't thinking of logging *every* UI event though.
 your game engine
Thank you for implying that I wrote a "game engine". That sounds like an accomplishment on my part. I'm not really sure which parts of my code would be referred to as the "engine" though.
Mar 23
parent harakim <harakim gmail.com> writes:
On Saturday, 23 March 2024 at 22:37:06 UTC, Liam McGillivray 
wrote:
 ...a tick system would go hand-in-hand with making animations 
 happen in a separate thread, but it sounds like you're talking 
 about the same thread. Are you suggesting a fixed framerate?
I have done both ways. If you're new to programming, I think the single thread would be better since your game logic is fairly simple. Simply update your world, then draw everything then sleep. Steven Schveighoffer does a lot of entry-level games so hopefully he will respond if he disagrees. You can have a bool flag you set when an action happens that requires the win condition to be checked and then if that flag is set, check the win condition at the end of the loop, assuming only one player can achieve a win condition at a time.
 This is during the Unit's constructor, where it gives the 
 `Tile` object a reference to itself. What exactly is wrong with 
 this? Can memory addresses change when a constructor completes? 
 I assumed that objects come into existence at the beginning of 
 the constructor function.
I think the idea is the object is not ready to use until the constructor is complete and if you leak a reference, someone else who doesn't know could use it and they might have expectations about it's state that are not upheld midway through the constructor. I used to do this a lot and never had a problem with it. In an application where you're the only developer and it's single threaded, it won't be a problem. It's just bad practice because on a team you want to be able to trust that a reference to an object is of a completely constructed object and you don't want to have to check it's constructor every time.
 Anyway, I can change this by calling `Unit.setLocation` after 
 creating a new `Unit` object.
That's a good plan
 I suppose the current system for setting up objects from a 
 `JSONValue` is messy because much of the data applies to the 
 base `Tile` & `Unit` objects, but then some of it needs to be 
 in `VisibleTile` & `VisibleUnit` because it has sprite 
 information.
That's fine. I would move the code out because I only care about it when I'm working on loading from JSON, so it wouldn't be helpful to see it all the time when I'm working on game logic. The value comes in having less to see and think about at a time but it will work just the same (assuming you don't break it when you move it :). If you like it there, then leave it.
 Do you really think it would be better if I removed 
 `Unit.currentTile`, and just used `Unit.xlocation` & 
 `Unit.ylocation` as parameters for `Map.getTile` instead?
Go with your gut. If you start having problems with them getting out of sync, then I would separate them. Most of my suggestions boil down to: if you have problems and the fix breaks something else and that fix breaks something else or it's just hard to understand, then my suggestion will probably help. If it ain't broke, don't fix it.
 I have considered doing a rewrite of the rendering system, in 
 which all the rendering, and possibly input during game are 
 handled by a new `Renderer` object, which may have it's own 
 array with all the units in it.
 This sounds a little like my idea of the `Renderer` object, in 
 which the state of what's on screen would be updated by calling 
 it's methods, but having a log of the UI wasn't what I had in 
 mind.
I like the renderer idea. I would keep it in the same thread for now unless you really want to make a separate thread.
 Before going with the current approach, I intended to have a 
 module called `loadData` which would read JSON files and make 
 objects out of them
I think you made the right call. A generic json file loader is overkill at this point. If you make a second game, make a generic and reusable json loader. I try to never make things generic unless I have multiple actually use cases that I can design against or if it's pretty obvious.
 //Always set destroy to false when calling from the Unit 
 destructor, to avoid an infinite > loop.
 I was just doing some work on the AI system, and I had a 
 segfault every time the enemy was in reach to attack a unit. It 
 turns out this was because the destructor was called. I 
 replaced destroy(unit) with map.deleteUnit(unit), and it solved 
 the problem.
 Nevermind. It turns out this was because the call to the Unit 
 destructor was missing in Map.deleteUnit. The segfault happens 
 whenever a unit is destroyed.
This is exactly the kind of problem circular references cause. You're not quite sure what makes the bug or when to consider it done, especially when there's multiple entry points into the cycle.
 In this case, how should I handle safe destruction of units, 
 given that there are multiple arrays that contain references to 
 it?
Here are my options, in inverse preference order (neglecting the time it would take): 1. Keep it like you have it 2. Switch to the tick system. At the end of your updating the world phase, clean up and for each unit that has alive = false, remove it from all the things. 3. Move the combat logic out of the unit and either have receiveDamage return whether they are still alive or check their hitpoints after each attack. If they are dead, then clean them up there instead of in the unit. Make the change I suggested to set the occupant of the tile outside of the constructor. Do not save the faction on the unit.
 It just occurred to me that this must be what you were 
 suggesting here.
That's very similar to what I was suggesting. All you would have to do is track which tick you processed the event. When you add random numbers, you'd want to use a deterministic random number generator and save your seed. It's a great idea.
Mar 25
prev sibling next sibling parent reply Liam McGillivray <yoshi.pit.link.mario gmail.com> writes:
On Saturday, 23 March 2024 at 04:32:29 UTC, harakim wrote:
This comment points to a symptom of the circular
 dependency: //Always set `destroy` to false when calling from 
 the Unit destructor, to avoid an infinite loop.
I was just doing some work on the AI system, and I had a segfault every time the enemy was in reach to attack a unit. It turns out this was because the destructor was called. I replaced `destroy(unit)` with `map.deleteUnit(unit)`, and it solved the problem.
Mar 23
parent Liam McGillivray <yoshi.pit.link.mario gmail.com> writes:
On Saturday, 23 March 2024 at 23:59:18 UTC, Liam McGillivray 
wrote:
 I replaced `destroy(unit)` with `map.deleteUnit(unit)`, and it 
 solved the problem.
Nevermind. It turns out this was because the call to the Unit destructor was missing in `Map.deleteUnit`. The segfault happens whenever a unit is destroyed. In this case, how should I handle safe destruction of units, given that there are multiple arrays that contain references to it? - Just call the unit destructor directly. The unit destructor will call functions in `Map` & `Faction` to delist the unit from it's arrays. - Call a function in `Map` which will delist the unit from `allUnits`, call a function in it's faction to delist it, and then call the unit's destructor. - Just call the units destructor, which will be rather plain. `Map` & `Faction` will have functions that frequently go over it's list of units, and delete any null references found.
Mar 23
prev sibling parent Liam McGillivray <yoshi.pit.link.mario gmail.com> writes:
On Saturday, 23 March 2024 at 04:32:29 UTC, harakim wrote:
 * You should probably not do this, but it might give you some 
 ideas for later. What I would do is make a separate thread for 
 managing the UI state and push events to that thread through 
 the mailbox. I have done this once (on my third version of a 
 program) and it was by far the cleanest and something I was 
 proud of. The benefit is you can publish those same events to a 
 log and if something in your UI goes wrong, you can look at the 
 log.
I was thinking about how I can have one thread doing the rendering and another doing everything else, given that the "everything else" thread would be idle most of the time. I thought about giving the "everything else" thread a queue; an array of functions that it's tasked with going over. Every UI interaction would add one to the queue. It just occurred to me that this must be what you were suggesting here.
Mar 24