Maybe I am thinking about this the wrong way, but is this the best approach to reach my goal?

Hi all,

I am new here, but not all that new to game creation and object oriented and event driven programming. I am a hobbyist without much depth of understanding with the Unity engine as of yet.

I am creating an 8-bit style turn-based RPG of sorts targeting mobile devices and I have decided to start in unity with my battle engine state machine.
The concept behind the battle animations and state transitions is SUPER simplistic, but may be challenging to explain. With image editing software, I have pre-created all the animations frame-by-frame for each interaction/outcome in battle between each enemy and the player(excessive I know). The animations are complete and contain the player, enemy, and, effects. Player and enemy return to their ‘ready stance’ at the end of each interaction, which is just a short (2 frame) animation of the player and enemy in the ready stance. I have also created sound files that sync with each animation. I built a state machine in animator on the base layer of a game object that I have named ready stance, that has an animator, sprite renderer, and script which allows me to transition to a state based on a key-press (for testing basically) but will ultimately be used as the battle engine. Each possible interaction in battle is represented as its own state in the state machine, which I tie in the animation and sound script behaviors for the given interaction. Each state has a transition to and from the default ‘Ready Stance’ state. This all looks and sounds smooth just the way I was imagining it.
First Q: does anyone see any more simplistic way to create my battle engine? If more clarifying information is needed don’t hesitate to ask

Before I started researching into unity, I created a simple form in Visual basic that is essentially my Player and Enemy statistics calculator, and a battle simulator program. The form relies on user to first input the player and enemy level, and strength, speed, and insight stats. Using this input, the battle outcomes such as chance to hit, critical chance, attack damage, block, health, energy etc are calculated, and a simulated battle can take place between the player and enemy by selecting the attacks for the player and enemy one at a time. It’s simplistic but has helped me to fine tune my calculations and make battles interesting. My next hurdle is going to be creating a similar form in unity to define the variables and pass them to the battle script, the problem is I am not quite sure what I need to do next.
Second Q: Given that I have already established the calculations necessary for defining all of my variables, what would be the most efficient way to input them into my project? Do I need to have a single script that manages these variables and then use getcomponent to pull them into the battle script? Can I define these all within a single script? Any insight here would be appreciated, and as always feel free to ask any clarifying questions.

The long term goal of this project is that there will be a map which can be explored with points of interest and the player will find themselves in plenty of battles along the way. Players will level up as they progress through the map and win battles, find items, and power up their character.

Respectfully,

-T

For the first thing, it seems like a good angle as long as you’re planning on breaking up those animations before you start on the “real” engine.

For the second thing, maybe you could write a class with methods for running battle-related calculations, and instantiate one as a “battle controller” object or something. You could have it wait for input, get stats from the interacting parties, then calculate and apply damage, etc. It would probably also be responsible for loading/unloading battle scenes and distributing loot.

1 Like

Thanks for the reply Hyblademin,
I started converting my C++ calculation program logic over to C# and I’m 99% sure that I am making this terribly over-complicated after reading your message. You will have to bear with me as my understanding is pretty basic still and I know I am missing a few key concepts.
What I have done so far is create a battle script which generates a few buttons for attacks using OnGUI. I am also calling in my player and enemy stat values from their respective objects.
When a button is clicked, a series of potential outcomes are configured based on several randomly generated numbers between 1 - 100.

int ROLL { get { return Random.Range(1, 101); } }
int CRIT { get { return Random.Range(1, 101); } }

Once the attack is selected I use the random value in the manor below

if (GUI.Button(new Rect(Screen.width / 2 - 200, Screen.height / 2 + 120, 150, 20), "Attack")) 
            {
            
                    if (ROLL <= ES.ECTD)  //Roll is less than the enemies chance to dodge - enemy dodges
                    {


                        if (CRIT <= ES.ECC)  // Roll a new random number to determine if enemy gets a critical? if random # is less than or equal to the enemies 'critical chance' 
                        {

                            anim.SetTrigger(M1CC); //play the critical couter attack animation

                            if (ES.EM1DMG - PS.BLOCK <= 0)  //check for negative value against the block amount, if block amount would add life instead of take it away, cause one dmg instead
                            {
                                PS.hp_now -= 1;
                            }
                            else
                            {
                                PS.hp_now -= ES.EM1DMG - PS.BLOCK;  // player takes normal counter attack damage 
                            }

                        else
                        {
                            anim.SetTrigger(M1DO);  //play the normal dodge animation
                        }
                    }

At this point I first want to check if the random number that was generated is less than or equal to the enemies chance to dodge. If so, there is a second condition we need to check for that is weather or not the enemy has rolled a critical for this defense. I am not sure if I need to use a second randomly generated number here, or if each time I write an IF statement containing the ROLL variable a new integer is chosen, any clarification there?
Now I check for the next condition

if (ROLL > ES.ECTD & (ROLL <= ES.ECTD * 2))  // rolled glancing blow 
                    {
                        anim.SetTrigger(M1GL);  // play the glancing blow animation

                        if ((PS.M1DMG / 2) - ES.EBLOCK <= 0) //checking for negative value
                        {
                            ES.ehp_now -= 1;
                        }
                        else
                        {
                            ES.ehp_now -= (PS.M1DMG / 2) - ES.EBLOCK; // 1/2 normal melee dmg for glance
                        }
                    }

While writing this, I researched some other methods of generating a random integer that seems to work much better than the one I presented here. Now, on button press I generate my first random integer, and call a new variable for the secondary/tertiary critical rolls.

 int ROLL = Random.Range(1, 101);

Finally this all seems to be functioning as I would have expected.

If the roll is less than the dodge chance, the enemy should dodge, right? But in your script, the logic will continue toward the damage calculation. Then, if the roll is less than the critical block chance, there should be a block, but instead the logic again continues toward the damage calculation. Should you be checking for the roll to be GREATER than the chance, so that when attack DOESN’T miss it will take the next damage step? Maybe I’m wrong, but I thought I’d mention it.

Other than that, it looks good to me. The meat of what I was suggesting before was that there could be one battle manager that handles all of the calculations and battle actions. The manager would have references to all of the participants to get their stats/tables when needed, and the GUI buttons would have a reference to the manager object in order to call attack methods, etc. The manager could also check to see if only one side is still standing, to either continue the game or start game over logic, or whatever is relevant.

Whether you do it this way is your call, I just think it would be a good way to organize it. It will give you more flexibility in your game design and simplify implementation of new battles.

Just to clarify on the code function above, if the roll is less than the dodge chance, the enemy will either dodge, or counter attack. The counter attack is decided based on the second random roll, and if its less than the critical chance, then we play the critical counter attack animation and deal damage to the player. else, we just play the dodge animation and do not effect stats in any way.