Converting the Shield into a Weapon

As crazy as the title sounds, I want to add a ‘WeaponDamage’ variable to my ShieldConfig.cs script (I created that script when I was still developing my shield back then, to make it equipable), so I can give it it’s own unique damage when my player performs any sort of parrying with the shield (i.e: he strikes the enemy with the shield). How do I do this?

Right now, the parrying deals damage depending on what the player has in his attack slot, which is not ideal at all

Anyway, here’s my ‘ShieldConfig.cs’ script:

using System.Collections.Generic;
using UnityEngine;
using GameDevTV.Inventories;
using RPG.Stats;

namespace RPG.Combat {

    [CreateAssetMenu(fileName = "Shield", menuName = "Defence/Shield", order = 0)]
    public class ShieldConfig : EquipableItem, IModifierProvider
    {
        
        [SerializeField] Shield equippedPrefab;
        [SerializeField] bool isRightHanded;
        [SerializeField] float defenseBonus = 0;
        [SerializeField] float percentageBonus = 0;

        const string shieldName = "Shield";
        
        public Shield SpawnEquipableItem(Transform rightHand, Transform leftHand) {

            DestroyOldEquipableItem(rightHand, leftHand);

            Shield shield = null;

            if (equippedPrefab != null) {

                Transform handTransform = GetTransform(rightHand, leftHand);
                shield = Instantiate(equippedPrefab, handTransform);
                shield.gameObject.name = shieldName;

            }

            return shield;

        }

        public float GetDefenseBonus() 
        {
            return defenseBonus;
        }

        public float GetPercentageBonus() 
        {
            return percentageBonus;
        }

        public Transform GetTransform(Transform rightHand, Transform leftHand) {

            Transform handTransform;
            if (isRightHanded) handTransform = rightHand;
            else handTransform = leftHand;
            return handTransform;

        }

        void DestroyOldEquipableItem(Transform rightHand, Transform leftHand) {

            Transform oldWeapon = rightHand.Find(shieldName);

            if (oldWeapon == null) {
                oldWeapon = leftHand.Find(shieldName);
            }

            if (oldWeapon == null) return;

            oldWeapon.name = "DESTROYING";
            Destroy(oldWeapon.gameObject);

        }
        

        // Added Armor to 'Stats.cs'
        public IEnumerable<float> GetAdditiveModifiers(Stat stat)
        {
            if (stat == Stat.Defence) yield return defenseBonus;
        }

        public IEnumerable<float> GetPercentageModifiers(Stat stat)
        {
            if (stat == Stat.Defence) yield return percentageBonus;
        }

        public override string GetDescription()
        {

            string result = "Protection Shield";    // definition
            result += $"\n\n{GetRawDescription()}\n";   // description of the gameObject

            if ((int) defenseBonus != 0) {  // color change of bonus, based on positive or negative
                string bonus = defenseBonus > 0 ? "<color=#8888ff>bonus</color>" : "<color=#ff8888>penalty</color>";
                
                if ((int) defenseBonus >= 0) result += $"\n{(int)defenseBonus} point {bonus} to Defence";
                else if ((int) defenseBonus < 0) result += $"\n{(int)defenseBonus * -1} point {bonus} to Defence";
            }

            if ((int) percentageBonus != 0) {
                string bonus = percentageBonus > 0 ? "<color=#8888ff>bonus</color>" : "<color=#ff8888>penalty</color>";
                
                if ((int) percentageBonus >= 0) result += $"\n{(int)percentageBonus} percentage {bonus} to Defence";
                else if ((int) percentageBonus < 0) result += $"\n{(int) percentageBonus * -1} percentage {bonus} to Defence";
            }

            result += isRightHanded ? "\nshield is right handed" : "\nshield is left handed";

            return result;

        }

    }

}

Something else that’s been troubling me, is when the player parries with the shield. I did all the required transitions in ‘Fighter.cs’ and introduced all the needed variables in ‘ShieldConfig.cs’ as shown above, but… because of the Sphere collider size and shape (I’ll post a picture whenever the backup is done, or in the morning), there’s a considerable chance that the enemy NPC and the shield will never collide, which makes more than 50% of all parry attempts at close distance a complete failure. The hits do happen from time to time, but you gotta get “The perfect angle”, and that’s not ideal for my game at all

Anyone knows how to increase this chance, or a better overall approach to this problem other than Animation Events mixed with a Physics Overlap Sphere? I’m trying all I know, but nothing is working.

SOO… I went around this problem in a very weird way. For the enemy, I left his parrying as is, an Animation Event-triggered system, since he seemed to get most of his hits right anyway

For the player, however, I took a different Approach

A while ago, me and Brian figured a way to deactivate multiple capsule colliders from registering the same hit in ‘Fighter.cs’, and I used that on all of my enemies now as well, since it exists.

So, what I did was develop two colliders, both set as triggers. One goes on the player’s Equipped Shield, and the other goes on the Enemy himself. When the player goes into the enemy’s radius, that collider interaction essentially attempts to get them to hit one another, but the sphere collider for the shield itself won’t get activated unless the ‘IsParrying’ boolean, which I setup in my Player’s InputReader.cs script, gets activated (i.e: When the player hits the Parrying key)

And when they interact, I installed my usual Attack Force and damage dealing formula in there

In the end, the player hits much more than the old approach with this new system

But is it robust? I don’t know, but I know it works well for the player, and the Animation-Event based system is no longer needed in this one

And obviously don’t forget to split your ‘Equipped Shield’ between the enemy and the player, so whatever you do to the player’s shield doesn’t necessarily translate to the enemy’s shield, but keep the fundamentals for both the same

And I also added an ‘Attack’ variable in my ‘ShieldConfig.cs’ so I can get the attack for the shield in there, so as to apply a force on the NPC

I just need to find a way to turn this from my temporary Update-function based approach to an event-based approach somehow, because leaving the activation and deactivation of these colliders risks my NPC Animal Driving System down the line

OK so, I think I got the prototype of shield parrying to work, to no one’s surprise by now. Here’s the problem, and the solution:

[Problem]
When parrying, due to the fact that shields were never a big thing in the course, I initially had to code one myself, and I carefully followed how weapons were created for that. Next, I realized that because of the shape and size of the shield, the Animation Hit event for the player was simply not cutting it. So I decided to take a different approach

[Solution]
Create a Capsule Collider on the enemy, and the shield. When they are within range (i.e: When they “Touch”), and the parrying event is triggered (you’ll need to setup your own function for that), you do whatever parrying does

As for the time, I used two cooldown token managers for that one, the one on the player, and then I gave my shield its own cooldown token manager. Both (by both, I mean the damage and the animation. They are split up now, for the shield, remember?) are linked to the same exact cooldown timer that I recently placed in my ‘ShieldConfig.cs’ script, so they both will simultaneously know when the next hit is available, so the animation and the damage itself will do their own magic individually

both of them use the same parent shield configurator for that. The player uses the PlayerStateMachine’s ShieldConfigurator to identify the shield in hand, and the shield itself has it setup as a serialized variable to attach the shield configurator on it (the same way as you set anything up in Unity’s inspector), so we can access the data from there

And I also made sure to tell the ‘TryHit’ function in ‘Fighter.cs’ to ignore any shield parrying commands from the player, to make sure not to mess everything up

Tada, problem solved, in the most unusual way (but if it works, it works!)

And it’s all event-driven (because these capsules in the future can’t be controlled through update. When I make my AI Smart Enough to drive animals, controlling their capsule colliders through Update will be a disaster that’ll take me days to figure out if I leave it as is now. So, I had no choice to cheat my way this time :sweat_smile:), so there will be no performance issues with that one

My last step is to add the attack force for the player (I already implemented the hit force on the enemy, just need the attack force for the player)

And that too is done now. System is split into a damage system and a parrying animation system, because the parrying on the animation system was, for a lack of a better word, terrible, and for the naked eye, 99% of the time you wouldn’t even notice a thing that went wrong

Well done. We really didn’t do much with shields in the course, and it was never conceived of as a weapon in it’s own right (though in truth, a good sword and shield fighter would use that shield to bash an opponent when given the opportunity.

1 Like

you guys are honestly missing out on so much by ignoring the shields and armour… It’s A WHOLE WORLD OF FUN waiting to be triggered, no joke

Please do consider adding them in the future. I promise you, Players (like me and others) will enjoy parrying shields just because we can :stuck_out_tongue:

Who doesn’t want to parry someone and also deflect arrows coming their way? That’s just so much more fun in a game, and a reason to keep playing because it makes you smile :smiley:

Hopefully you fine tune that parry, Because a parry system can fundementally make the game also too easy. so there has to be some bad parts of a failed parry, like takes longer to recover or something so it feels like a risk vs reward sort of thing rather than I can parry in every instance I want. Thats the shame about parrys I find most games don’t find the right balance between them.

I’ll work on the game balance as soon as possible. For now, I’m just developing the core mechanics first, so I don’t have to return to coding again down the line :slight_smile:

When the core mechanics are done, I’ll slowly go public with the game over YouTube, Kickstarter, etc, as I actually develop the game

But first, make sure you actually have a promise you can deliver on (which is what I’m trying to do now)

I understand that part sure, sounds alright

You will always return to the code, its a venom that never leaves you :laughing:

1 Like

well at least let me get comfy first in the driver’s seat first. I still get worried everyday that I hit a roadblock that can potentially let me down… I already hit a few along the way tbh :stuck_out_tongue_winking_eye:

1 Like

I used to fence when I was 1/3rd my current weight and age. There is an inherent danger to a parry. When successful, your opponent takes a hit. When failed, your opponent has a wider opening (because you’ve exposed yourself, really the same principle that allowed the parry in the first place). So a failed parry could result in increased damage from the incoming attack.

we can add a function for that on the Animation event line, no problemo :smiley: - it’s a great idea though

Let’s just hope that I remember it down the line when my enemies get smarter. For now, it’s all prototypes, and I also gotta make sure the enemies get harder as the game progresses

(Fun fact: I quietly setup an ‘OpponentDefenceSetup’, something I invented to get enemies to parry with their own shields against specific hits, if they got a shield in their hand. They need to be randomized though, because right now it’s impossible to beat them because their parry rate is 100%)

Also watch the balance on that also, I had a game where the opponents can also parry and It was a non stop back and forth parry battle, it was bassically like ping pong, Trust me fun but bad game design if nobody fails a parry. :laughing:

which is why there’s going to be probability involved. The higher their levels, the harder your fight will be, but the bigger the reward, and the more experience you shall get :smiley:

The goal is to make sure you never get bored! (although my skilling system will say otherwise)

On a side note @Brian_Trotter does this tutorial still work?

I need a dynamic respawner, so I can have NPCs and Cops and what not spawn in the game, but outside your view radius, and they also get deleted when you leave them… something to keep the game world exciting, but also keep the game computationally light

but it’s also important that specific NPCs can only spawn at specific areas. The last thing I want is a high level NPC spawning in the rookies’ lobby :stuck_out_tongue:

For the most part, yes. Actually, I thought you were already using part of this, to be honest. If I recall, there were a few Gatchas here and there (things that I missed in prototypes that students found when they implemented it, as no plan survives first contact with the enemy.)

It was in the plans for a while, but I kept delaying it… I don’t even know how to implement a test for it just yet :sweat_smile:

(I went through the comments, and now I see why you once told me that someone got terrified of reading through a 500 comment long thread… :stuck_out_tongue:). I got a little terrified too, lol

Privacy & Terms