Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
1
Question by epn2365 · Jul 23, 2018 at 09:33 PM · animation2d2d-platformerplatformerfighting

2D Combo Attack

In my game, I have two problems: 1. When my character attacks while moving, he continues to move while the punch animation plays. 2. I don't know where to start with coding a combo attack.

I need it so that my character remains still after pressing the attack button and that I can perform a quick three-punch combo.

Here's my code.

 public float playerSpeed, jumpForce;
 
     public bool grounded = false;
     private bool attacking;
 
     public Transform groundedEnd;
 
     Animator anim;
 
     void Start(){
         anim = GetComponent<Animator> ();
     }
 
     // Update is called once per frame
     void Update () {
         PlayerMove ();
         Raycasting ();
         attackInput ();
     }
 
     void FixedUpdate(){
         handleAttacks ();
         resetValues ();
     }
 
     //attacking
     private void handleAttacks (){
         if (attacking) {
             anim.SetTrigger ("first_punch");
         }
     }
 
     //attack inputs
     private void attackInput(){
         if(Input.GetKeyDown(KeyCode.Q)){
             attacking = true;
         }
     }
 
     //player movement function
     void PlayerMove (){
 
         anim.SetFloat ("speed", Mathf.Abs(Input.GetAxisRaw("Horizontal")));
 
         //move right
         if(Input.GetAxisRaw ("Horizontal") > 0){
             transform.Translate(Vector3.right * playerSpeed * Time.deltaTime);
             transform.eulerAngles = new Vector2 (0, 0);
 
         }
 
         //move left
         if(Input.GetAxisRaw ("Horizontal") < 0){
             transform.Translate(Vector3.right * playerSpeed * Time.deltaTime);
             transform.eulerAngles = new Vector2 (0, 180);
         }
 
         //jump
         if(Input.GetKeyDown (KeyCode.Space) && (grounded == true)){
             GetComponent<Rigidbody2D> ().AddForce (Vector2.up * jumpForce);
         }
     }
 
     //check if player is grounded
     void Raycasting(){
         Debug.DrawLine (this.transform.position, groundedEnd.position, Color.green);
         grounded = Physics2D.Linecast (this.transform.position, groundedEnd.position, 1 << LayerMask.NameToLayer("Ground"));
     }
 
     private void resetValues(){
         attacking = false;
     }
 }





Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

1 Reply

· Add your reply
  • Sort: 
avatar image
0

Answer by Thorlar · Jul 23, 2018 at 11:11 PM

Before explaining in detail:

When my character attacks while moving, he continues to move while the punch animation plays.

In essence, you want to stop your character's movement right when you attack.

I don't know where to start with coding a combo attack.

First of all, you will need an int variable, to store the combo. Increasing by one for each attack, and going to 0 when no attack is detected for X seconds. In this way, you will know where in the combo you are, and what to do (simple if check on the variable), probably name it something like comboCounter

Alternatively, you can expand your trigger design:

 //attacking
      private void handleAttacks (){
          if (attacking) {
              anim.SetTrigger ("first_punch");
          }
      }//didn't change a line, no need to compare, just highlighting that you will be relying on "anim" variable a lot if you go for combos this way

but it will get messy if you want to have big combos, with many outcomes, because you have a lot of dependency to the animator.

Now, on how to stop movement on above script in detail:

First of all, I do not know how your movement works definitely, but I will assume that movement combines both transform and animation (that anim.SetFloat doesn't say much alone)

 //player movement function
      void PlayerMove (){
 if (attacking == true)
      return;

 anim.SetFloat ("speed", Mathf.Abs(Input.GetAxisRaw("Horizontal")));

However, there is a risk. You reset your value on fixed update. attacking bool should be true for the duration of the attack (and animation) so I don't think you should reset the value on FixedUpdate(), otherwise you will have to replace the variable I used, with another "isAttacking" boolean which will be messy. attacking bool should become false only when animation/punch has finished, not right after it has set the values you want (in this case, the Trigger) because in this case, your code could become something like this:

  //attacking
      private void handleAttacks (){
      }
  
      //attack inputs
      private void attackInput(){
          if(Input.GetKeyDown(KeyCode.Q)){
              anim.SetTrigger ("first_punch");
          }
      }

Off-topic: If you are dealing with hitboxes, I would suggest you remake the PlayerMove(), so it works only on FixedUpdate, and move with a rigidbody.(Noting the Jump method/function on PlayerMove(), adding force on Update() isn't as performant as doing it on FixedUpdate() and I don't see why not move the rigidbody by changing its position or velocity instead of transform, since physics don't go well with Transform.translate)

 []

I sincerely hope my answer will be useful, although I did delve into "alternatives" which kinda goes against your current code and I apologize for that, it's just that in the long-term such code may backfire but all in all, good luck :)

(Don't hesitate to write more if my answer failed)

Comment
Add comment · Show 6 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image epn2365 · Jul 24, 2018 at 12:42 PM 0
Share

Sorry for the late reply. I had a class and when I got off, it was really late.

I easily fixed the Player$$anonymous$$ove() function and called it in FixedUpdate() ins$$anonymous$$d of Update().

I understand the idea of using the combo counter to trigger each subsequent attack, but using time in seconds to deter$$anonymous$$e when the next punch can be thrown is where I'm stumped. Could you go into a little more detail in how to approach something like that? Is it more in the code or in the animator (Sorry, I'm relatively new to coding. I only have very basic knowledge of it).

Here is my new code now that I've fixed Player$$anonymous$$ove(). public class playerController : $$anonymous$$onoBehaviour {

     public float playerSpeed, jumpForce;
     private float moveX;
     private int comboCount = 0;
     public bool grounded = false;
     private bool attacking, faceRight;
 
     public Transform groundedEnd;
 
     Animator anim;
 
     void Start(){
         anim = GetComponent<Animator> ();
     }
 
     // Update is called once per frame
     void Update () {
         Raycasting ();
         attackInput ();
     }
 
     void FixedUpdate(){
         Player$$anonymous$$ove ();
         handleAttacks ();
         resetValues ();
     }
 
     //attacking
     private void handleAttacks (){
         if (attacking) {
             anim.SetTrigger ("punch");
         }
     }
 
     //attack inputs
     private void attackInput(){
         if(Input.Get$$anonymous$$eyDown($$anonymous$$eyCode.Q)){
             attacking = true;
         }
     }
 
     //player movement function
     void Player$$anonymous$$ove (){
 
         moveX = Input.GetAxis ("Horizontal");
         GetComponent<Rigidbody2D> ().velocity = new Vector2(moveX * playerSpeed, GetComponent<Rigidbody2D> ().velocity.y);
 
         //in animator, when speed is above 0.01, play running animation
         anim.SetFloat ("speed", $$anonymous$$athf.Abs(Input.GetAxis("Horizontal")));
 
         //move right
         if(moveX < 0.0f && faceRight == false){
             flipPlayer ();
         }
 
         //move left
         if(moveX > 0.0f && faceRight == true){
             flipPlayer ();
         }
 
         //jump
         if(Input.Get$$anonymous$$eyDown ($$anonymous$$eyCode.Space) && (grounded == true)){
             GetComponent<Rigidbody2D> ().AddForce (Vector2.up * jumpForce);
         }
     }
 
     //check if player is grounded
     void Raycasting(){
         Debug.DrawLine (this.transform.position, groundedEnd.position, Color.green);
         grounded = Physics2D.Linecast (this.transform.position, groundedEnd.position, 1 << Layer$$anonymous$$ask.NameToLayer("Ground"));
     }
 
     void flipPlayer(){
         faceRight = !faceRight;
         Vector2 localScale = gameObject.transform.localScale;
         localScale.x *= -1;
         transform.localScale = localScale;
     }
 
     private void resetValues(){
         attacking = false;
     }
 }

Also, I'm still lost on stopping the character's motion when the attack animation plays.

avatar image Thorlar epn2365 · Jul 24, 2018 at 01:48 PM 0
Share

Could you go into a little more detail in how to approach something like that? Is it more in the code or in the animator (Sorry, I'm relatively new to coding. I only have very basic knowledge of it).

No worries on the coding level, no one is judging you, but to go back on topic: You must distinquish what animator and your code does, aka what responsibility each one gets. Otherwise, you will be dealing and evaluating the animator more than what you would like in the long-term. The new code is much better, but to go to your 2 points:

but using time in seconds to deter$$anonymous$$e when the next punch can be thrown is where I'm stumped. Could you go into a little more detail in how to approach something like that?

You must create a simple timer, to check when your punch finishes, so your code needs this part: (I honestly don't know why stack overflow shows the example code below like this, but do paste it somewhere else so it's readable)
float timeElapsed = 0f; public float punchDuration;//Assign this via Inspector, it's how long you expect a punch to last from start to end
void Update() { timeElapsed += Time.deltaTime; if ( timeElapsed > punchDuration ) EndPunch(); }
void EndPunch() { attacking = false; }
Perhaps have 2 timers, the other one counting the combo, so attacking can be true/false, but the combo can still have sometime before it ends. Or, if another punch is detected while attacking == true, await for current punch to end, and go for the next one instantly. (buffering the attacks, I don't like this one so much) So, on the code I suggest, it would look something like this:
avatar image Thorlar epn2365 · Jul 24, 2018 at 01:52 PM 0
Share

The final code is more than 3000 characters but here it is: https://pastebin.com/YkZB50uq
Enjoy :D

avatar image epn2365 Thorlar · Jul 24, 2018 at 02:32 PM 0
Share

It's starting to work the way I would like it to. The only problem right now is that it plays the punch animation twice. Sorry for not explaining the handleAttacks() function, but it triggers the "punch" parameter in my animator which is the only condition for transitioning from Idle or Running to Punch. $$anonymous$$y character stops to punch while running, but whether he is idle or running, the punch plays twice after pressing once.

I'll also need to work the code into the animation of the subsequent punches. I'm assu$$anonymous$$g a way to do this is to create a new variable in the animator that functions similarly to the combo counter, and resets either at the end of the combo or when the punch timer runs out so that the character can return to his idle animation.

Thank you so much btw you've been a huge help!

Show more comments

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

301 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Animation Parameters Not Working Correctly 0 Answers

Character clips into the ground in 2D platformer 0 Answers

Animation Coordinates Issue 0 Answers

Moving platform player bounce when moving down 1 Answer

Animation on public transform from script 2D 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges