Adapting code from courses into other projects - knockback function

I’m making a small game where a knight fights bandits. I’m trying to get a knockback function to work and I adapted this code from the 2D course :slight_smile:

public class KnockBack : MonoBehaviour
{
[SerializeField] private float knockbackTime;
private Rigidbody2D rb;

private void Awake() {
    rb = GetComponent<Rigidbody2D>();
}

public void getKnockedBack(Transform damageSource, float knockBackThrust) {
    Vector2 difference = transform.position - damageSource.position;
    difference = difference.normalized * knockBackThrust * rb.mass;
    rb.AddForce(difference, ForceMode2D.Impulse);

However, it doesn’t work. I think it’s because I haven’t referenced the proper terms, since I can’t just copy and paste the entire script.

The above paragraph looks accurate to me though. I also don’t know why Unity is not throwing errors since I haven’t defined DamageSource and other terms? When I try to paste it on all the scripts, it throws tons of errors as the project is designed to work with itself and not what I did.

Those errors are a list of what you need to do. When I added part of one project to another, I just went through the list of errors and fixed them one by one. Pick an error and try to fix it. If you get stuck, post the error message here and any code that is referenced in the error message. Don’t let the number of errors get you down. Sometimes fixing one will make several go away.

That’s not what I asked, I want to know why the code I pasted doesn’t work :slight_smile: That and why there AREN’T errors thrown because I didn’t define terms like (Transform damageSource, float knockBackThrust)

Usually I get lots of red squiggly lines and Unity tells me I they are not defined in this context.

You did define these terms. They are local variables inside your getKnockedBack method. That’s why there are no error messages for them. Without knowing where and how you are calling this method, I can not tell what else is wrong.

1 Like

Thanks for the explanation.

Yes I realize I was not that clear I apologize. I attached this script to the knight Gameobject but it doesn’t work.

So “not defined in current context” is an issue of scope?

The code you posted above does not call the getknockedBack method. Attaching it to a game object does not mean it will get used. Do you have a script that calls this method? Something that controls the combat? Or is there more to the script than you posted? Details like the scripts and the complete error message would help me to help you.

So when I attach this script to objects, if I place them inside OnCollision2D and call the method, will the objects get knocked back?

As I understand it, the tutorial says that I can then attach the script to objects I want to knockback. However, I am making my own minigame and using the script. Is the functionality going to be the same? (I only pasted that section because the rest of the script used terms defined in the tutorial game, which I’m not using. It should still work right?)

Sorry for being unclear this is my first time adapting scripts.

Yes, attach the script to an object and in the OnCollision2D method call your knockback method and the object should get knocked back. You may need to comment out the code you are not using in the script so that unnecessary error messages don’t overwhelm any real issues.

No need to apologize, we are all here to learn. Taking things for one project and putting them in another one is a big step in the learning curve. It takes time, but is very satisfying when it is working.

So I wrote this but I get red lines under GameObject…I know I’m supposed to pass in the correct argument because Transform is a class, but I don’t know what to do there (I thought I did)

As in I don’t know what are the right arguments to pass in.

private void OnCollisionEnter2D(Collision2D collision)
{
getKnockedBack(GameObject, 100f);
}

Thanks for your patience. I thought I could just cut and paste projects into each other without much difficulty but it turns out not because they all use different terms and references (this is what I meant earlier but maybe I wasn’t clear)

You need to pass in the transform of the source of the damage.

It should be the other collider that the Knight either hit into or was hit by.

I tried this :slight_smile:

    {
        getKnockedBack(GameObject.FindWithTag)("Enemy"); 100f) 
    }

But I got errors under the GetKnockedBack and the last parentheses.

Should I use other.Collider or another term? I get confused about the syntax sometimes.

The first argument needs to be a Transform. Also, you have a couple of typos. Try this:

{
        getKnockedBack(GameObject.FindGameObjectWithTag("Enemy").transform, 100f);
}

I did that but no dice. I think it’s because my movement is being called in Update and is overriding the velocity.

I wrapped the controls in :slight_smile:

if (controlsEnabled)
{

public void DisableControls(float duration)
{
if (controlsEnabled)
{
controlsEnabled = false;
StartCoroutine(EnableControlsAfterDelay(duration));
}
}

IEnumerator EnableControlsAfterDelay(float delay)
{
    yield return new WaitForSeconds(delay);
    controlsEnabled = true;
}

but when I call DisableControls it doesn’t work.

Are the typos a problem for the program?

if (controlsEnabled)
{
         public void DisableControls(float duration)
        {
               if (controlsEnabled)
              {
                   controlsEnabled = false;
                   StartCoroutine(EnableControlsAfterDelay(duration));
              }
        }
}

You are trying to declare a method inside an if statement. This will not work. Get rid of the first if statement.

Yes, getting the syntax correct is very important for any programing. Spelling, capitalization and punctuation all have to be exact.

OK I did but now it doesn’t work. If I don’t wrap the controls in an if statement, how does it know that I wish to disable them?

I watched the tutorial video again I think I understand the logic behind how it is coded.

Could I define the method below the if statement?

There aren’t any more compiler errors, so I think the program is ok now?

No compiler errors means that the c# syntax is correct. Now you need to see if Unity does what you want it to. Please paste in the whole script use the correct formating. I am at work right now but I will look at it when I get home.

Ok I posted the whole player.cs

using UnityEngine;
using System.Collections;
public class HeroKnight : MonoBehaviour
{

    [SerializeField] float m_speed = 4.0f;
    [SerializeField] float m_jumpForce = 7.5f;
    [SerializeField] float m_rollForce = 6.0f;
    [SerializeField] bool m_noBlood = false;
    [SerializeField] GameObject m_slideDust;

    private Animator m_animator;
    private Rigidbody2D m_body2d;
    private Sensor_HeroKnight m_groundSensor;
    private Sensor_HeroKnight m_wallSensorR1;
    private Sensor_HeroKnight m_wallSensorR2;
    private Sensor_HeroKnight m_wallSensorL1;
    private Sensor_HeroKnight m_wallSensorL2;
    private bool m_isWallSliding = false;
    private bool m_grounded = false;
    private bool m_rolling = false;
    private int m_facingDirection = 1;
    private int m_currentAttack = 0;
    private float m_timeSinceAttack = 0.0f;
    private float m_delayToIdle = 0.0f;
    private float m_rollDuration = 8.0f / 14.0f;
    private float m_rollCurrentTime;
    public bool isHit;
    public bool isAlive;
    public int startingLives = 3;
    public int currentLives;
    private bool controlsEnabled = true;




    // Use this for initialization
    void Start()
    {
        m_animator = GetComponent<Animator>();
        m_body2d = GetComponent<Rigidbody2D>();
        m_groundSensor = transform.Find("GroundSensor").GetComponent<Sensor_HeroKnight>();
        m_wallSensorR1 = transform.Find("WallSensor_R1").GetComponent<Sensor_HeroKnight>();
        m_wallSensorR2 = transform.Find("WallSensor_R2").GetComponent<Sensor_HeroKnight>();
        m_wallSensorL1 = transform.Find("WallSensor_L1").GetComponent<Sensor_HeroKnight>();
        m_wallSensorL2 = transform.Find("WallSensor_L2").GetComponent<Sensor_HeroKnight>();
    }

    // Update is called once per frame
    void Update()
    {



        {


            // Increase timer that controls attack combo
            m_timeSinceAttack += Time.deltaTime;

            // Increase timer that checks roll duration
            if (m_rolling)
                m_rollCurrentTime += Time.deltaTime;

            // Disable rolling if timer extends duration
            if (m_rollCurrentTime > m_rollDuration)
                m_rolling = false;

            //Check if character just landed on the ground
            if (!m_grounded && m_groundSensor.State())
            {
                m_grounded = true;
                m_animator.SetBool("Grounded", m_grounded);
            }

            //Check if character just started falling
            if (m_grounded && !m_groundSensor.State())
            {
                m_grounded = false;
                m_animator.SetBool("Grounded", m_grounded);
            }

            // -- Handle input and movement --
            float inputX = Input.GetAxis("Horizontal");

            // Swap direction of sprite depending on walk direction
            if (inputX > 0)
            {
                GetComponent<SpriteRenderer>().flipX = false;
                m_facingDirection = 1;
            }

            else if (inputX < 0)
            {
                GetComponent<SpriteRenderer>().flipX = true;
                m_facingDirection = -1;
            }

            // Move
            if (!m_rolling)
                m_body2d.velocity = new Vector2(inputX * m_speed, m_body2d.velocity.y);

            //Set AirSpeed in animator
            m_animator.SetFloat("AirSpeedY", m_body2d.velocity.y);

            // -- Handle Animations --
            //Wall Slide
            m_isWallSliding = (m_wallSensorR1.State() && m_wallSensorR2.State()) || (m_wallSensorL1.State() && m_wallSensorL2.State());
            m_animator.SetBool("WallSlide", m_isWallSliding);

            //Death
            if (Input.GetKeyDown("e") && !m_rolling)
            {
                m_animator.SetBool("noBlood", m_noBlood);
                m_animator.SetTrigger("Death");
            }

            //Hurt
            else if (Input.GetKeyDown("q") && !m_rolling)
                m_animator.SetTrigger("Hurt");

            //Attack
            else if (Input.GetMouseButtonDown(0) && m_timeSinceAttack > 0.25f && !m_rolling)
            {
                m_currentAttack++;

                // Loop back to one after third attack
                if (m_currentAttack > 3)
                    m_currentAttack = 1;

                // Reset Attack combo if time since last attack is too large
                if (m_timeSinceAttack > 1.0f)
                    m_currentAttack = 1;

                // Call one of three attack animations "Attack1", "Attack2", "Attack3"
                m_animator.SetTrigger("Attack" + m_currentAttack);

                // Reset timer
                m_timeSinceAttack = 0.0f;



            }

            // Block
            else if (Input.GetMouseButtonDown(1) && !m_rolling)
            {
                m_animator.SetTrigger("Block");
                m_animator.SetBool("IdleBlock", true);
            }

            else if (Input.GetMouseButtonUp(1))
                m_animator.SetBool("IdleBlock", false);

            // Roll
            else if (Input.GetKeyDown("left shift") && m_grounded && !m_rolling && !m_isWallSliding)
            {
                m_rolling = true;
                m_animator.SetTrigger("Roll");
                m_body2d.velocity = new Vector2(m_facingDirection * m_rollForce, m_body2d.velocity.y);
            }


            //Jump
            else if (Input.GetKeyDown("space") && m_grounded && !m_rolling)
            {
                m_animator.SetTrigger("Jump");
                m_grounded = false;
                m_animator.SetBool("Grounded", m_grounded);
                m_body2d.velocity = new Vector2(m_body2d.velocity.x, m_jumpForce);
                m_groundSensor.Disable(0.2f);
            }

            //Run
            else if (Mathf.Abs(inputX) > Mathf.Epsilon)
            {
                // Reset timer
                m_delayToIdle = 0.05f;
                m_animator.SetInteger("AnimState", 1);
            }

            //Idle
            else
            {
                // Prevents flickering transitions to idle
                m_delayToIdle -= Time.deltaTime;
                if (m_delayToIdle < 0)
                    m_animator.SetInteger("AnimState", 0);
            }


        }

        // Animation Events
        // Called in slide animation.
        void AE_SlideDust()
        {
            Vector3 spawnPosition;

            if (m_facingDirection == 1)
                spawnPosition = m_wallSensorR2.transform.position;
            else
                spawnPosition = m_wallSensorL2.transform.position;

            if (m_slideDust != null)
            {
                // Set correct arrow spawn position
                GameObject dust = Instantiate(m_slideDust, spawnPosition, gameObject.transform.localRotation) as GameObject;
                // Turn arrow in correct direction
                dust.transform.localScale = new Vector3(m_facingDirection, 1, 1);
            }
        }
    }


    public void DisableControls(float duration)
    {
        if (controlsEnabled)
        {
            controlsEnabled = false;
            StartCoroutine(EnableControlsAfterDelay(duration));
        }
    }

    IEnumerator EnableControlsAfterDelay(float delay)
    {
        yield return new WaitForSeconds(delay);
        controlsEnabled = true;
    }
}








OK, one quick thing. You said the script is player.cs, but the class is declared as

public class HeroKnight : MonoBehavior

The file name and the class name have to match. Otherwise Unity will have problems. I will dig deeper later tonight.

Nothing is jumping out at me as being wrong. Just looking at this script by itself, I do not see any issue. Except the name difference I posted about above.

One minor thing: There is an extra set of { } in the update method. It does not hurt the code but it may add to confusion.

Let me know if fixing the file name helps. If you are still having problems, post more for me to look at.

Yeah sorry I got confused because I was posting to multiple forums. The file name is correct.

I am not certain why it’s not knocking back as I don’t see any issues. I attached this and the knockback to the same GameObject (HeroKnight) so it should work.

Privacy & Terms