public IEnumerator CastSpell(EntityManager dstManager, Fire1FireballEffect FireballParams) { ActorAbilitySystem hitTarget = null; // Begin casting // Wait for cloud animation to complete FireballParams.Fireball.gameObject.SetActive(false); yield return(new WaitForSeconds(0.8f)); FireballParams.Fireball.gameObject.SetActive(true); FireballParams.Fireball.transform.localPosition = new Vector3(0, 0, 0); yield return(new WaitForSeconds(0.1f)); // Subscribe to fireball hitbox event FireballParams.Fireball.TriggerEnterEvent += HitTriggered; // Fire projectile straight, up to a particular distance float distanceTravelled = 0f; float penetrations = 0; while (distanceTravelled < FireballParams.maxProjectileDisplacement && penetrations < FireballParams.maxPenetration) { // Move projectile forward float displacement = Time.deltaTime * FireballParams.projectileSpeed; FireballParams.Fireball.transform.position = FireballParams.Fireball.transform.position + (FireballParams.Fireball.transform.forward * displacement); distanceTravelled += displacement; if (hitTarget != null) { penetrations += 1; // Create damage modifier on hit target CreateTargetAttributeModifiers(dstManager, hitTarget.AbilityOwnerEntity); } yield return(null); } FireballParams.Fireball.TriggerEnterEvent -= HitTriggered; FireballParams.Fireball.gameObject.SetActive(false); void HitTriggered(object sender, ColliderEventArgs e) { hitTarget = e.other.gameObject.GetComponent <HurtboxMonoComponent>().ActorAbilitySystem; } }
private IEnumerator AbilityActionLogic(BasicMeleeAbilityPayload payload) { var entityManager = payload.EntityManager; var transform = payload.ActorTransform; var actorAbilitySystem = payload.ActorAbilitySystem; var grantedAbilityEntity = payload.GrantedAbilityEntity; // Check ability state var abilityStateComponent = entityManager.GetComponentData <AbilityStateComponent>(grantedAbilityEntity); if (abilityStateComponent.Value != 0) { yield break; } var animator = actorAbilitySystem.GetComponent <Animator>(); var animatorLayerName = "Weapon"; var animatorStateName = animatorLayerName + ".Swing"; var animatorStateFullHash = Animator.StringToHash(animatorStateName); var animatorLayerIndex = animator.GetLayerIndex(animatorLayerName); // If we aren't in idle, then do nothing if (!animator.GetCurrentAnimatorStateInfo(animatorLayerIndex).IsName("Idle")) { yield break; } BeginActivateAbility(entityManager, grantedAbilityEntity); CreateSourceAttributeModifiers(entityManager, actorAbilitySystem.AbilityOwnerEntity); // Get animator state info var weaponLayerAnimatorStateInfo = GetAnimatorStateInfo(animator, animatorLayerIndex, swingStateName); animator.SetTrigger(AnimationStartTriggerName); // Wait to reach the "Swing" state while (!IsInOrEnteringAnimatorState(animator, animatorLayerIndex, swingStateName)) { yield return(null); } // In the swing state, check for a collision between this hitbox and any hurtbox // Get reference to all hitboxes on source var hitboxes = payload.ActorAbilitySystem.GetComponentsInChildren <HitboxMonoComponent>(false); ActorAbilitySystem hitTarget = null; // Once we're about 35% through the animation, allow hit to trigger while (GetAnimatorStateInfo(animator, animatorLayerIndex, swingStateName).normalizedTime < 0.35f) { yield return(null); } void HitTriggered(object sender, ColliderEventArgs e) { hitTarget = e.other.gameObject.GetComponent <HurtboxMonoComponent>().ActorAbilitySystem; } // Subscribe each hitbox on actor to the HitTriggered method for (int i = 0; i < hitboxes.Length; i++) { hitboxes[i].TriggerEnterEvent += HitTriggered; } // Wait for hitTriggered to become true, or animation to complete while (IsInOrEnteringAnimatorState(animator, animatorLayerIndex, swingStateName) && hitTarget == null) { yield return(new WaitForFixedUpdate()); } // If we get to here trigger return to idle state if (hitTarget != null) { CreateTargetAttributeModifiers(entityManager, hitTarget.AbilityOwnerEntity); animator.SetTrigger("ReturnWeaponToIdle"); // Once we are no longer in the swing animation, commit the ability CreateCooldownEntities(entityManager, actorAbilitySystem.AbilityOwnerEntity); Entity cooldownEntity2 = new AttackCombo1GameplayEffectComponent().Instantiate(entityManager, actorAbilitySystem.AbilityOwnerEntity, 1.5f); } // Get target entity while (IsInOrEnteringAnimatorState(animator, animatorLayerIndex, swingStateName)) { yield return(new WaitForFixedUpdate()); } animator.ResetTrigger("ReturnWeaponToIdle"); EndActivateAbility(entityManager, grantedAbilityEntity); // If we didn't anything, create cooldown entities if (hitTarget == null) { CreateCooldownEntities(entityManager, actorAbilitySystem.AbilityOwnerEntity); } yield return(null); }
private IEnumerator DoDefaultAttack(Entity entity, ActorAbilitySystem actorAbilitySystem) { var translation = GetComponentDataFromEntity <Translation>()[entity]; var rotation = GetComponentDataFromEntity <Rotation>()[entity]; var AbilityState = -1; Entity GrantedAbilityEntity = default(Entity); var forwardVector = math.normalize(math.mul(rotation.Value, new float3(0, 0, 1))); // Check if player can use ability (the GrantedAbility entity contains this information) Entities .WithAllReadOnly <AbilityOwnerComponent, AbilityStateComponent, DefaultAttackAbilityTag>().ForEach((Entity grantedAbilityEntity, ref AbilityStateComponent abilityState, ref AbilityOwnerComponent abilityOwner) => { if (abilityOwner == actorAbilitySystem.AbilityOwnerEntity) { AbilityState = abilityState; GrantedAbilityEntity = grantedAbilityEntity; } }); if (AbilityState != 0) { // We could also do checks here to see what the ability state is and report an appropriate error on screen // For example, we are using AbilityState = 2 to note that the ability is on cooldown, so we could display // something like "This ability is on cooldown" on the screen. yield break; } var playerCastHelper = actorAbilitySystem.GetComponent <PlayerCastTimelineHelperMono>(); // Raycast forward, and if we hit something, reduce it's HP. RaycastHit hit; float3 rayOrigin = actorAbilitySystem.CastPoint.transform.position; // Does the ray intersect any objects if (!Physics.Raycast(rayOrigin, forwardVector, out hit, Mathf.Infinity)) { yield break; } bool wasHit = false; Entity targetEntity = default(Entity); if (hit.distance < 1f) { Debug.DrawRay(rayOrigin, forwardVector * hit.distance, Color.black, 1f); if (hit.transform.parent.gameObject.TryGetComponent <ActorAbilitySystem>(out var targetActorAbilitySystemMono)) { targetEntity = targetActorAbilitySystemMono.AbilityOwnerEntity; wasHit = true; } } new DefaultAttackAbilityTag().BeginActivateAbility(EntityManager, GrantedAbilityEntity); playerCastHelper.PlaySwingAnimation(); yield return(playerCastHelper.StartCoroutine(playerCastHelper.CheckForSwingHit(wasHit, EntityManager, targetEntity))); // Default attack - trigger cooldown and resource cost (new DefaultAttackAbilityTag()).CommitAbility(EntityManager, actorAbilitySystem.AbilityOwnerEntity); new DefaultAttackAbilityTag().EndActivateAbility(EntityManager, GrantedAbilityEntity); }