Ejemplo n.º 1
0
        // 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));
        }
Ejemplo n.º 2
0
        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));
            }
        }