private void Update() { if (_situation.IsAlerted) { if (!_hasAddedToAlertedControllers) { _hasAddedToAlertedControllers = true; _alertedControllers.Add(this); } } else if (_hasAddedToAlertedControllers) { _alertedControllers.Remove(this); } _stateTime += Time.deltaTime; _agent.updatePosition = false; _agent.updateRotation = false; _agent.updateUpAxis = false; _agent.autoRepath = true; _agent.autoBraking = false; if (!_motor.IsAlive) { _situation.TargetCover = null; } if (_lastTargetCover != _situation.TargetCover) { if (_lastTargetCover != null) { _lastTargetCover.UnregisterUser(_actor); } _lastTargetCover = _situation.TargetCover; if (_lastTargetCover != null) { _lastTargetCover.RegisterUser(_actor); } } if (_isWaitingForPath && !_agent.pathPending) { _pathLength = _agent.path.GetCornersNonAlloc(_path); _currentPathIndex = 0; _isWaitingForPath = false; } if (!_motor.IsAlive) { _state = AIState.none; _agent.enabled = false; return; } else { _agent.enabled = true; } if (_motor.PotentialCover != null) { _motor.InputTakeCover(); } if (_situation.IsAlerted) { if (!_motor.IsInCover) { _motor.InputAim(); } // Make the AI pick up a weapon. if (Fighting.WeaponToUse <= 0) { _motor.InputWeapon(0); } else if (Fighting.WeaponToUse - 1 < _motor.Weapons.Length) { _motor.InputWeapon(Fighting.WeaponToUse); } else { _motor.InputWeapon(_motor.Weapons.Length); } _situation.IsAllowedToBeAggressive = true; /// /// POTENTIALLY FORGET ABOUT THE ENEMY. CHECK IF CAN BE AGGRESSIVE. /// if (_situation.Threat != null) { if (_situation.Threat.IsAlive) { if (!_situation.CanSeeTheThreat && _situation.NoThreatTimer > View.EnemySustainTime) { _situation.RemoveEnemyState(); } else { if (_registeredGroup != null) { _registeredGroup.MarkAsPotentialAggressive(this); _situation.IsAllowedToBeAggressive = _registeredGroup.IsAggressive(this); } } } else { _situation.RemoveEnemyState(); } } /// /// AIM AND FIRE /// if (_situation.Threat != null && (_situation.CanSeeTheThreat || _situation.NoThreatTimer < View.SightSustainTime)) { // Process grenade throwing if (_situation.ThrownGrenadeCount < Grenades.GrenadeCount) { var doThrow = false; if (_situation.IsAllowedToBeAggressive) { if (_hasThrowFirstGrenade) { if (_grenadeTimer < Grenades.Interval) { _grenadeTimer += Time.deltaTime; } else { doThrow = true; } } else { if (_grenadeTimer < Grenades.FirstGrenadeDelay) { _grenadeTimer += Time.deltaTime; } else { doThrow = true; } } } if (doThrow && _motor.PotentialGrenade != null) { if (_grenadeCheckTimer <= float.Epsilon) { GrenadeDescription desc; desc.Gravity = _motor.Grenade.Gravity; desc.Duration = _motor.PotentialGrenade.Timer; desc.Bounciness = _motor.PotentialGrenade.Bounciness; var length = GrenadePath.Calculate(GrenadePath.Origin(_motor, Util.AngleOfVector(_situation.ThreatGroundPosition - transform.position)), _situation.ThreatGroundPosition, _motor.Grenade.MaxVelocity, desc, _grenadePath, _motor.Grenade.Step); if (Vector3.Distance(_grenadePath[length - 1], _situation.ThreatGroundPosition) > Grenades.MaxRadius || Vector3.Distance(_grenadePath[length - 1], _situation.CurrentPosition) < Grenades.AvoidDistance) { _grenadeCheckTimer = Grenades.CheckInterval; } else { _motor.InputThrowGrenade(_grenadePath, length, _motor.Grenade.Step); _situation.ThrownGrenadeCount++; _grenadeTimer = 0; _hasThrowFirstGrenade = true; } } else { _grenadeCheckTimer -= Time.deltaTime; } } else { _grenadeCheckTimer = 0; } } // Position in world space that is best fit to aim at. var perfectTarget = _situation.ThreatGroundPosition + (_situation.ThreatTopPosition - _situation.ThreatGroundPosition) * 0.7f; if (_situation.IsThreatInCover) { var dot = Vector3.Dot(_situation.ThreatCoverForward, (_situation.ThreatGroundPosition - transform.position).normalized); if (dot < -0.1f) { perfectTarget = _situation.ThreatStandingTopPosition; } } // Make the AI look at the target. { var vector = perfectTarget - _motor.transform.position; vector.y = 0; if (vector.magnitude < 2) { _motor.SetLookTarget(perfectTarget + vector * 2); } else { _motor.SetLookTarget(perfectTarget); } _motor.SetBodyLookTarget(perfectTarget); } // Aim the gun at the inprecise target. var targetRadius = Fighting.TargetRadius.Get(Vector3.Distance(_situation.ThreatGroundPosition, transform.position)); _motor.SetFireTarget(perfectTarget + new Vector3(UnityEngine.Random.Range(-1, 1) * targetRadius, UnityEngine.Random.Range(-1, 1) * targetRadius, UnityEngine.Random.Range(-1, 1) * targetRadius)); // We want AI too look at the corner when standing near it. if (_motor.IsInTallCover) { if (_situation.TargetDirection < 0) { _motor.InputStandLeft(); } else if (_situation.TargetDirection > 0) { _motor.InputStandRight(); } } // Fire { var isAllowedToFire = _situation.IsAllowedToBeAggressive; if (Behaviour.OnlyFireWhenSeen || !_situation.IsAllowedToBeAggressive) { var up = Camera.main.WorldToViewportPoint(transform.position); var down = Camera.main.WorldToViewportPoint(transform.position + Vector3.up * 2); if ((up.x < 0 || up.y < 0 || up.x > 1 || up.y > 1 || up.z < 0) && (down.x < 0 || down.y < 0 || down.x > 1 || down.y > 1 || down.z < 0)) { isAllowedToFire = false; } else { isAllowedToFire = true; } } if (isAllowedToFire) { var burst = Behaviour.IsFightingUsingCovers ? CoveredFightingBursts : CoveredApproachBursts; var isDumb = _state == AIState.fireInCover && (_stateTime <= burst.IntroDuration || _stateTime >= burst.IntroDuration + burst.Duration); var isWalking = _state != AIState.takeCover && _state != AIState.approach && _state != AIState.retreat; // Check if can fire right now. if (Behaviour.CanFire && (!isWalking || _walkingBurstWait < WalkingBursts.Duration) && (!_situation.IsTargetCoverGood || (_state != AIState.hideInCover && (_state != AIState.takeCover || _motor.Cover == null)))) { var aimPoint = transform.position; if (_motor.IsInTallCover && _situation.IsTargetCoverGood) { if (_situation.TargetDirection < 0) { aimPoint = _motor.Cover.LeftCorner(transform.position.y, _motor.CoverSettings.CornerOffset.x); } else { aimPoint = _motor.Cover.RightCorner(transform.position.y, _motor.CoverSettings.CornerOffset.x); } } // See if the motor can hit the standing enemy after potentially peeking. if (AIUtil.IsInSight(this, aimPoint, _situation.ThreatStandingTopPosition)) { if (_state == AIState.fireInCover) { _motor.InputAim(); } if (!isDumb) { _motor.InputFire(); } } } } _lookPointTimer = 0; } } else { _motor.SetFireTarget(_situation.ThreatGroundPosition); _motor.SetLookTarget(_situation.ThreatGroundPosition); _motor.SetBodyLookTarget(_situation.ThreatGroundPosition); lookAround(_situation.ThreatGroundPosition - _motor.transform.position); } } else { _motor.InputWeapon(0); if (_state == AIState.patrol || _state == AIState.patrolPause) { Vector3 forward; if (Waypoints.Length > 1) { var next = Waypoints[_situation.PatrolPoint]; forward = next.Position - transform.position; if (forward.magnitude < 0.5f) { var previous = _situation.PatrolPoint == 0 ? Waypoints[Waypoints.Length - 1] : Waypoints[_situation.PatrolPoint - 1]; var line = next.Position - previous.Position; if (Vector2.Dot(line, forward) > 0) { forward = line; } } } else { forward = transform.forward; } lookAround(forward); } else { _lookPointTimer = 0; } } var positionToMoveTo = transform.position; /// /// STATE MANAGEMENT /// { var updateSituationInDetail = false; { // Update the update delay timer. _updateTimer -= Time.deltaTime; if (_updateTimer < 0) { _updateTimer = Fighting.ReactionTime; updateSituationInDetail = true; } } // Update standing burst timer. { _walkingBurstWait += Time.deltaTime; if (_walkingBurstWait > WalkingBursts.Duration + WalkingBursts.Wait) { _walkingBurstWait = 0; } } { _situation.Update(this, _previousSituation, updateSituationInDetail); if (!isStateStillValid(_state, _stateTime, _situation, _situation)) { updateSituation(calcState(_situation, _state, _stateTime)); } } } /// /// WALK /// if (!_motor.IsInCornerAimState) { if (_state == AIState.takeCover || _state == AIState.approach || _state == AIState.investigate || _state == AIState.retreat || _state == AIState.patrol || _state == AIState.avoidGrenade) { var toTarget = _situation.TargetPosition - transform.position; // If patrolling, set the body to rotate towards the target. if (_state == AIState.patrol) { if (toTarget.magnitude > 0.1f) { var normalized = toTarget.normalized; var position = transform.position + normalized * 4; var dot = Vector3.Dot(toTarget.normalized, _motor.transform.forward); if (Waypoints[_situation.PatrolPoint].Run) { _motor.SetBodyLookTarget(position, 8); } else { if (dot > 0) { _motor.SetBodyLookTarget(position, 1.6f); } else if (dot > -0.5f) { _motor.SetBodyLookTarget(position, 2.5f); } else { _motor.SetBodyLookTarget(position, 4f); } } } } // Move the last meter without using the agent. if (toTarget.magnitude > 1.0f) { var vectorToAgent = _agent.nextPosition - transform.position; var distanceToAgent = vectorToAgent.magnitude; if (distanceToAgent > float.Epsilon) { vectorToAgent /= distanceToAgent; } // If agent moved too far, reset it. if (distanceToAgent > 1f) { updateAgent(_situation.TargetPosition); } float walkSpeed; if (_state == AIState.patrol && !Patrol.IsAlwaysRunning && (Waypoints.Length == 0 || !Waypoints[_situation.PatrolPoint].Run)) { walkSpeed = 0.5f; } else { walkSpeed = 1.0f; } var point = _currentPathIndex + 1 < _pathLength ? _path[_currentPathIndex + 1] : _situation.TargetPosition; var vectorToPoint = point - transform.position; var distanceToPoint = vectorToPoint.magnitude; if (distanceToPoint > float.Epsilon) { vectorToPoint /= distanceToPoint; } if (distanceToPoint < 0.1f && _currentPathIndex + 1 < _pathLength) { _currentPathIndex++; } _agent.speed = 0.1f; _motor.InputMovement(new CharacterMovement(vectorToPoint, walkSpeed)); } else { if (_state == AIState.takeCover) { _motor.InputImmediateCoverSearch(); _motor.InputTakeCover(); } if (toTarget.magnitude > 0.05f) { _motor.InputMovement(new CharacterMovement(toTarget.normalized, 0.5f)); } else { _motor.transform.position = _situation.TargetPosition; } } } } }
public bool ManualUpdate() { if (_mode != Mode.Grenade) { destroyGrenadePreview(); } checkLanded(); switch (_mode) { ////////////////////////////////////////////////////////////////////////////////////////////////////// case Mode.Default: { //// TRANSITIONS ////////////////////// if (_motor.HasGrenadeInHand) { return(transitionAndPerform(Mode.Grenade)); } if (updateIsAiming()) { return(transitionAndPerform(Mode.Aim)); } if (isSprinting()) { return(transitionAndPerform(Mode.Sprint)); } if (updateIsMelee()) { return(transitionAndPerform(Mode.Melee)); } if (_motor.IsInCover) { return(transitionAndPerform(Mode.Cover)); } //// LOGIC ////////////////////// checkArmLift(); checkReload(); checkUnzoom(); checkEquipment(); checkJump(); checkRoll(); checkClimbOrVault(); checkMovement(1); checkCover(); checkGrenade(); checkCrouch(); checkMelee(); } break; ////////////////////////////////////////////////////////////////////////////////////////////////////// case Mode.Sprint: { //// TRANSITIONS ////////////////////// if (_motor.HasGrenadeInHand) { return(transitionAndPerform(Mode.Grenade)); } if (updateIsAiming()) { return(transitionAndPerform(Mode.Aim)); } if (!isSprinting()) { return(transitionAndPerform(Mode.Default)); } //// LOGIC ////////////////////// lowerArms(); checkReload(); checkUnzoom(); checkEquipment(); checkJump(); checkRoll(); checkClimbOrVault(); checkMovement(2); checkCover(); checkGrenade(); checkCrouch(); } break; case Mode.Cover: { //// TRANSITIONS ////////////////////// if (_motor.HasGrenadeInHand) { return(transitionAndPerform(Mode.Grenade)); } if (updateIsAiming()) { return(transitionAndPerform(Mode.Aim)); } if (isSprinting()) { return(transitionAndPerform(Mode.Sprint)); } if (updateIsMelee()) { return(transitionAndPerform(Mode.Melee)); } if (!_motor.IsInCover) { return(transitionAndPerform(Mode.Default)); } //// LOGIC ////////////////////// lowerArms(); checkMelee(); checkReload(); checkUnzoom(); checkEquipment(); checkJump(); checkRoll(); checkClimbOrVault(); checkMovement(1); checkGrenade(); checkCrouch(); } break; ////////////////////////////////////////////////////////////////////////////////////////////////////// case Mode.Aim: { //// TRANSITIONS ////////////////////// if (!updateIsAiming()) { return(transitionAndPerform(Mode.Default)); } //// LOGIC ////////////////////// _noAimSustain = 0; if (AimWhenWalking && MovementInput.IsMoving) { _aimSustain = AimSustain; } else { _aimSustain -= Time.deltaTime; } checkZoom(); checkEquipment(); checkJump(); checkRoll(); checkClimbOrVault(); checkMovement(1); checkCover(); checkGrenade(); checkCrouch(); checkReload(); checkMelee(); if (CancelHurt) { _motor.CancelAndPreventGetHit(0.3f); } liftArms(); _motor.SetBodyTarget(BodyTargetInput); _motor.SetAimTarget(AimTargetInput); if (ImmediateTurns) { _motor.InputPossibleImmediateTurn(); } if (_motor.IsInCover) { _motor.InputAimWhenLeavingCover(); } _motor.InputAim(); if (_motor.IsWeaponReady && FireInput) { _aimSustain = AimSustain; var gun = _motor.ActiveWeapon.Gun; if (gun != null && gun.LoadedBulletsLeft <= 0) { _motor.InputReload(); } else { _motor.InputFire(); } } if (_motor.IsWeaponScopeReady && ZoomInput) { _aimSustain = AimSustain; _motor.InputZoom(); if (_isScoping) { _motor.InputScope(); } } } break; ////////////////////////////////////////////////////////////////////////////////////////////////////// case Mode.Grenade: { if (!_motor.HasGrenadeInHand) { return(transitionAndPerform(Mode.Default)); } if (_motor.IsReadyToThrowGrenade && _motor.CurrentGrenade != null) { GrenadeDescription desc; desc.Gravity = _motor.Grenade.Gravity; desc.Duration = _motor.PotentialGrenade.Timer; desc.Bounciness = _motor.PotentialGrenade.Bounciness; var verticalAngle = Mathf.Min(GrenadeVerticalAngleInput + ThrowAngleOffset, MaxThrowAngle); var velocity = _motor.Grenade.MaxVelocity; if (verticalAngle < 45) { velocity *= Mathf.Clamp01((verticalAngle + 15) / 45f); } _grenadePathLength = GrenadePath.Calculate(GrenadePath.Origin(_motor, GrenadeHorizontalAngleInput), GrenadeHorizontalAngleInput, verticalAngle, velocity, desc, _grenadePath, _motor.Grenade.Step); _hasGrenadePath = true; if (_explosionPreview == null && ExplosionPreview != null) { _explosionPreview = GameObject.Instantiate(ExplosionPreview); _explosionPreview.transform.SetParent(null); _explosionPreview.SetActive(true); } if (_explosionPreview != null) { _explosionPreview.transform.localScale = Vector3.one * _motor.PotentialGrenade.ExplosionRadius * 2; _explosionPreview.transform.position = _grenadePath[_grenadePathLength - 1]; } if (_pathPreview == null && PathPreview != null) { _pathPreview = GameObject.Instantiate(PathPreview); _pathPreview.transform.SetParent(null); _pathPreview.SetActive(true); } if (_pathPreview != null) { _pathPreview.transform.position = _grenadePath[0]; var path = _pathPreview.GetComponent <PathPreview>(); if (path != null) { path.Points = _grenadePath; path.PointCount = _grenadePathLength; } } } else { destroyGrenadePreview(); } if (_hasGrenadePath && _wantsToThrowGrenade) { if (ImmediateTurns) { _motor.InputPossibleImmediateTurn(); } _motor.SetBodyTarget(BodyTargetInput); _motor.SetAimTarget(BodyTargetInput); _motor.InputThrowGrenade(_grenadePath, _grenadePathLength, _motor.Grenade.Step); } if (_wantsToCancelGrenade) { _motor.InputCancelGrenade(); } lowerArms(); checkZoom(); checkJump(); checkRoll(); checkClimbOrVault(); checkMovement(2); checkCover(); checkCrouch(); } break; ////////////////////////////////////////////////////////////////////////////////////////////////////// case Mode.Melee: { //// TRANSITIONS ////////////////////// if (_motor.HasGrenadeInHand) { return(transitionAndPerform(Mode.Grenade)); } if (isSprinting()) { return(transitionAndPerform(Mode.Sprint)); } if (!updateIsMelee()) { return(transitionAndPerform(Mode.Default)); } //// LOGIC ////////////////////// checkUnzoom(); checkEquipment(); checkJump(); checkRoll(); checkClimbOrVault(); checkMovement(2); checkGrenade(); checkCrouch(); checkMelee(); if (_meleeTarget != null) { _motor.SetBodyTarget(_meleeTarget.transform.position); _motor.SetAimTarget(_meleeTarget.transform.position + Vector3.up * 1.5f); _motor.InputMeleeTarget(_meleeTarget.transform.position); if (!MovementInput.IsMoving) { var vector = _meleeTarget.transform.position - _motor.transform.position; var distance = vector.magnitude; if (distance < MinMeleeDistance) { var other = Characters.Get(_meleeTarget.gameObject); if (other.Motor == null || !other.Motor.IsPerformingMelee) { const float minMovementDuration = 0.2f; if (distance < MinMeleeDistance * 0.35f) { _motor.InputMovement(new CharacterMovement(-vector / distance, 1, minMovementDuration)); } else { _motor.InputMovement(new CharacterMovement(-vector / distance, 0.5f, minMovementDuration)); } } } } } } break; } // RESET _wantsToThrowGrenade = false; _wantsToAim = false; _wantsToHit = false; _wantsToRoll = false; _wantsToReload = false; _wantsToUnequip = false; _wantsToTakeGrenade = false; _wantsToCancelGrenade = false; _wantsToCrouch = false; _wantsToTakeCover = false; _wantsToJump = false; _wantsToClimbOrVault = null; if (!_wantsToEquip.IsNull) { _wantsToEquip = new WeaponDescription(); } // RETURN return(true); }
private void Update() { if (_isActivating) { _activateTimer -= Time.deltaTime; if (_activateTimer < float.Epsilon) { _isActivating = false; _isActivated = true; GrenadeList.Register(this); _timer = Timer; } } if (_isActivated) { if (_timer < float.Epsilon) { explode(); } else { _timer -= Time.deltaTime; if (_timer < Timer - PreviewTime) { if (_preview == null) { _preview = GameObject.Instantiate(ExplosionPreview); _preview.transform.parent = null; _preview.SetActive(true); } if (_preview != null) { _preview.transform.localScale = Vector3.one * ExplosionRadius * 2; _preview.transform.position = transform.position; } } else if (_preview != null) { GameObject.Destroy(_preview); _preview = null; } } } if (_isFlying) { var position = transform.position; var previousOffset = _offset; _offset = Vector3.Lerp(_offset, Vector3.zero, Time.deltaTime * 2); position += _offset - previousOffset; GrenadePath.Step(ref position, ref _velocity, Time.deltaTime, _gravity, Bounciness); transform.position = position; } }
private void updateGrenadeAimAndPreview() { if ((HasAiming || _wasAiming) && IsAllowedToFire && _motor.IsAlive && _motor.IsReadyToThrowGrenade && _motor.CurrentGrenade != null) { GrenadeDescription desc; desc.Gravity = _motor.Grenade.Gravity; desc.Duration = _motor.PotentialGrenade.Timer; desc.Bounciness = _motor.PotentialGrenade.Bounciness; var angle = Magnitude * 45f; var velocity = _motor.Grenade.MaxVelocity; if (angle < 45) { velocity *= Mathf.Clamp01((angle + 15) / 45f); } _grenadePathLength = GrenadePath.Calculate(GrenadePath.Origin(_motor, _motor.LookAngle), _motor.LookAngle, angle, velocity, desc, _grenadePath, _motor.Grenade.Step); _hasGrenadePath = true; if (_explosionPreview == null && ExplosionPreview != null) { _explosionPreview = GameObject.Instantiate(ExplosionPreview); _explosionPreview.transform.parent = null; _explosionPreview.SetActive(true); } if (_explosionPreview != null) { _explosionPreview.transform.localScale = Vector3.one * _motor.PotentialGrenade.ExplosionRadius * 2; _explosionPreview.transform.position = _grenadePath[_grenadePathLength - 1]; } if (_pathPreview == null && PathPreview != null) { _pathPreview = GameObject.Instantiate(PathPreview); _pathPreview.transform.parent = null; _pathPreview.SetActive(true); } if (_pathPreview != null) { _pathPreview.transform.position = _grenadePath[0]; var path = _pathPreview.GetComponent <PathPreview>(); if (path != null) { path.Points = _grenadePath; path.PointCount = _grenadePathLength; } } } else { if (_explosionPreview != null) { GameObject.Destroy(_explosionPreview); _explosionPreview = null; } if (_pathPreview != null) { GameObject.Destroy(_pathPreview); _pathPreview = null; } _hasGrenadePath = false; } }