Introducing the Enhanced Attack System in 2D RPG Accelerator Project

Introducing the Enhanced Attack System in 2D RPG Accelerator Project

Hello fellow developers and RPG enthusiasts!

I'm thrilled to announce a major update to the 2D RPG Project Accelerator available on the Unity Asset Store. As an indie game developer myself, I've been hard at work refining and expanding the features of this package to make it even more powerful and user-friendly for creators like you.

Today, I'm excited to unveil the newly implemented Attack System, which brings a new level of depth and flexibility to your game's combat mechanics. This update not only enhances gameplay but also showcases robust coding practices and architectural improvements that you can leverage in your own projects.

What's New in the Attack System?

1. Unified Damage Calculation Function

We've merged multiple damage calculation functions into a single, versatile method that handles both humanoid and non-humanoid characters seamlessly.

  • Polymorphic Design: By utilizing inheritance and polymorphism, the CalculateDamage function now accepts a BaseMobile parameter, allowing all mobile entities to calculate damage appropriately based on their specific attributes.

      public static class DamageHelper
      {
              // Calculate the final damage dealt by the mobile to a target
              public static int CalculateDamage(BaseMobile mobile, ICombatant target)
              {
                  var stats = mobile.Stats;
    
                  // Calculate base bare hands damage based on Strength
                  float bareHandsDamage = stats.Strength * 0.5f;  // Bare hands damage scales with Strength
    
                  // Initialize baseDamage with bare hands damage
                  float baseDamage = bareHandsDamage;
    
                  // Check if the mobile is a humanoid with equipment
                  if (mobile is BaseHumanoid humanoid)
                  {
                      var equipment = humanoid.Equipment;
    
                      // Get the equipped weapon (if any)
                      var weapon = equipment.GetEquippedItem(EquipmentType.MainHand) as BaseWeapon;
    
                      if (weapon != null)
                      {
                          // Weapon damage: base weapon damage + some scaling with Strength
                          baseDamage = weapon.Damage + (stats.Strength * 0.3f);  // Weapons get a moderate bonus from Strength
                      }
                      else
                      {
                          // Bare hands damage: scales more directly with Strength
                          baseDamage = bareHandsDamage;
                      }
                  }
    
                  // Add randomness to the damage (±10% of the base damage)
                  float randomFactor = UnityEngine.Random.Range(0.9f, 1.1f);  // Random variation between 90% and 110%
                  float resultedDamage = baseDamage * randomFactor;
    
                  // Ensure there's at least 1 damage dealt
                  int finalDamage = Mathf.CeilToInt(Mathf.Max(resultedDamage, 1));
    
                  // Return the final damage
                  return finalDamage;
              }
      }
    

    Humanoid-Specific Logic: Within the same function, we check if the mobile is a BaseHumanoid to apply weapon-based damage calculations.

  •   if (mobile is BaseHumanoid humanoid)
      {
          // Humanoid-specific damage calculation, including weapon stats
      }
    

    Benefits: This approach reduces code duplication, enhances maintainability, and makes it easier to extend functionality in the future.

2. Flexible Attack Speed Mechanics

We've overhauled how attack speed is calculated to make it more dynamic and responsive to character stats.

  • Attribute-Based Modifiers: Attack speed now considers Dexterity and Stamina, affecting how quickly a character can perform attacks.

      public static float GetFinalAttackSpeed(BaseMobile mobile)
              {
                  float dexterityMultiplier = GetDexterityMultiplier(mobile);
                  float staminaMultiplier = GetStaminaMultiplier(mobile);
    
                  // Set a minimum base speed so that the attack is never too slow
                  float baseAttackSpeed = 1.5f;
    
                  // Initialize final attack speed calculation
                  float finalAttackSpeed = baseAttackSpeed * dexterityMultiplier * staminaMultiplier;
    
                  // Check if the mobile is a humanoid to apply weapon attack speed modifier
                  if (mobile is BaseHumanoid humanoid)
                  {
                      float weaponAttackSpeedModifier = GetWeaponAttackSpeedModifier(humanoid);
                      finalAttackSpeed *= weaponAttackSpeedModifier;
                  }
    
                  // Clamp the final speed between 0.5x and 3.0x
                  return Mathf.Clamp(finalAttackSpeed, 0.5f, 3f);
              }
    

    Extensible Design: The system is designed to accommodate additional character types and modifiers with minimal changes.

3. Refactored Mobile Behaviour Classes

To better support diverse character types, we've refactored the MobileBehaviour and HumanoidBehaviour classes.

  • Generic MobileBehaviour: The MobileBehaviour class now works with a general BaseMobile type instead of being tied to BaseHumanoid.

      public class MobileBehaviour : MonoBehaviour
      {
          protected BaseMobile mobile;
          // ...
      }
    

    Humanoid-Specific Behaviour: HumanoidBehaviour inherits from MobileBehaviour and uses casting to access humanoid-specific properties.

      public class HumanoidBehaviour : MobileBehaviour
      {
          public BaseHumanoid Humanoid => (BaseHumanoid)mobile;
          // ...
      }
    

    Technical Challenges Overcome:

    • Unity's Generic Limitations: Unity doesn't support GetComponent with generic types, so we've carefully designed the classes to work within these constraints.

    • Type Safety: By using casting and property overrides, we maintain type safety while ensuring the code remains clean and understandable.

4. Lootable Enemies with Shared Inventory System

All mobile entities now have inventories, making it possible to loot any defeated enemy.

  • Inventory Integration: Moved inventory management from HumanoidBehaviour to MobileBehaviour, allowing all mobiles to carry items.

      [RequireComponent(typeof(InventoryBehaviour))]
      public class MobileBehaviour : MonoBehaviour
      {
          protected InventoryBehaviour inventoryBehaviour;
          // ...
      }
    

Why These Changes Matter

For Developers:

  • Cleaner Architecture: The refactoring leads to a more organized codebase that's easier to navigate and extend.

  • Reusability: By generalizing mobile behaviors, you can add new character types without rewriting common logic.

  • Performance Optimizations: Efficient use of inheritance and method merging reduces overhead and potential bugs.

For Players:

  • Enhanced Gameplay Experience: Players can now enjoy more realistic combat mechanics and the satisfaction of looting any enemy they defeat.

  • Strategic Depth: The impact of character stats on combat introduces new layers of strategy and customization.

Technical Insights

Overcoming Unity's Component Limitations

Unity doesn't fully support generics in components that need to be serialized or accessed via GetComponent. To address this:

  • Avoided Generics in Components: Kept MobileBehaviour non-generic and used casting in HumanoidBehaviour to access specific properties.

  • Property Shadowing: Used the new keyword to shadow the Mobile property in HumanoidBehaviour, allowing access to BaseHumanoid without altering the base class.

Efficient Use of Polymorphism

  • Single Responsibility Principle: Each class has a clear purpose—MobileBehaviour handles general mobile logic, while HumanoidBehaviour manages humanoid-specific features.

  • Extensibility: This structure makes it straightforward to introduce new mobile types like animals or monsters by creating new subclasses of MobileBehaviour.

Refined Damage and Attack Speed Calculations

  • Unified Functions: Merged separate functions for humanoids and other mobiles to reduce redundancy.

  • Dynamic Calculations: Stats and equipment now dynamically affect combat outcomes, making the system more flexible and realistic.

What's Next for the Package?

We're committed to continuously improving the 2D RPG Project Accelerator. Upcoming features include:

  • Expanded Item System: Introduction of off-hand items (shields), two-handed weapons, and crafting mechanics.

  • Enhanced AI: Smarter enemy behaviors and more engaging combat scenarios.

  • Skill Systems: Allowing characters to learn and use unique abilities, further deepening gameplay.

Get the Updated Package Today!

If you're looking to accelerate your game development with a robust, flexible, and well-architected system, this update is for you.

  • New Buyers: Purchase the 2D RPG Project Accelerator on the Unity Asset Store and get access to all these features and future updates.

  • Existing Customers: Simply download the latest version to enjoy the new attack system and improvements.

Visit the Unity Asset Store to get started!

Your Feedback Matters

As an indie developer, I value your input immensely. If you have suggestions, encounter issues, or want to share how you're using the package in your projects, please don't hesitate to reach out.

Let's build amazing games together!

Keep rocking!
Deniz