2
\$\begingroup\$

so I am trying to implement a "Zelda"- or "Dark Souls"-like z-targeting system. You'll see in the code, that the function compiles a list of every enemy in the current scene. I'm still in the prototyping phase so the only credential for the targeting is the distance between enemy and player. The script is attached to my player and there are three enemies in the scene.

Now for the problem: The function is not reliable. Sometimes it updates the 'target', sometimes it doesn't. The debug.log fires as expected, only the most important thing appears to zoom in and out. This function is supposed to toggle the lockon as well, which doesn't reliably work either.

Tips on how to make the code lighter are appreciated as well!

Edit: Added the FixedUpdate(), which is a hot mess right now:

void FixedUpdate ()
{

    // Store the input axes.
    h = Input.GetAxisRaw ("Horizontal");
    v = Input.GetAxisRaw ("Vertical");

    stateInfo = anim.GetCurrentAnimatorStateInfo(0); // 0 is for the base layer.
    if (!stateInfo.IsName("Swing")) { 
        if( Input.GetButtonDown("Fire1")){
            anim.SetTrigger("isAttacking");
        }
    } 

    if (controller.isGrounded) {
        CalcMovement (h, v);
    } else {
        movement.y -= gravity * Time.deltaTime;
    }
    if (Input.GetButtonDown ("Jump")) {
        movement.y = jumpSpeed;  
    }
    if (Input.GetButtonDown ("Fire3")) {
        LockOnEnemy ();
    }
    ProcessEvasion ();
    controller.Move(movement * Time.deltaTime);

    Debug.DrawRay(transform.position, -Vector3.up, Color.blue, transform.position.y + 0.1f);

}

void LockOnEnemy()
{
    //we default to check == false
    bool check = false;

    //we will ONLY scan for new targets if current target is null
    if (target == null)
    {
        GameObject[] enemyList = GameObject.FindGameObjectsWithTag("Enemy");
        if (enemyList.Length > 0)
        {
            int enemyID = -1; //default this to 'invalid' value (just good practice!)
            float closestEnemyDistanceSqr = float.MaxValue; //max lockon distance here (use float.MaxValue unless you have a good reason not to!)

            //find closest enemy (only change is I'm looking at squared magnitudes, as they do the job and are more efficient)
            for (int i = 0; i < enemyList.Length; i++)
            {
                float enemyDeltaSqr = (transform.position - enemyList[i].transform.position).sqrMagnitude;
                if (enemyDeltaSqr < closestEnemyDistanceSqr)
                {
                    closestEnemyDistanceSqr = enemyDeltaSqr;
                    enemyID = i;
                }
            }

            //store the target. we can safely assume enemyID is no longer -1, as we know there is at least 1 enemy in enemyList
            target = enemyList[enemyID].transform;
            Debug.Log("Found: Enemy( " + enemyID + ") at " + Mathf.Sqrt(closestEnemyDistanceSqr));
        }

        //now we set check to true regardless of whether we found an enemy - is this what we want
        check = true;
    }

    //if check is false (i.e. we didn't go through the above if statement), we clear 'target'.
    if (check == false)
    {
        this.target = null;
    }
}

Please note: This version of the code has been commented and cleaned up by the user wibble82, over at unity.answers. Unfortunately nobody could really help me there.

\$\endgroup\$
  • \$\begingroup\$ The code above will set a target on the first call, then always clear it to null on the second call, then select a target on the third call... is that alternating behaviour desired? Or is that the bug you're trying to fix? \$\endgroup\$ – DMGregory Dec 22 '15 at 15:55
  • \$\begingroup\$ are all enemies tagget "Enemy"? \$\endgroup\$ – dnk drone.vs.drones Dec 22 '15 at 15:58
  • \$\begingroup\$ @DMGregory Yes, it is supposed to toggle the lock-on every time the button is pressed. \$\endgroup\$ – Biggzlar Dec 22 '15 at 16:11
  • \$\begingroup\$ @dnkdrone.vs.drones Yes, all enemies are tagged. It might be of note, that the list is compiled properly every time the function is called, same as the Debug.log. \$\endgroup\$ – Biggzlar Dec 22 '15 at 16:13
  • \$\begingroup\$ Where are you calling LockOnEnemy, Biggzlar? Can you show us the relevant snippet of the previous procedure in the call stack? \$\endgroup\$ – DMGregory Dec 22 '15 at 17:12
2
\$\begingroup\$

put

if (Input.GetButtonDown ("Fire3")) {
        LockOnEnemy ();
    }

into Update. In FixedUpdate may be called more than once per frame (or input cicle). Reference: GetButtonDown not always firing

FixedUpdate gets called based on even intervals, the times it ignores your input is the times that it's not updated/called between those intervals.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ That's it, thank you so much! I should really read up on what the different c# functions do. Would you recommend putting other functions into the Update() instead of FixedUpdate()? \$\endgroup\$ – Biggzlar Dec 23 '15 at 9:00
  • \$\begingroup\$ @biggzlar yes for input management. Leave in fixed only physic relevant code \$\endgroup\$ – dnk drone.vs.drones Dec 23 '15 at 9:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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