// Proxy targeting for special range handling private Vector3?GetTargetLocation() { // If target is invalid, we can't update proxy if (!_originalTarget.IsValid || !_originalTarget.HasPosition) { return(null); } // If source is invalid, we can't update proxy if (!Source.IsValid || !Source.HasPosition) { return(null); } var desired = _originalTarget.Position; var source = Source.Position; var dir = new Vector3(desired.x - source.x, 0, desired.z - source.z); var distance = dir.magnitude; dir.Normalize(); switch (Spell.RangeBehaviour) { case Spell.TargetRangeBehaviour.RetargetClampToRange: desired = source + dir * Mathf.Clamp(distance, _minRange, _maxRange); break; case Spell.TargetRangeBehaviour.RetargetSetMaxRange: desired = source + dir * _maxRange; break; } // Stick to floor return(TargetUtility.AboveGround(desired)); }
private void Update() { if (!IsActive) { return; } // Lifetime check if (_timer > 0) { _timer -= Time.deltaTime; if (_timer <= 0) { HandleEvent(ProjectileEvents.TimeExpired, new Target(transform.position)); } } // If target become invalid (i.e. character died) - retarget to its last location if (!_target.IsValid) { _target = new Target(_lastValidTargetPosition); } // Sample new target since the target can move (i.e. character) _lastValidTargetPosition = _target.Position; var currentPosition = transform.position; // If we have reached destination than no additional movement required if (TargetUtility.XZDistance(currentPosition, _lastValidTargetPosition) < DestinationThreshold) { return; } // Calculate direction and distance var xzDir = _lastValidTargetPosition - currentPosition; xzDir.y = 0; var xzDistance = xzDir.magnitude; // XZ direction only xzDir.Normalize(); // Calculate desired position var nextPosition = currentPosition + _speed * Time.deltaTime * xzDir; _distanceTraveled += _speed * Time.deltaTime * xzDir.magnitude; // Update height by calculating relative progress using traveled and remaining distance var progress = Mathf.Clamp01(_distanceTraveled / (_distanceTraveled + xzDistance)); // And sampling height from Height curve float baseY; if (_projectile.HoverGround) { baseY = TargetUtility.AboveGround(nextPosition).y; } else { baseY = Mathf.Lerp(_spawnPoint.y, _lastValidTargetPosition.y, progress); } nextPosition.y = baseY + _projectile.HeightProfile.Evaluate(progress); // If projectile have reached the destination var targetDir = nextPosition - _lastValidTargetPosition; // Update position and rotation transform.position = nextPosition; transform.rotation = Quaternion.LookRotation(targetDir.normalized); if (TargetUtility.XZDistance(nextPosition, _lastValidTargetPosition) < DestinationThreshold) { var eventTarget = _handler.Target; // If eventTarget (destination) is not valid // Raise event with repositioned target if (!eventTarget.IsValid) { eventTarget = _target; } HandleEvent(ProjectileEvents.ReachedDestination, eventTarget); } // Distance check if (_maxDistance > 0 && _distanceTraveled > _maxDistance) { HandleEvent(ProjectileEvents.ReachedMaxDistance, new Target(transform.position)); } }