Showing posts with label Programming. Show all posts
Showing posts with label Programming. Show all posts

June 23, 2021

[Progress Update] Combat Prototype

Last December I made a major change to the design of Daughter of Dreams as I pivoted from real-time combat to turn-based combat. Over the last few months, I worked to develop a prototype turn-based combat system. A little bit ago, I finished the entire system and produced a version that I shared with my internal alpha-testers. This post is a wrap-up on the turn-based prototype. I will document the progress I've made so far, and share what improvements I plan to make next.

For this progress update, I created a commentated video that showcases the entire combat system. If you are not familiar with the project thus far, I recommend skimming through it a bit. It is easiest to understand how the game works when it is shown in actual gameplay.

There are a few primary systems implemented in this version:

  • Performing actions and attacks on the turn-based grid-based battlefield.
  • Damage handling, modifiable combat stats, and status effects.
  • Simple enemy AI and a few basic enemies.

There are also two characters implemented, with a full set of unique combat abilities each. There are posts covering their abilities in detail here [Sonya] [Lydia]. Their abilities are not finalized (I have major changes already planned). However, what I have so far does showcase the overall idea I have for both of their characters, and how I plan to design abilities generally.

Conclusions

This is actually the second prototype I developed, the first one being a real-time combat engine that I developed last summer. That one ended up feeling stale, and unoriginal. I wanted to do something more interesting and within my skillset, so I pivoted to turn-based combat. I talked about this in-depth in a previous blog post.

Overall, I am extremely pleased with this new system. From the alpha-testers gameplay, I saw that they were all able to quickly understand the combat system (even without a tutorial). Furthermore, I was able to develop some mechanics that I have genuinely not seen in any other games. Fire Emblem (if you only had gambit attacks) and the upcoming Project Triangle Strategy are the closest direct comparisons, but I am also drawing inspiration from Chrono Trigger, Paper Mario, and traditional JRPGs. I really believe that what I have has the foundation to be something unique and incredible. I will be moving forward with this prototype to develop the full game, and I am excited to see what I can do with this game!

Future Development

My next update will be focusing on two things. (1) Polishing the combat system, and (2) adding the inventory and equipable charms, which will be a foundational mechanic for creating custom strategies. The specific changes I have planned address each of these points:
  • The combat system needs to be more readable and provide more information to the player. I will be adding context-sensitive UI and more information about attack types and enemy weaknesses. I will also be streamlining the controls, and updating the UI.
  • I will be adding charms that can be equipped to modify a character's combat stats. Along with this, I need a way to view the current stats for each player and show how different stats will affect their abilities during combat. This mechanic is similar to charms from Hollow Knight and badges from Paper Mario and I think it's really important to encourage strategic play.
  • I will be updating the enemy AI to be more nuanced and easier to understand. Due to the complex nature of attacks, it is currently hard to tell where on the battlefield is safe or in range of enemies. I will try to simplify the design of enemies and provide some telegraphed indicators of what the enemies will try to do.
  • The current abilities are not well balanced. Sonya in particular is unable to effectively synergize with her abilities. I have plans to refactor all of the combat abilities and damage values, including some significant adjustments to the AP system. I don't think this will be very hard fortunately since the foundational mechanics are already in place.

Stray Thoughts

It has been a long while since I wrote a blog post. This alpha-version was actually finished a while ago. At one point I wanted to write once per month, but other things took priority. Now I am into summer break, however, and I believe that development for Daughter of Dreams will be pretty consistent for the next few months. Stay tuned for more updates on this project, and some of the other things I am working on!

December 08, 2020

[Programming Notes] Turn-Based Combat System

This week, I implemented the core systems of the new turn-based combat system for Daughter of Dreams. This is one of the most technically complicated pieces of code I've written, though it may not seem like it. The challenging part for me was making it as simple as it is. I believe what I have will be powerful and flexible enough to expand easily to support the entire combat system (and probably in-game cutscenes as well, though GML 2.3 sequences may still be a better option). Abilities are modular, and can be assigned to any entity (player characters and enemies), and the combat engine can transition between states fluidly, as well as undo actions.

What It Looks Like

So far, the combat prototype has two main operations. A character can be selected from any number of playable characters, and they can be given an order to move according to basic grid-based movement. These are merely the simple actions I implemented to test the system. As the game expands, I will add new actions that will be supported by the foundational code that makes up the combat system.

Two playable characters with grid-based movement.

System Overview

The combat system is currently comprised of two primary components.
- A finite state queue of functions which return true or false.
- An index of actions assigned to combat entities (playable characters and enemies).

The logic for the finite state function queue is as follows:
1) Run the current function when the update method is called. (Usually in the step event).
2) If the function returns true, progress the queue to the next function.

Next, an action is defined globally, and can be assigned by reference ID to any entity.
- The action includes all the data required to display the action on the UI.
- The action execute method can assign required values for the entities.
- The action can add functions to the combat function queue to define the logic of the action.

Class definitions shows the essential attributes and operations of each component.


System Implementation

With these components in place, the logic for starting a new combat scenario is as simple as adding each step of the combat cycle to the combat function queue. The logic of each step is handled internally, moving to the next state once that function returns true.


Each step (combat_start, combat_player, etcetera) can divert from the primary cycle by inserting more functions in the combat function queue at its own position. For example, the player phase will allow the player to choose actions for their characters. When an action is chosen, the associated functions are added to the combat function queue.


The final combat cycle can be represented with this flowchart. The primary combat cycle is the Start > Player Phase > Enemy Phase > End/Restart. Each player or enemy action diverts the primary cycle by inserting other phases into the combat function queue. Furthermore, actions could be canceled at certain steps, by instead inserting the previous phase. (For example: with Choose Attack, on "confirm" input, insert Choose Target, but on "cancel" input, insert Player Phase again).


System Pros and Cons

This method is powerful because it is easy to transition from each state to any other state, just by appending the next associated function. It handles the turn-based aspect of the combat with the simple logic of the function queue. Each state is handled in order, one at a time. Actions are modular, so they can be assigned to and used by any entity, instead of programming every ability for each entity.

The downside of this system is that at the moment, the function queue cannot accept parameters. Every function used for combat abilities must return true or false, and be designed to run every time the function queue update method is called. If additional variables are needed (such as timers, or damage values), they must be declared outside of the scope of the function. It is possible I will expand the function queue to use parameters as well, but it will complicate the system.

Additionally, while actions are modular, they also require more code this way than they would if each was more specialized. The move action as it stands uses four separate functions (initialization, player input, drawing, and execution). However I believe the flexibility outweighs this complication.

Stray Thoughts

In the future, I hope to regularly post programming notes to cover the more interesting systems that I develop for Daughter of Dreams. I am learning a lot, and I hope if I share what I've been doing that others might find it useful too. Also, if anyone knows of useful articles or posts covering similar topics, please let me know and I will include them in the resources section.

Resources