Пример #1
0
        private bool FireWeapon(
            TargetTuple target,
            Vector3 displacement,
            float distance,
            bool isServer)
        {
            Ammo ammo = PickBestAmmo(target, displacement, distance);

            if (ammo == null)
            {
                return(false);
            }

            ammo.ShellCountRemaining--;

            // sound
            _audioSource.PlayOneShot(ammo.ShotSound, _shotVolume);

            if (ammo.MuzzleFlashEffect != null)
            {
                ammo.MuzzleFlashEffect.transform.LookAt(target.Position);
                ammo.MuzzleFlashEffect.Play();
            }

            GameObject shell = GameObject.Instantiate(
                _shellPrefab,
                _barrelTip.position,
                _barrelTip.transform.rotation);

            GameObject.Instantiate(ammo.ShellArtPrefab, shell.transform);

            float   roll             = _random.NextFloat(0.0, 100.0);
            bool    isHit            = roll <= ammo.Accuracy;
            Vector3 shellDestination = target.Position;

            if (!isHit)
            {
                int deviationMode = (int)roll % 4;

                float missFactor = _random.NextFloat(
                    Constants.MISS_FACTOR_MIN,
                    Constants.MISS_FACTOR_MAX);

                float weightX = _random.NextFloat(0, 1);

                switch (deviationMode)
                {
                case 0:
                    shellDestination.x += distance * missFactor * weightX;
                    shellDestination.y += distance * missFactor * (1 - weightX);
                    break;

                case 1:
                    shellDestination.x -= distance * missFactor * weightX;
                    shellDestination.y += distance * missFactor * (1 - weightX);
                    break;

                case 2:
                    shellDestination.x += distance * missFactor * weightX;
                    shellDestination.y -= distance * missFactor * (1 - weightX);
                    break;

                case 3:
                    shellDestination.x -= distance * missFactor * weightX;
                    shellDestination.y -= distance * missFactor * (1 - weightX);
                    break;
                }
            }

            ShellBehaviour shellBehaviour = shell.GetComponent <ShellBehaviour>();

            shellBehaviour.Initialize(shellDestination, ammo);

            if (isServer)
            {
                if (target.IsUnit)
                {
                    if (isHit && !ammo.IsAoe)
                    {
                        target.Enemy.HandleHit(
                            ammo.DamageType, ammo.DamageValue, displacement, distance);
                    }
                }
                else
                {
                    // HE damage is applied by the shellBehavior when it explodes
                }
            }

            return(true);
        }
Пример #2
0
        public void HandleUpdate()
        {
            _weapon?.HandleUpdate();

            if (_target == null || !_target.Exists)
            {
                TurnTurretBackToDefaultPosition();
                return;
            }

            bool  aimed = false;
            float targetHorizontalAngle = 0f;
            float targetVerticalAngle   = 0f;

            if (_target.Position != Vector3.zero)
            {
                aimed = true;

                Vector3 directionToTarget = _target.Position - _turret.position;
                directionToTarget = new Vector3(directionToTarget.x, 0, directionToTarget.z);
                Quaternion rotationToTarget = Quaternion.LookRotation(
                    _turret.parent.transform.InverseTransformDirection(directionToTarget));

                // Add any necessary cannon elevation to the rotation
                rotationToTarget *= ShellBehaviour.CalculateBarrelAngle(
                    _shellVelocity, _turret.transform.position, _target.Position, out _);

                targetHorizontalAngle = rotationToTarget.eulerAngles.y.unwrapDegree();

                // If this turret has no flexibility (ArcHorizontal = 0) and is fully
                // rotated by a parent turret, it can get stuck 0.0000000001 degrees
                // away from the target due to float rounding errors (parent rounds
                // one way and decides he's done, child rounds the other way).
                // So round away the last degree to avoid this case:
                targetHorizontalAngle = Util.RoundTowardZero(targetHorizontalAngle);
                if (Mathf.Abs(targetHorizontalAngle) > _arcHorizontal)
                {
                    targetHorizontalAngle = 0f;
                    aimed = false;
                }

                targetVerticalAngle = rotationToTarget.eulerAngles.x.unwrapDegree();
                targetVerticalAngle = (float)Math.Floor(targetVerticalAngle);
                if (targetVerticalAngle < -_arcUp || targetVerticalAngle > _arcDown)
                {
                    targetVerticalAngle = 0f;
                    aimed = false;
                }
            }

            float turn            = Time.deltaTime * _rotationRate;
            float horizontalAngle = _turret.localEulerAngles.y;
            float verticalAngle   = _turret.localEulerAngles.x;
            float deltaAngle;

            deltaAngle = (targetHorizontalAngle - horizontalAngle).unwrapDegree();
            if (Mathf.Abs(deltaAngle) > turn)
            {
                horizontalAngle += (deltaAngle > 0 ? 1 : -1) * turn;
                aimed            = false;
            }
            else
            {
                horizontalAngle = targetHorizontalAngle;
            }

            deltaAngle = (targetVerticalAngle - verticalAngle).unwrapDegree();
            if (Mathf.Abs(deltaAngle) > turn)
            {
                verticalAngle += (deltaAngle > 0 ? 1 : -1) * turn;
                aimed          = false;
            }
            else
            {
                verticalAngle = targetVerticalAngle;
            }

            _turret.localEulerAngles = new Vector3(verticalAngle, horizontalAngle, 0);

            IsFacingTarget = aimed;

            foreach (Turret turret in Children)
            {
                turret.HandleUpdate();
            }
        }