Post by dslyecix on Sept 28, 2018 18:11:24 GMT
Hi there,
As I work on my current project I will try my best at not taking every issue to this forum, but I'm hoping that I might be able to get a few thoughts on the following and how it might be integrated into the tutorial project. When I reach a more thorough prototype I plan to release what I've got for others to learn from and compare to the original, but I'm not quite there yet.
What I've been working on so far, is taking the "next unit in line" turn style from the tutorial, and making it alternate between "players" instead. Loosely like a chess game, two (eventually perhaps more) players will be in charge of moving whichever of their units they fancy on a turn. More than one unit might take more than one action up to a predefined number of actions - per unit and per player. After one player has exhausted all of their potential moves, control of the 'round' switches to the other player, who may then move any of their units who still have allotted actions remaining.
This has gone quite well. I converted the Round Controller into a sort of "player turn" manager (still calling them Rounds). The Turn Controller still controls the 'unit presently being controlled', until their actions are done, upon which action costs are subtracted from the stat and the player gets to choose a new unit to continue acting with. I have separate Player Manager and Unit Manager classes controlling the creation/instantiation of the required players and units. The excellent Notification system has made all of this relatively trivial, connecting things intuitively and easily.
My issue now, is that I'd like for players to be able to "undo" (and I guess redo) actions they've given units. We started with a *sort* of undo; with the 'hasMoved' bool tracking whether or not a unit has already moved during it's turn, and similarly with the 'hasActed' or whatever it was called, we could undo the movement action taken during a single 'turn' (and only if the unit hadn't already used an action after moving). Remember, 'turn' in this case being "while the current unit is acting" - the turn ends after we choose a facing direction, but control is still given to the same player, and they might select the same unit to take 'another turn' if it hasn't exhausted it's potential action points. This is somewhat convoluted, but has been how I adapted the existing system to bend to my new rules. It is possible it needs to be completely rewritten and I'm not against that.
My first thought was to create a TurnData class, and when a 'new' unit takes a turn, we simply attempt to store the changes in board state in this TurnData object. If we select a unit, we check to see if it already has a TurnData entry ascribed to it, and if it does we know there are potential things to undo already. If it does not we create one and add it to the tracker. Although it might be awkward, I'm currently using a dictionary of <Unit, List<TurnData>> type. As units might rack up a small number of turns in a round, I would tie them to the Unit with the dictionary, but then iterate through however many there are in the list. Ignoring that this might be a strange or improper use of dictionaries.....
This has got me wondering about the Command pattern, the 'usual' way of storing actions and being able to undo them. However, given the architecture of the tutorial so far, I do not see HOW to integrate this concept. The units themselves are not controlled from a singular entity; the various states, as required, only use the "turn controller's current unit" as the way of specifying who we are interacting with. It feels like I'd be trying to create command objects and passing them to half a dozen different places in order to execute the effects. I also can't quite grapple with how a command would possibly tie together all of our various aspects of using Abilities. The actual Command (that would be undone) is really only the final result of the chain of states/classes - we don't want to undo the various Confirm/Cancel methods, but we might undo a whole slew of states' actions that resulted in a knockback ability moving an enemy and changing their health and applying a burn effect. So the PerformAbilityCommand would at least need to somehow track all of that and be able to undo it...
In order to have a stack of commands to do/undo, they have to be kept in some central spot. Should this perhaps be a separate kind of manager - a Unit Action Controller or something similar? One that basically accepts UnitCommand objects, which can be broken up into say UnitMoveCommands and UnitAbilityCommands, or something? Have the various battlestates feed their desired outputs into creating a command, passing it to this manager, and having IT actually control the execution, and undo/redo? This is the first time writing anything out has made a lick of sense, so perhaps this is an okay place to start with the idea... Seriously at this point anything to point me in *A* direction would be quite helpful
I realize this is getting far beyond the original scope of the project, and fully appreciate if we're past the statute of wanting to assist anymore. This is just the only place where people who might be privy to how this tutorial operates could possibly weigh in and assist me.
Thanks again for all you did for us by creating this tutorial. It is single-handedly the thing that has kicked me in the ass and ignited my passion for programming.
As I work on my current project I will try my best at not taking every issue to this forum, but I'm hoping that I might be able to get a few thoughts on the following and how it might be integrated into the tutorial project. When I reach a more thorough prototype I plan to release what I've got for others to learn from and compare to the original, but I'm not quite there yet.
What I've been working on so far, is taking the "next unit in line" turn style from the tutorial, and making it alternate between "players" instead. Loosely like a chess game, two (eventually perhaps more) players will be in charge of moving whichever of their units they fancy on a turn. More than one unit might take more than one action up to a predefined number of actions - per unit and per player. After one player has exhausted all of their potential moves, control of the 'round' switches to the other player, who may then move any of their units who still have allotted actions remaining.
This has gone quite well. I converted the Round Controller into a sort of "player turn" manager (still calling them Rounds). The Turn Controller still controls the 'unit presently being controlled', until their actions are done, upon which action costs are subtracted from the stat and the player gets to choose a new unit to continue acting with. I have separate Player Manager and Unit Manager classes controlling the creation/instantiation of the required players and units. The excellent Notification system has made all of this relatively trivial, connecting things intuitively and easily.
My issue now, is that I'd like for players to be able to "undo" (and I guess redo) actions they've given units. We started with a *sort* of undo; with the 'hasMoved' bool tracking whether or not a unit has already moved during it's turn, and similarly with the 'hasActed' or whatever it was called, we could undo the movement action taken during a single 'turn' (and only if the unit hadn't already used an action after moving). Remember, 'turn' in this case being "while the current unit is acting" - the turn ends after we choose a facing direction, but control is still given to the same player, and they might select the same unit to take 'another turn' if it hasn't exhausted it's potential action points. This is somewhat convoluted, but has been how I adapted the existing system to bend to my new rules. It is possible it needs to be completely rewritten and I'm not against that.
My first thought was to create a TurnData class, and when a 'new' unit takes a turn, we simply attempt to store the changes in board state in this TurnData object. If we select a unit, we check to see if it already has a TurnData entry ascribed to it, and if it does we know there are potential things to undo already. If it does not we create one and add it to the tracker. Although it might be awkward, I'm currently using a dictionary of <Unit, List<TurnData>> type. As units might rack up a small number of turns in a round, I would tie them to the Unit with the dictionary, but then iterate through however many there are in the list. Ignoring that this might be a strange or improper use of dictionaries.....
This has got me wondering about the Command pattern, the 'usual' way of storing actions and being able to undo them. However, given the architecture of the tutorial so far, I do not see HOW to integrate this concept. The units themselves are not controlled from a singular entity; the various states, as required, only use the "turn controller's current unit" as the way of specifying who we are interacting with. It feels like I'd be trying to create command objects and passing them to half a dozen different places in order to execute the effects. I also can't quite grapple with how a command would possibly tie together all of our various aspects of using Abilities. The actual Command (that would be undone) is really only the final result of the chain of states/classes - we don't want to undo the various Confirm/Cancel methods, but we might undo a whole slew of states' actions that resulted in a knockback ability moving an enemy and changing their health and applying a burn effect. So the PerformAbilityCommand would at least need to somehow track all of that and be able to undo it...
In order to have a stack of commands to do/undo, they have to be kept in some central spot. Should this perhaps be a separate kind of manager - a Unit Action Controller or something similar? One that basically accepts UnitCommand objects, which can be broken up into say UnitMoveCommands and UnitAbilityCommands, or something? Have the various battlestates feed their desired outputs into creating a command, passing it to this manager, and having IT actually control the execution, and undo/redo? This is the first time writing anything out has made a lick of sense, so perhaps this is an okay place to start with the idea... Seriously at this point anything to point me in *A* direction would be quite helpful
I realize this is getting far beyond the original scope of the project, and fully appreciate if we're past the statute of wanting to assist anymore. This is just the only place where people who might be privy to how this tutorial operates could possibly weigh in and assist me.
Thanks again for all you did for us by creating this tutorial. It is single-handedly the thing that has kicked me in the ass and ignited my passion for programming.