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.

Reply via email to