6
\$\begingroup\$

This question already has an answer here:

I'm reposting this from my own thread in reddit's gamedev community, since there were too few responses:

I've been looking for some info on that, but I mostly find articles on the design of such systems, which are very useful, but not helpful from the coder's point of view. My main idea is similar to what the 2D Zelda games used to do, but with more directional freedom. In Zelda, you can only face one of the cardinal directions and attack the enemy there.
My idea is to have the same but with any direction, since we now have analog sticks, or even mice. I'm pretty sure this has been done before, and a few Flash games come to mind, such as the Zombie Apocalypse game Dead Frontier (which is now done on Unity3D, but was Flash back when I played it)

I'm working with Unity3D (although I'm making a 2D game), and I'm not completely happy with where I'm going.

This: enter image description here is my current hacky solution for a Melee hit check. The green triangle is the player, the faint green circle is a trigger that checks if there are enemies in this trigger, and the red boxy thing is an enemy.
When the player presses the "melee attack" button, it picks one of the enemies in the trigger (by order of the first one to enter the trigger) and causes damage.

Among a few things I've added to that are: Slow down the player movement during an attack, so that they can't "run n' slash" through an entire level, and also limit how many attacks the player can do per second. An attack cannot start if the previous one hasn't finished yet.

This is looking a bit crude, though. I just kind of hacked it together and it doesn't feel as natural as in other games I've played.

Here's my hacky Melee Attack script in my prototype (it uses a few magic numbers, such as the attack duration):

void Update()
{
 //other logic
    if (Input.GetMouseButtonDown (0) && sec <= 0) 
    {
        attackDuration = 0.5f; //setting how long the attack takes from start to finish
    }
    if (attackDuration > 0)
    {
        attackDuration -= Time.deltaTime;
        if (attackDuration <= 0.25f && !done) //cause the damage when the attack is halfway done
        {
            if(EnemiesInRange.Count > 0)
            {
                Enemy target = ((GameObject)EnemiesInRange[0]).GetComponent<Enemy>();
                target.health -= 10;
                if (target.health <= 0)
                {
                    EnemiesInRange.Remove(target.gameObject); //if the enemy dies, it's no longer a valid target. 
                }

            }
            done = true;
        }
    }
    else
    {
        done = false;
        sec = 0; //attack over, reset it to zero (to avoid stuff like -0,001)
    }
//other logic
}

Meanwhile, in the CharacterMovement.cs script:

void Update()
{
//other logic
    if(gameObject.GetComponent<MeleeAttack>().sec <= 0)
    {       
        lookAtMouse();
        transform.Translate(new Vector3(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"), 0) * baseSpeed, Space.World);
    }
    else
    {
        transform.Translate(new Vector3(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"), 0) * (baseSpeed*0.25f), Space.World);
    }
//other logic
}

What I'm doing here is stopping the player to change their facing during the attack as well as slowing the movement down to 1/4 the base speed.

Anyway, any advice? How could I make attacking and moving feel more natural? What about the hit mechanics themselves?

My biggest gripe right now is: I don't think "Pick an enemy in a small circular area ahead of the player" is really good. What should I do?

\$\endgroup\$

marked as duplicate by wolfdawn, Anko, Josh Nov 6 '14 at 16:39

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • \$\begingroup\$ You should probably ask one thing at a time. This site is Q -> A type and asking many unrelated questions in one post is not really the best idea. \$\endgroup\$ – wondra Sep 18 '14 at 15:54
  • \$\begingroup\$ @wondra, thanks for the advice. I've reworded the title and removed some of the non hit-detection related parts. \$\endgroup\$ – Kiloku Sep 18 '14 at 16:00
  • 5
    \$\begingroup\$ "feel natural" is a subjective term. I think you're at the polish phase, where you just need to play test and tweak things. Add some sliders in game where you can change the magic numbers of your algorithm. Keep tweaking until you get something that feels right to you. It's iterative empirical testing. Anyway, given the nature of the problem, I think this question is in the "primarily opinion based" category of questions. \$\endgroup\$ – MichaelHouse Sep 18 '14 at 16:34
  • \$\begingroup\$ In addition to adjusting the magic values until something feels better, you may also want to try different collision shapes. I might try it with two circles centered on the player representing the min and max range of an attack, and testing if an enemy is within an arc, say 15 degrees left or right of the player's forward vector, and at a distance that falls between those two radii. \$\endgroup\$ – LLL79 Oct 1 '14 at 19:13
  • \$\begingroup\$ What about launching a few virtual bullets (like 4) that would have a circular move ? \$\endgroup\$ – GameAlchemist Oct 6 '14 at 18:06
0
\$\begingroup\$

To help you with collision : There are ways to check for pixels changing color(being drawn over eachother) but I don't use that. I give all object in the game a Bounds Property. The Bounds is a Rectangle that is at the position of the object(enemy/character). Rectangles have a method .Intersects that allows you to see if two rectangle are intersecting. When moving I use a velocity variable that takes the games ellapsed time * the character's movement speed. When I choose attack I check to see if the characters bounds + his Melee Range are intersecting with the enemy's bounds.

It would look something like this :

gameTime = this.GameTime;
velocity = (float)(gameTime.TotalEllapsedTime.MilleSeconds);

Character.Bounds = new Rectangle(Character.Position.X, Character.Position.Y,Character.Widht, Character.Height);

characterMeleeBounds = new Rectangle(Character.Position.X + HeroMeleeRange, Character.Position.Y + HeroMeleeRange,Character.Width + HeroMeleeRange, Character.Height + HeroMeleeRange);

if (characterMeleeBounds.Intersects(Enemy.Bounds)){

//Enemy is hit

}

The limitations of this is that it is limited to a Rectangle, or a collection of Rectangles if you were to make a List to make up an abstract shape. You would then have to loop through the rectangles to see if any of them have intersected with the object.

\$\endgroup\$
  • \$\begingroup\$ I normally do both, rectangle collision and if true, pixel per pixel detection, but only the one inside the 2 colliding rectangle, just exit the loop on the 1st true result, and give him the damage (1st enemy to cross the sword path takes the hit, you can stop your animation there). \$\endgroup\$ – Thierry Savard Saucier Oct 1 '14 at 19:02
0
\$\begingroup\$

Anyway, any advice? How could I make attacking and moving feel more natural? What about the hit mechanics themselves?

My biggest gripe right now is: I don't think "Pick an enemy in a small circular area ahead of the player" is really good. What should I do?

You could have the hit detection and movement restrictions match your attack animations. If the hit detection matches the shown position of the weapon as it moves during an attack, the visual experience will synch with the game effect, and the player can learn how to place themselves to choose which target to try to hit.

You and playtesters can play with it a bit, and tweak it to remove movements that don't look or seem right.

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.