🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Basic Combat

posted in My First Game
Published July 16, 2021
Advertisement

That was bad

Looking over my first blog post about my journey from zero to… average, I definitely could have done a much better job at documenting my process and have taken the opportunity to teach fellow amateurs and wayward souls what I have learned to help them, and while I kind of want to rewrite it while the information is fresh I'm using this blog to show my progress as a developer over time, so I'll leave it. That horribly written post will stand the test of time and show that this isn't as easy as it all seems, and there's a lot of trial and error involved. So now that I have reflected on the filth, I have made here's some of my new filth.

What is an Attack?

This might seem like a basic question, but what really is an attack in a game? At its core, it seems to mostly be a function or group of functions that help convey to the player that a thing has happened that has subtracted an amount from an obfuscated number that represents how much a beating an entity is can take. A lot of games play a bunch of sounds and have flashy effects and maybe even some combos, but right now, I'm going to focus on three main parts. I want to focus on playing an animation, detecting valid entities within the area of the attack and having the entity take damage.

The Animation

Implementing the animation itself wasn't too hard. Utilizing unity's Trigger parameter in the Animation Controller can easily implement it into the player's animation controller I built yesterday. For now, I'm not going to worry about having a weapon and just grabbed a simple punching animation from Mixamo for testing. Hooking up the Punch animation to the Any State, I can now set it so that the player performs a punch at any point the attack trigger is set. However, a quality of life change I have made is changing the naming conventions of my variables that hold the hash of the Animation Controller parameters so that I can tell the type of parameter at a glance. As such, the hash for the bool “isRunning” has been changed from “isRunningHash” to “boolisRunning_Hash”. The entire addition to my animation code looks like this:

	//Naming convention is variabletype_name_hash
	int bool_isRunning_Hash;
    int trigger_Attack_Hash;
    bool isRunning = false;
    void Start()
    {
        animator = GetComponentInChildren<Animator>();
        bool_isRunning_Hash = Animator.StringToHash("isRunning");
        trigger_Attack_Hash = Animator.StringToHash("Attack");
    }
    public void SetRunning(bool isRunning)
    {
        if (this.isRunning == isRunning) return;
        this.isRunning = isRunning;
        animator.SetBool(bool_isRunning_Hash, isRunning);
    }
    //this is the new function
    public void Attack()
    {
        animator.SetTrigger(trigger_Attack_Hash);
    }

Implement the Logic

The addition of the code attack has three parts. First, the input that triggers the attack, getting the entity that got attacked and then making that entity takes damage. I could implement most of it into the update function without creating a new function, but I have seen some other devs create very bloated update functions that became hard to follow. While this may work for them, simply creating a function to organize the logic seems like the best way to go about this. It keeps my update function short and concise by ensuring that all logic related to player input is neatly organized and compartmentalized. On top of that, it makes it far easier to show all of you only the relevant segment of code.

Deciding to go with triggering the attack on a left-click was the obvious and easy part of this; however, deciding how I was going to get the entity that was struck was much more difficult. While I could use a ray cast, it seemed much more difficult, and the idea of easily missing due to a slight pixel of movement seemed infuriating at best. So after pouring over the different methods unity has for grabbing entities, I decided to go with a method that utilized the OverlapBox, which is part of unity's physics implementation. Most of the code I needed was even in their example, so it was pretty simple to set up. The main addition I made was adding Layer to the LayerMasks that all targetable entities will be assigned to. This will help for the implementation of anything else that I want to be damageable while making sure I don't need to worry about it picking up other game objects that I don't really care about.

Now while this might sound all fine and well, I had one major problem. I had no idea where my OverlapBox was actually appearing, but with the help of OnDrawGizmosSelected and the Gizmos.DrawWireCube I managed to visualize where my overlap box was to move it to somewhere more practical than the player's feet. Now with it firmly in front of the player, it was finally time to create something to attack, so I decided that the target of my aggression will be the previous incarnation and once placeholder model, the Capsule. Creating a simple little component called Health that adds one to the value hits, so it's easy to tell if it's actually being hit. As soon as I attached it to my soon to be assailed I hit play and attacked this filthy heathen… or at least I would have if I actually remembered to make sure that left-clicking called the attack function. Instead, I poured over my code for ten minutes without realizing that I made such a stupid mistake before fixing it. Overall it went pretty well. The only other change I had to make was to change the Input code from Input.GetMouseButton(0) to Input.GetMouseButtonDown(0). For those who don't know the difference, the former will return true EVERY frame the left mouse button is held down while the latter will only do so when it's initially pressed, which means it won't run the Attack function hundreds of times a second.

Implementing Damage

For the time being, I'm going to leave entity damage to the health script and change hits to hitpoints with a simple -1 on each call of the function TakeDamage. While this isn't the best implementation of a health or hitpoint system, that's okay. In the future, I plan to create a script that handles various effects to include damage that has the reference to the targeted entity passed into it, which then executes the appropriate behaviour. For the time being, though, I need to research how to set up a combo attack, even if it's just a basic four-piece.

The final piece of my Attack and Gizmo code looks like the following:

    private void CharacterAttack()
    {
        Collider[] colliders = Physics.OverlapBox(gameObject.transform.position, transform.localScale / 2, Quaternion.identity, m_LayerMask);
        foreach (Collider i in colliders)
        {
            if (i.gameObject.GetInstanceID() == this.gameObject.GetInstanceID()) return; //guard to make sure the player doesnt target themselves.
            
            Debug.Log("Hit: " + i.gameObject.name);
        }
        animationController.Attack();
    }

    private void OnDrawGizmosSelected()
    {
        if (!drawDebugGizmos) return; //guard so gizmos only draw when debugging.
        Gizmos.color = Color.red;
        Gizmos.DrawWireCube(new Vector3(transform.localPosition.x, 1.5f, transform.localPosition.z+.5f), transform.localScale);
    }

Closing

Hopefully, I'll find a way to implement the ability to chain attacks sometime today or tomorrow. If you have any tips or advice on implementation or best practices, then please share. I love learning and improving and welcome all criticism. Thank you for taking the time to read, and happy developing!

Previous Entry A Single Step
0 likes 0 comments

Comments

Nobody has left a comment. You can be the first!
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement

Latest Entries

Basic Combat

5438 views

A Single Step

5032 views
Advertisement