private bool ChooseAttack(bool onlyLookForTaps = false) { // Figure out which attack, if any, matches the current conditions attackDefinition = (from attack in _wS.attacks //TODO instead of GetAttackDirection with inH and inV, do it relative to rotated player where (!onlyLookForTaps || attack.attackInputType == AttackInputType.Tap) && attack.directionTriggers.Contains(_wS.GetAttackDirection(inH, inV)) && (!_wS.mvmt.grounded || attack.groundedState != GroundedState.NotGrounded) && (_wS.mvmt.grounded || attack.groundedState != GroundedState.Grounded) && attack.movementStates.Contains(_wS.mvmt.movementState) select attack).DefaultIfEmpty(NoMatches).First(); // If no attack matches, just cancel this attack (do nothing, basically) if (ReferenceEquals(attackDefinition, NoMatches)) { if (ReferenceEquals(this, _wS.bufferAttack)) { _wS.bufferAttack.state = AttackState.Ended; } else { EndAttack(dontFade: true); // To also make buffer attack primary } return(false); } return(true); }
internal IEnumerator _CheckMeleeHit(AttackAction attackAction) { DirectionalAttackDefinition attackDefinition = attackAction.attackDefinition; _prevBase = weaponBase.position; _prevTip = weaponTip.position; while (attackAction.state == AttackState.Attacking) { bool GetBaddyHit(out RaycastHit2D swingCheck) { bool HitBaddy(RaycastHit2D rHit) { #if UNITY_EDITOR if (visualizeDebug && rHit && !(rHit.collider.GetComponentInParent <IDamageable>() is null) && Linecast(_prevBase, rHit.point, whatIsNotHittable & ~(1 << rHit.collider.gameObject.layer))) { Debug.DrawLine(_prevBase, rHit.point, Color.red); } #endif return(rHit && !(rHit.collider.GetComponentInParent <IDamageable>() is null) && // Make sure nothing of a different layer is between where the sword was and where it hit !Linecast(_prevBase, rHit.point, whatIsNotHittable & ~(1 << rHit.collider.gameObject.layer))); } // print("CHECK1"); //CHECK1: along blade Vector2 basePos = weaponBase.position; Vector2 tipPos = weaponTip.position; swingCheck = Linecast(basePos, tipPos, whatIsHittable); #if UNITY_EDITOR if (visualizeDebug) { Debug.DrawLine(basePos, tipPos); } #endif if (HitBaddy(swingCheck)) { return(true); } // print("CHECK2"); //CHECK2: along tip movement swingCheck = Linecast(_prevTip, tipPos, whatIsHittable); #if UNITY_EDITOR if (visualizeDebug) { Debug.DrawLine(_prevTip, tipPos); } #endif if (HitBaddy(swingCheck)) { return(true); } // print("CHECK3"); //CHECK3: along base movement swingCheck = Linecast(_prevBase, basePos, whatIsHittable); #if UNITY_EDITOR if (visualizeDebug) { Debug.DrawLine(_prevBase, basePos); } #endif if (HitBaddy(swingCheck)) { return(true); } // print("CHECK4"); //CHECK4: along lower third movement swingCheck = Linecast(Vector2.Lerp(_prevBase, _prevTip, 0.33f), Vector2.Lerp(basePos, tipPos, 0.33f), whatIsHittable); #if UNITY_EDITOR if (visualizeDebug) { Debug.DrawLine(Vector2.Lerp(_prevBase, _prevTip, 0.33f), Vector2.Lerp(basePos, tipPos, 0.33f)); } #endif if (HitBaddy(swingCheck)) { return(true); } // print("CHECK5"); //CHECK5: along upper third movement swingCheck = Linecast(Vector2.Lerp(_prevBase, _prevTip, 0.66f), Vector2.Lerp(basePos, tipPos, 0.66f), whatIsHittable); #if UNITY_EDITOR if (visualizeDebug) { Debug.DrawLine(Vector2.Lerp(_prevBase, _prevTip, 0.66f), Vector2.Lerp(basePos, tipPos, 0.66f)); } #endif if (HitBaddy(swingCheck)) { return(true); } // print("CHECK6"); //CHECK6: along first third blade float swordLength = Vector2.Distance(basePos, tipPos); Vector2 baseMid = Vector2.Lerp(_prevBase, basePos, 0.33f); Vector2 tipMid = Vector2.Lerp(_prevTip, tipPos, 0.33f); swingCheck = Raycast(baseMid, tipMid - baseMid, swordLength, whatIsHittable); #if UNITY_EDITOR if (visualizeDebug) { Debug.DrawRay(baseMid, (tipMid - baseMid).normalized * swordLength); } #endif if (HitBaddy(swingCheck)) { return(true); } // print("CHECK7"); //CHECK7: along second third blade baseMid = Vector2.Lerp(_prevBase, basePos, 0.66f); tipMid = Vector2.Lerp(_prevTip, tipPos, 0.66f); swingCheck = Raycast(baseMid, tipMid - baseMid, swordLength, whatIsHittable); #if UNITY_EDITOR if (visualizeDebug) { Debug.DrawRay(baseMid, (tipMid - baseMid).normalized * swordLength); } #endif return(HitBaddy(swingCheck)); } // Check for any hits, then update the prev things bool baddyHit = GetBaddyHit(out RaycastHit2D swingHit); _prevBase = weaponBase.position; _prevTip = weaponTip.position; // Wait till next frame if we didn't hit anything hittable if (!baddyHit) { yield return(Yields.WaitForFixedUpdate); continue; } IDamageable damageable = swingHit.collider.GetComponentInParent <IDamageable>(); Vector2 point = swingHit.point; Vector2 force = mvmt.rb.velocity; //Relative Velocity if (swingHit.collider.attachedRigidbody) { force -= swingHit.collider.attachedRigidbody.velocity; } force = mass * force; //Kinetic Energy = mv^2, but that was too much so just doing mv lol force += attackAction.attackDir * attackDefinition.knockback; // Add knockback in the direction of the swing switch (damageable.CheckProtected(point, swingHit.collider)) { case ProtectedType.Dodging: yield break; case ProtectedType.Blocking: { //TODO recoil and sparks or something shit idk var hTf = holder.transform; Vector2 recoil = (hTf.position - swingHit.transform.position + hTf.up / 6) * attackDefinition.knockback; holder.characterPhysics?.AddForceAt(point, recoil, GetComponentInParent <Collider2D>()); FadeAttackOut(0.30121f); attackAction.BeginRecovering(); yield break; } } // Damage scaled based on relative velocity int damageGiven = (int)Math.Max(attackAction.attackDefinition.damage, attackAction.attackDefinition.knockback * mvmt.rb.velocity.magnitude); damageable.DamageMe(point, force, damageGiven, swingHit.collider); yield break; } }