2
\$\begingroup\$

I could use a little help.

I've a state machine for an NPC that does a melee attack. The problem I'm running into is that the current code instantiates multiple instances when I only need one per cycle.

I could use some ideas.

This is the chunk of code I'm working with:

public void ChaseToAttack()
{
    _navMeshAgent.speed = 3.5f;//slow down the navAgent

    float playerDistance = Vector3.Distance(chaseTarget.position, transform.position);
    //stop navMeshAgent to begin attack sequence
    if (playerDistance <= stopAtDistance)
    {
        /// ensure enemy is always looking at player
        enemyToTarget = ((chaseTarget.position + offset) - eyes.transform.position);
        if(Physics.Raycast(eyes.position, enemyToTarget, out _hit, sightRange) && _hit.collider.CompareTag("Player"))
        {
            _navMeshAgent.Stop();
            currentState = _attackState;
            //StartCoroutine(FistTimer());
            PunchCycle();
        }
        /// ensure the enemy isn't hitting air & will always look for the player
        else
        {
            transform.Rotate(chaseTarget.position, searchTurnSpeed * Time.deltaTime, 0);
        }
        /// end look & atttack player block
    }
}

void PunchCycle()
{
    StartCoroutine(AttackCycle());
}

void PunchClone()
{
    clone = Instantiate(pfbPunch, transform.position, transform.rotation) as Rigidbody;
    clone.transform.Translate(0,1f,0);
    clone.velocity = transform.TransformDirection(0.0f,0.0f,0.125f * punchDistance);
}

IEnumerator AttackCycle()
{
    //move animation here
    AnimPunch();
    PunchClone();
    yield return new WaitForSeconds(4f);//fistTimer
    BeAlert();

}

Thanks in advance...

EDIT:

Changed the code so it would only instantiate once- but now, it will only instantiate only once even though it's still in the attack sequence.

    public void ChaseToAttack()
{
    _navMeshAgent.speed = 3.5f;//slow down the navAgent

    float playerDistance = Vector3.Distance(chaseTarget.position, transform.position);
    //stop navMeshAgent to begin attack sequence
    if (playerDistance <= stopAtDistance)
    {
        /// ensure enemy is always looking at player
        enemyToTarget = ((chaseTarget.position + offset) - eyes.transform.position);
        if(Physics.Raycast(eyes.position, enemyToTarget, out _hit, sightRange) && _hit.collider.CompareTag("Player"))
        {
            _navMeshAgent.Stop();
            currentState = _attackState;
            StartCoroutine(AttackCycle());
        }
        /// ensure the enemy isn't hitting air & will always look for the player
        else
        {
            transform.Rotate(chaseTarget.position, searchTurnSpeed * Time.deltaTime, 0);
        }
        /// end look & atttack player block
    }
}
void PunchClone()
{
    if(!didClone)
    {
        clone = Instantiate(pfbPunch, transform.position, transform.rotation) as Rigidbody;
        clone.transform.Translate(0,1f,0);
        clone.velocity = transform.TransformDirection(0.0f,0.0f,0.125f * punchDistance);
    }
    didClone = true;
}
IEnumerator AttackCycle()
{
    //move animation here
    AnimPunch();
    yield return new WaitForSeconds(0.75f);//fistTimer
    PunchClone();
}
\$\endgroup\$
  • \$\begingroup\$ I added an edit to my answer. You have to set the boolean to false again. \$\endgroup\$ – ElDuderino Dec 8 '15 at 9:18
1
\$\begingroup\$

So I've found a simple solution to synchronize the punch sequence without having to deal with coroutines or instantiating/destroying rigidbodies.

public void AttackCycle()
{
    _navMeshAgent.Stop();
    AnimPunch();
    nmeFistL.SetActive(true);
    if (_animation["nmePunch"].time >= 1.5f)
    {
        nmeFistL.SetActive(false);
    }
}
\$\endgroup\$
0
\$\begingroup\$

I am not sure why you have to instantiate the Rigidbody, but you can just destroy them when you are done punching.

Rigidbody PunchClone()
{
    clone = Instantiate(pfbPunch, transform.position, transform.rotation) as Rigidbody;
    clone.transform.Translate(0,1f,0);
    clone.velocity = transform.TransformDirection(0.0f,0.0f,0.125f * punchDistance);
    return clone;
}

IEnumerator AttackCycle()
{
    //move animation here
    AnimPunch();
    Rigidbody r = PunchClone();
    yield return new WaitForSeconds(4f);//fistTimer
    Destroy(r.gameObject);
    BeAlert();

}

Edit : If you need only one instance active at any time, then going with your boolean method is fine, but you have to set the boolean to false again. You can do that where I do the Destroy(r.gameObject).

\$\endgroup\$
  • \$\begingroup\$ Thanks ElDuderino, I need to instantiate a clone to correspond with the animation sequence (It would end up hitting the player 2x if I didn't). I originally had the collider activate/deactivate but that method ended up bogging down the game. \$\endgroup\$ – Mark Laurel Dec 8 '15 at 2:54
  • \$\begingroup\$ This method is still producing multiple instances. \$\endgroup\$ – Mark Laurel Dec 8 '15 at 3:04
  • \$\begingroup\$ ElDuderino, I get "The name `r' does not exist in the current context" when I added encapsulated - Rigidbody r = PunchClone(); - inside (!didClone) \$\endgroup\$ – Mark Laurel Dec 9 '15 at 1:07
0
\$\begingroup\$

void PunchClone() { if(!didClone) { clone = Instantiate(pfbPunch, transform.position, transform.rotation) as Rigidbody; clone.transform.Translate(0,1f,0); clone.velocity = transform.TransformDirection(0.0f,0.0f,0.125f * punchDistance); } didClone = true; }

There, didClone=true should be inside the if(!didClone){} block. After the if block, add

else didClone=false;

This will ensure that next time the method is called, the value of didClone will be toggled.

\$\endgroup\$
  • \$\begingroup\$ Thanks SanSolo, I've gone this route & it also creates multiple clones... \$\endgroup\$ – Mark Laurel Dec 8 '15 at 20:59

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.