예제 #1
0
    // public PolygonCollider2D[] attackColliders;
    // public bool[] activeAttacks;
    // public PolygonCollider2D attackCollider;
    // public List<Collider2D> collidersHit;
    // public List<Collider2D> collidersDamaged;

    public IEnumerator AttackCollider(bool attackFromWeaponOne, SO_Weapon sOWeapon, SO_Weapon.AttackChain WeapAtkChain, SO_AttackFX sO_AttackFX, PolygonCollider2D atkFXCol, Transform weapOrigTrans)
    {
        // References from the SO_AttackFX.
        float thisColStart = sO_AttackFX.colStart;
        float thisColEnd   = sO_AttackFX.colEnd;

        // Set chosen pool attack FX collider off in case the attack FX dosn't use a collider.
        atkFXCol.enabled = false;
        SO_ImpactFX sO_ImpactFX = sO_AttackFX.soImpactFX;

        // Apply the collision shape and offset position to the chosen pool collider.
        atkFXCol.points = sO_AttackFX.collider.points;
        atkFXCol.offset = sO_AttackFX.collider.offset;
        // Set other variables.
        List <Collider2D> collidersHit     = new List <Collider2D>();
        List <Collider2D> collidersDamaged = new List <Collider2D>();
        float             timer            = 0f;
        bool detectCol  = false;
        bool hitAnEnemy = false;

        // Wait a frame to avoid having the collider appear for a frame at its last position, the atkFX's new position HAS to be set before the collider is enabled. (Maybe specifically for atkFX's that have the same colStart time, first sprite time and moveDelay all set to the same value)
        yield return(null);

        while (timer < thisColEnd)
        {
            timer += Time.deltaTime;
            if (timer >= thisColStart && !detectCol)
            {
                yield return(null);

                // If the attack has a collider, enable it otherwise leave it off.
                if (sO_AttackFX.collider)
                {
                    atkFXCol.enabled = true;
                }
                detectCol = true;
                yield return(null);
            }
            if (detectCol)
            {
                // Detect hit collision.
                Physics2D.OverlapCollider(atkFXCol, hitLayers, collidersHit);
                foreach (Collider2D col in collidersHit)
                {
                    if (!collidersDamaged.Contains(col))
                    {
                        collidersDamaged.Add(col);
                        // If this is an enemy, apply damage.
                        if (col.gameObject.CompareTag("Enemy"))
                        {
                            col.GetComponent <Enemy_Health>().ReceiveDamage(WeapAtkChain.DamageRoll, charEquippedWeapons.activeWeapon.poiseDamage, atkFXCol.transform.position, col.bounds.center);
                            // If at least one enemy is hit apply durability damage to the active weapon.
                            if (!hitAnEnemy)
                            {
                                hitAnEnemy = true;
                                if (sOWeapon.durabilityDamageOnHit)
                                {
                                    charEquippedWeapons.DurabilityDamage(attackFromWeaponOne);
                                }
                            }
                        }
                        else if (col.gameObject.CompareTag("Destructible"))
                        {
                            col.GetComponent <Clutter_Health>().ReceiveDamage(WeapAtkChain.DamageRoll, atkFXCol.transform.position, col.bounds.center);
                        }
                        // Hit impact FX. Apply the correct rotation, position, sprites and layerMask to an impactFX.
                        HitImpact.PlayImpactFX(atkFXCol, col.bounds.center, sO_ImpactFX, hitLayers.layerMask, col);
                        // Set camera nudge backwards from the hit.
                        CameraFollow.CameraNudge_St(weapOrigTrans.up, nudgeStrength);
                        // Slow time. Duration to be set by weapon damage, slow to be adjusted (animation curve) by TimeSlow script.
                        TimeSlow.StartTimeSlow(timeSlowDur);
                        //Debug.Log("Collider: " + col.gameObject.name + " was hit! Hit hit, hurraay!");
                    }
                }
            }
            yield return(null);
        }
        if (collidersHit.Count > 0)
        {
            collidersHit.Clear();
            collidersDamaged.Clear();
        }
        atkFXCol.enabled = false;
        yield return(null);
    }
    public IEnumerator AttackMovement(SO_AttackFX sO_AttackFX, Transform atkFXTrans)
    {
        // References from SO_AttackFX.
        float          totalDuration  = sO_AttackFX.totalDuration;
        float          followDuration = sO_AttackFX.followDuration;
        float          moveDistance   = sO_AttackFX.moveDistance;
        float          spawnDistance  = sO_AttackFX.spawnDistance;
        float          moveDelay      = sO_AttackFX.moveDelay;
        AnimationCurve moveAnimCurve  = sO_AttackFX.moveAnimCurve;
        // Setup variables.
        Vector3 startPos   = Vector3.zero;
        Vector3 targetPos  = Vector3.zero;
        Vector3 xyweapOrig = Vector3.zero;

        //
        // Get movement values before or after delay.
        if (sO_AttackFX.setupBeforeDelay || moveDelay <= 0f)
        {
            // Get the correct orientation for the cur chain attack.
            atkFXTrans.rotation = weapOrigTrans.rotation;
            // Get the weapon's XY position.
            xyweapOrig = new Vector3(weapOrigTrans.position.x, weapOrigTrans.position.y, atkFXTrans.position.z);
            // Put the attack at the correct spawn point, after the move delay.
            atkFXTrans.position = xyweapOrig + (weapOrigTrans.up * spawnDistance);
            //print ("ATK FX has been MOVED to its initital position.");
        }
        if (moveDelay > 0f)
        {
            yield return(new WaitForSeconds(moveDelay));
        }
        if (!sO_AttackFX.setupBeforeDelay)
        {
            // Get the correct orientation for the cur chain attack.
            atkFXTrans.rotation = weapOrigTrans.rotation;
            // Get the weapon's XY position.
            xyweapOrig = new Vector3(weapOrigTrans.position.x, weapOrigTrans.position.y, atkFXTrans.position.z);
            // Put the attack at the correct spawn point, after the move delay.
            atkFXTrans.position = xyweapOrig + (weapOrigTrans.up * spawnDistance);
            //print ("ATK FX has been MOVED to its initital position.");
        }

        float timer        = 0f;
        float moveDuration = totalDuration - moveDelay;

        if (sO_AttackFX.followWeapon)
        {
            while (timer < followDuration)
            {
                timer += Time.deltaTime;
                atkFXTrans.position = weapSpriteTrans.position + (weapOrigTrans.up * sO_AttackFX.followWeaponHeight);
                atkFXTrans.rotation = weapOrigTrans.rotation;

                if (timer >= totalDuration)
                {
                    if (sO_AttackFX.loopAnimation)
                    {
                        timer = 0f;
                    }
                }
                yield return(null);
            }
        }
        // Move the attack a certain distance over attack length period using a lerp.
        if (followDuration < totalDuration)
        {
            // Set Lerp values.
            startPos  = atkFXTrans.position;
            targetPos = atkFXTrans.position + (weapOrigTrans.up * moveDistance);
            while (timer < 1f)
            {
                timer += Time.deltaTime / moveDuration;
                atkFXTrans.position = Vector3.Lerp(startPos, targetPos, moveAnimCurve.Evaluate(timer));
                yield return(null);
            }
        }
        // Reset its position to 999,999 in order to avoid having the collider spawn for a frame at its last used postion, interacting where it should not.
        // atkFXTrans.position = new Vector3(999, 999, atkFXTrans.position.z);
    }
예제 #3
0
    public IEnumerator AttackAnimation(SO_AttackFX sO_AttackFX, Character_AttackFX atkFX, bool atkFollowPlayerOrientation = false)
    {
        // References from the AttackFX object from the CharacterAttackFX Pool.
        atkFX.inUse = true;
        atkFX.exitAttackAnimationFX = false;
        atkFX.loopAnimation         = sO_AttackFX.loopAnimation;
        if (sO_AttackFX.stopOnStun)
        {
            atkFX.stopOnStun = true;
        }
        SpriteRenderer atkSpriteR = atkFX.spriteR;

        atkFX.gameObject.SetActive(true);
        //print ("ATK FX OBJECT set active");
        atkSpriteR.sprite = null;
        // References from the SO_AttackFX.
        Sprite[] atkSprites           = sO_AttackFX.sprites;
        float[]  atkSpriteChangeTimes = sO_AttackFX.spriteChangeTiming;
        float    totalDuration        = sO_AttackFX.totalDuration;
        // Set other variables.
        float timer              = 0f;
        int   thisSpriteIndex    = 0;
        float fxXOrientation     = atkFX.transform.localScale.x;
        float playerXOrientation = charAtk.playerSpriteTrans.localScale.x;
        bool  flipCheck          = false;

        // This was put it to avoid having the first sprite appear before the attack movement was set.
        yield return(null);

        // Go through all the attack FX sprites based on their change timings.
        while (timer < totalDuration)
        {
            timer += Time.deltaTime;
            if (timer >= atkSpriteChangeTimes[thisSpriteIndex])
            {
                atkSpriteR.sprite = atkSprites[thisSpriteIndex];
                if (thisSpriteIndex < atkSpriteChangeTimes.Length - 1)
                {
                    thisSpriteIndex++;
                }
            }
            if (atkFollowPlayerOrientation && timer >= atkSpriteChangeTimes[0] && !flipCheck)
            {
                flipCheck = true;
                if (charAtk.playerSpriteTrans.localScale.x != playerXOrientation)
                {
                    atkFX.transform.localScale = new Vector3(-fxXOrientation, 1, 1);
                }
            }
            // During this time the player will not be able to voluntarily interrupt his attack, for example they will not be able to use their dash skill.
            if (timer > sO_AttackFX.cantInterrupStart && timer < sO_AttackFX.cantInterrupEnd)
            {
                atkFX.canInterrupt = false;
            }
            else
            {
                atkFX.canInterrupt = true;
            }
            // Alternative to not have any point uninterruptable during the attack, have a point durring the attack where it will cancel the attack fx (projectile or not), for example if the player dashes before the nimble spear attack 01's projectile is fully formed it will make it disappear. Basically a point in the attack where the attack is either cancelled or continues.
            // Cancel Point, before this point the attack FX (visual, movement, collision) will be cancelled by things like getting hit aka stunned.
            if (timer > sO_AttackFX.cancelPoint)
            {
                atkFX.involuntaryCancel = false;
            }
            // If my Character_AttackFX pool object is set to stopAttackNow, exit the while loop immediately.
            if (atkFX.exitAttackAnimationFX)
            {
                break;
            }
            // If my Character_AttackFX pool object is set to loop, restart the animation.
            if (timer >= totalDuration)
            {
                if (atkFX.loopAnimation)
                {
                    timer           = 0f;
                    thisSpriteIndex = 0;
                }
            }
            yield return(null);
        }
        while (atkFX.holdLastSprite)
        {
            yield return(null);
        }
        atkSpriteR.sprite = null;
        atkFX.gameObject.SetActive(false);
        atkFX.stopOnStun        = false;
        atkFX.involuntaryCancel = true;
        atkFX.inUse             = false;
    }