Скрипт для стрельбы пулями на сверхвысоких скоростях

Программирование на Юнити.

Скрипт для стрельбы пулями на сверхвысоких скоростях

Сообщение Mousecach 09 мар 2014, 18:27

Друзья! Предлагаю Вам на осмеяние и поругание скрипт, который можно повесить на пулю(заданную как RigidBody), тем самым, смоделировав движение реальной пули. Причём, данный скрипт передаёт урон в первую попавшую цель, а скорости его могут быть до 100к единиц. Так же, если задать галочку у RigidBody "Use Gravity", то объект, как Вы знаете, будет подвержен гравитации, а изменяя параметр Drag - можно смоделировать сопротивление воздуха. Так же, скрипт учитывает добавление рандомного дамага и снижение урона в зависимости от пройденного расстояния, зависящего от времени полёта. По истечении времени или попадании пуля исчезает.

Собственно, сам скрипт:

Синтаксис:
Используется csharp
using UnityEngine;
using System.Collections;

public class BulletMove : MonoBehaviour {
        public float TimeToDestruct = 10;
        public bool RandomDamage = true;
        public float Damage = 20;
        public float minRandLimit = -5;
        public float maxRandLimit = 5;
        public bool DamageReduction = true;
        public float StartPoinOfDamageReduction = 20;
        public float FinalDamageInPercent = 20;
        public int StartSpeed = 50;

        Vector3 PreviousStep;
        float StartTime, TimeStartDamageReduction;
        float CurrentDamage;

        void Awake ()
        {
                Invoke ("DestroyNow", TimeToDestruct);

                rigidbody.velocity = transform.TransformDirection(Vector3.forward * StartSpeed);

                PreviousStep = gameObject.transform.position;

                StartTime = Time.time;
                TimeStartDamageReduction = TimeToDestruct * StartPoinOfDamageReduction / 100.0f;

                CurrentDamage = Damage;
                if(RandomDamage)
                        CurrentDamage += Random.Range(minRandLimit, maxRandLimit);
        }

        void FixedUpdate()
        {
                Quaternion CurrentStep = gameObject.transform.rotation;

                transform.LookAt (PreviousStep, transform.up);
                RaycastHit[] Objects;
                Ray ray = new Ray (transform.position, transform.forward);
                float Distance = Vector3.Distance (PreviousStep, transform.position);
                if (Distance == 0)
                        Distance = 1.0f;
                Objects = Physics.RaycastAll (ray, Distance);
                if (Objects.Length != 0)
                {
                        SendDamage(Objects [Objects.Length - 1].transform.gameObject);
                }

                gameObject.transform.rotation = CurrentStep;

                PreviousStep = gameObject.transform.position;
        }

       
        void DestroyNow ()
        {
                DestroyObject (gameObject);
        }

        void OnCollisionEnter(Collision hit)
        {      
                SendDamage (hit.gameObject);
        }

        void SendDamage(GameObject Hit)
        {
                Hit.SendMessage ("ApplyDamage", CurrentDamage * GetDamageCoefficient(), SendMessageOptions.DontRequireReceiver);
                Destroy(gameObject);
        }

        float GetDamageCoefficient()
        {
                float Value = 1.0f;
                if (DamageReduction)
                {
                        float CurrentTime = Time.time - StartTime;
                        Debug.Log ("CurrentTime: " + CurrentTime);
                        if (CurrentTime >= TimeStartDamageReduction)
                        {
                                Value = 1.0f - (1 - FinalDamageInPercent / 100) * ((CurrentTime - TimeStartDamageReduction) / (TimeToDestruct - TimeStartDamageReduction));
                        }
                }
                return Value;
        }
}
 


Немного обновил его! Более гибкая настройка нанесения дамага в зависимости от пройденного расстояния с помощью AnimationCurve. Учтите, что если график покрутить вручную, он так и останется! И значения будут сниматься с того, что Вы наскрутили! Так же, этот скрипм можно расценить как небольшое пояснение работы AnimationCurve)

Синтаксис:
Используется csharp
using UnityEngine;
using System.Collections;

public class BulletMove : MonoBehaviour {
        public float TimeToDestruct = 10;
        public bool RandomDamage = true;
        public float Damage = 20;
        public float minRandLimit = -5;
        public float maxRandLimit = 5;
        public bool DamageReduction = true;
        public float StartPoinOfDamageReduction = 20;
        public float FinalDamageInPercent = 20;
        public AnimationCurve DamageReductionGraph;
        public int StartSpeed = 50;

        Vector3 PreviousStep;
        float StartTime;
        float CurrentDamage;

        void Awake ()
        {
                Invoke ("DestroyNow", TimeToDestruct);

                rigidbody.velocity = transform.TransformDirection(Vector3.forward * StartSpeed);

                PreviousStep = gameObject.transform.position;

                StartTime = Time.time;

                CurrentDamage = Damage;
                if(RandomDamage)
                        CurrentDamage += Random.Range(minRandLimit, maxRandLimit);

                Keyframe[] ks;
                ks = new Keyframe [3];

                ks [0] = new Keyframe (0, 1);
                ks [1] = new Keyframe (StartPoinOfDamageReduction / 100, 1);
                ks [2] = new Keyframe (1, FinalDamageInPercent / 100);

                DamageReductionGraph = new AnimationCurve (ks);
        }

        void FixedUpdate()
        {
                Quaternion CurrentStep = gameObject.transform.rotation;

                transform.LookAt (PreviousStep, transform.up);
                RaycastHit[] Objects;
                Ray ray = new Ray (transform.position, transform.forward);
                float Distance = Vector3.Distance (PreviousStep, transform.position);
                if (Distance == 0)
                        Distance = 1.0f;
                Objects = Physics.RaycastAll (ray, Distance);
                if (Objects.Length != 0)
                {
                        SendDamage(Objects [Objects.Length - 1].transform.gameObject);
                }

                gameObject.transform.rotation = CurrentStep;

                PreviousStep = gameObject.transform.position;
        }

       
        void DestroyNow ()
        {
                DestroyObject (gameObject);
        }

        void OnCollisionEnter(Collision hit)
        {      
                SendDamage (hit.gameObject);
        }

        void SendDamage(GameObject Hit)
        {
                Hit.SendMessage ("ApplyDamage", CurrentDamage * GetDamageCoefficient(), SendMessageOptions.DontRequireReceiver);
                Destroy(gameObject);
        }

        float GetDamageCoefficient()
        {
                float Value = 1.0f;
                float CurrentTime = Time.time - StartTime;
                Value = DamageReductionGraph.Evaluate(CurrentTime / TimeToDestruct);

                return Value;
        }
}
 


UPDATE!

И вот, пока третий, но, вроде, не финальный релиз скрипта. Траблы с нанесением двойного урона исключены. Данный скрипт вешается на пустой!(если будут меши или коллайдеры, пуля самоуничтожится! В предыдущих скриптах такого не было, так как мы стреляли в обратную сторону) GameObject с RigidBody. Гораздо менее нагружает игру. Позволяет в поле "Particle Hit" добавить эффект попадания. Тестилось на скоростях от 1 до 500к единиц. Всё работало отлично. Можете использовать.

Синтаксис:
Используется csharp
using UnityEngine;
using System.Collections;

public class BulletMove : MonoBehaviour {
        public float TimeToDestruct = 10;
        public bool RandomDamage = true;
        public float Damage = 20;
        public float minRandLimit = -5;
        public float maxRandLimit = 5;
        public bool DamageReduction = true;
        public float StartPoinOfDamageReduction = 20;
        public float FinalDamageInPercent = 20;
        public AnimationCurve DamageReductionGraph;
        public int StartSpeed = 50;
        public GameObject particleHit;
       
        Vector3 PreviousStep;
        float StartTime;
        float CurrentDamage;
       
        void Awake ()
        {
                Invoke ("DestroyNow", TimeToDestruct);
               
                rigidbody.velocity = transform.TransformDirection(Vector3.forward * StartSpeed);
               
                PreviousStep = gameObject.transform.position;
               
                StartTime = Time.time;
               
                CurrentDamage = Damage;
                if(RandomDamage)
                        CurrentDamage += Random.Range(minRandLimit, maxRandLimit);
               
                Keyframe[] ks;
                ks = new Keyframe [3];
               
                ks [0] = new Keyframe (0, 1);
                ks [1] = new Keyframe (StartPoinOfDamageReduction / 100, 1);
                ks [2] = new Keyframe (1, FinalDamageInPercent / 100);
               
                DamageReductionGraph = new AnimationCurve (ks);
        }
       
        void FixedUpdate()
        {
                Quaternion CurrentStep = gameObject.transform.rotation;
               
                transform.LookAt (PreviousStep, transform.up);
                RaycastHit hit = new RaycastHit();
                float Distance = Vector3.Distance (PreviousStep, transform.position);
                if (Distance == 0.0f)
                        Distance = 1e-05f;
                Debug.Log(Distance);
                if(Physics.Raycast(PreviousStep, transform.TransformDirection(Vector3.back), out hit, Distance * 0.9999f) && (hit.transform.gameObject != gameObject))
                {
                        Instantiate(particleHit, hit.point, Quaternion.FromToRotation(Vector3.up, hit.normal));
                        SendDamage(hit.transform.gameObject);
                }
               
                gameObject.transform.rotation = CurrentStep;
               
                PreviousStep = gameObject.transform.position;
        }
       
        void DestroyNow ()
        {
                DestroyObject (gameObject);
        }

        void SendDamage(GameObject Hit)
        {
                Hit.SendMessage ("ApplyDamage", CurrentDamage * GetDamageCoefficient(), SendMessageOptions.DontRequireReceiver);
                Destroy(gameObject);
        }
       
        float GetDamageCoefficient()
        {
                float Value = 1.0f;
                float CurrentTime = Time.time - StartTime;
                Value = DamageReductionGraph.Evaluate(CurrentTime / TimeToDestruct);
               
                return Value;
        }
}


P.S. Просьба старые варианты не удалять, вдруг кому пригодится. А места он не много занимает.

Вся критика приветствуется. Благодарю за внимание!
Последний раз редактировалось Mousecach 16 мар 2014, 18:10, всего редактировалось 3 раз(а).
Аватара пользователя
Mousecach
UNец
 
Сообщения: 13
Зарегистрирован: 03 фев 2014, 14:30
Откуда: Коломна
Skype: Mousecach
  • Сайт

Re: Скрипт для стрельбы пулями на сверхвысоких скоростях

Сообщение llka 09 мар 2014, 23:48

:ymsigh:
llka
UNIверсал
 
Сообщения: 359
Зарегистрирован: 08 янв 2014, 05:00

Re: Скрипт для стрельбы пулями на сверхвысоких скоростях

Сообщение beatlecore 10 мар 2014, 03:26

у меня есть крипт стрельбы без интснациирования геймобжектов на сцене, по сути по одному го на игрока, дабы не плодить сущности, но он еще сырой и пока что я им не поделюсь)
а еще на больших скоростях рейкаст имеет свойство "проскакивать", было не раз мной поймано, для этих целей лучше использовать LineCast, плюс в вашем скрипте может быть двойной урон, в случае, когда начальная точка шага будет меньше диаметра пули, получится что сработает и рейкаст и коллизия, еще добавлю что данная стрельба не соблюдает законов баллистики, хотя вполне пойдет для упрощенной имитации
Аватара пользователя
beatlecore
Старожил
 
Сообщения: 964
Зарегистрирован: 05 фев 2013, 21:26
Откуда: Sun Crimea

Re: Скрипт для стрельбы пулями на сверхвысоких скоростях

Сообщение waruiyume 10 мар 2014, 03:39

для этих целей лучше использовать LineCast

Инфа 100%?)
Синтаксис:
Используется csharp
// Type: UnityEngine.Physics

public static bool Linecast(Vector3 start, Vector3 end, [DefaultValue("DefaultRaycastLayers")] int layerMask)
    {
      Vector3 direction = end - start;
      return Physics.Raycast(start, direction, direction.magnitude, layerMask);
    }
 
Аватара пользователя
waruiyume
Адепт
 
Сообщения: 6143
Зарегистрирован: 30 окт 2010, 05:03
Откуда: Ростов на Дону

Re: Скрипт для стрельбы пулями на сверхвысоких скоростях

Сообщение beatlecore 10 мар 2014, 04:27

waruiyume писал(а):
для этих целей лучше использовать LineCast

Инфа 100%?)
Синтаксис:
Используется csharp
// Type: UnityEngine.Physics

public static bool Linecast(Vector3 start, Vector3 end, [DefaultValue("DefaultRaycastLayers")] int layerMask)
    {
      Vector3 direction = end - start;
      return Physics.Raycast(start, direction, direction.magnitude, layerMask);
    }
 

писал же, что с рейкастом, сырым, были просеры, с лайнкастом ни одного, да и у меня пули как таковой на сцене не создается, видимо из-за специфики именно моей стрельбы, так что не 100%
Аватара пользователя
beatlecore
Старожил
 
Сообщения: 964
Зарегистрирован: 05 фев 2013, 21:26
Откуда: Sun Crimea

Re: Скрипт для стрельбы пулями на сверхвысоких скоростях

Сообщение Mousecach 10 мар 2014, 10:50

beatlecore писал(а):плюс в вашем скрипте может быть двойной урон, в случае, когда начальная точка шага будет меньше диаметра пули, получится что сработает и рейкаст и коллизия


Так после нанесения урона, пуля уничтожается! И к моменту вызову второй функции, уже и вызывать нечего. Или я где-то ошибоаюсь? :(
Аватара пользователя
Mousecach
UNец
 
Сообщения: 13
Зарегистрирован: 03 фев 2014, 14:30
Откуда: Коломна
Skype: Mousecach
  • Сайт

Re: Скрипт для стрельбы пулями на сверхвысоких скоростях

Сообщение beatlecore 10 мар 2014, 22:05

Mousecach писал(а):
beatlecore писал(а):плюс в вашем скрипте может быть двойной урон, в случае, когда начальная точка шага будет меньше диаметра пули, получится что сработает и рейкаст и коллизия


Так после нанесения урона, пуля уничтожается! И к моменту вызову второй функции, уже и вызывать нечего. Или я где-то ошибоаюсь? :(

Если не наблюдалось, то можете не брать во внимание, если столкнетесь с багом двойного дамага, обратите внимание
Аватара пользователя
beatlecore
Старожил
 
Сообщения: 964
Зарегистрирован: 05 фев 2013, 21:26
Откуда: Sun Crimea

Re: Скрипт для стрельбы пулями на сверхвысоких скоростях

Сообщение Mousecach 11 мар 2014, 15:14

beatlecore писал(а):Если не наблюдалось, то можете не брать во внимание, если столкнетесь с багом двойного дамага, обратите внимание


Да!) Конечно!) Благодарю за критику! Если такое будет наблюдаться, я и сюда обязательно напишу. Сегодня вечером ещё его немного подкорректирую, чтобы он стал пригоден для адекватного наложения текстур выстрела и партиклей на поражаемый объект. А то получается, что стреляем спереди, а дамаг прилетает сзади) Не есть хорошо. Плюс скрипт облегчится. :)
Аватара пользователя
Mousecach
UNец
 
Сообщения: 13
Зарегистрирован: 03 фев 2014, 14:30
Откуда: Коломна
Skype: Mousecach
  • Сайт

Re: Скрипт для стрельбы пулями на сверхвысоких скоростях

Сообщение Mousecach 16 мар 2014, 18:10

И вот, пока третий, но, вроде, не финальный релиз скрипта. Траблы с нанесением двойного урона исключены. Данный скрипт вешается на пустой!(если будут меши или коллайдеры, пуля самоуничтожится! В предыдущих скриптах такого не было, так как мы стреляли в обратную сторону) GameObject с RigidBody. Гораздо менее нагружает игру. Позволяет в поле "Particle Hit" добавить эффект попадания. Тестилось на скоростях от 1 до 500к единиц. Всё работало отлично. Можете использовать.
Аватара пользователя
Mousecach
UNец
 
Сообщения: 13
Зарегистрирован: 03 фев 2014, 14:30
Откуда: Коломна
Skype: Mousecach
  • Сайт

Re: Скрипт для стрельбы пулями на сверхвысоких скоростях

Сообщение Kea 16 мар 2014, 18:39

А зачем
Invoke ("DestroyNow", TimeToDestruct);
?

Можно же
DestroyObject (gameObject, TimeToDestruct );
сделать.
Kea
UNIт
 
Сообщения: 71
Зарегистрирован: 21 июл 2012, 09:49

Re: Скрипт для стрельбы пулями на сверхвысоких скоростях

Сообщение Mousecach 19 мар 2014, 07:44

Kea писал(а):А зачем
Invoke ("DestroyNow", TimeToDestruct);
?

Можно же
DestroyObject (gameObject, TimeToDestruct );
сделать.


Вы знаете.... как-то я об этом не подумал) :) Просто, не так долго работаю, потому и не проследил за сим моментом. :-\ Спасибо большое! Я так понимаю, DestroyObject (gameObject, TimeToDestruct ) быстрее чем Invoke?
Аватара пользователя
Mousecach
UNец
 
Сообщения: 13
Зарегистрирован: 03 фев 2014, 14:30
Откуда: Коломна
Skype: Mousecach
  • Сайт

Re: Скрипт для стрельбы пулями на сверхвысоких скоростях

Сообщение Nestle 05 апр 2014, 16:23

Mousecach писал(а):
Kea писал(а):А зачем
Invoke ("DestroyNow", TimeToDestruct);
?

Можно же
DestroyObject (gameObject, TimeToDestruct );
сделать.


Вы знаете.... как-то я об этом не подумал) :) Просто, не так долго работаю, потому и не проследил за сим моментом. :-\ Спасибо большое! Я так понимаю, DestroyObject (gameObject, TimeToDestruct ) быстрее чем Invoke?

DestroyObject (gameObject, TimeToDestruct ); - удалит gameObject, через заданный интервал TimeToDestruct.
Invoke ("DestroyNow", TimeToDestruct); - запустит "DestroyNow", через заданный интервал TimeToDestruct, в котором удалится gameObject(велосипед, да ещё и без седушки :-? )
Nestle
UNец
 
Сообщения: 1
Зарегистрирован: 04 апр 2014, 18:03

Re: Скрипт для стрельбы пулями на сверхвысоких скоростях

Сообщение Левш@ 05 апр 2014, 18:26

DestroyObject (gameObject, TimeToDestruct ) быстрее чем Invoke?

Быстрее всего DestroyImmediate(), сработает мгновенно. :)
_X.cor.R (Prologue)
Аватара пользователя
Левш@
Адепт
 
Сообщения: 4073
Зарегистрирован: 14 окт 2009, 16:34
Откуда: IBERIA
Skype: bars_levsha
  • Сайт

Re: Скрипт для стрельбы пулями на сверхвысоких скоростях

Сообщение DKV666 12 сен 2022, 11:16

Применял сея скрипт аж в 2022 году))) Работает)))
Если кому надо версия под современную версию юнити:

Синтаксис:
Используется csharp
using System.Collections;
using UnityEngine;

public class BulletMove : MonoBehaviour {
        public float TimeToDestruct = 10;
        public bool RandomDamage = true;
        public float Damage = 20;
        public float minRandLimit = -5;
        public float maxRandLimit = 5;
        public bool DamageReduction = true;
        public float StartPoinOfDamageReduction = 20;
        public float FinalDamageInPercent = 20;
        public AnimationCurve DamageReductionGraph;
        public int StartSpeed = 50;
        public GameObject particleHit;
       
        Vector3 PreviousStep;
        float StartTime;
        float CurrentDamage;
       
        void Awake ()
        {
                Destroy(gameObject, TimeToDestruct);
               
                gameObject.GetComponent<Rigidbody>().velocity = transform.TransformDirection(Vector3.forward * StartSpeed);
               
                PreviousStep = gameObject.transform.position;
               
                StartTime = Time.time;
               
                CurrentDamage = Damage;
                if(RandomDamage)
                        CurrentDamage += Random.Range(minRandLimit, maxRandLimit);
               
                Keyframe[] ks;
                ks = new Keyframe [3];
               
                ks [0] = new Keyframe (0, 1);
                ks [1] = new Keyframe (StartPoinOfDamageReduction / 100, 1);
                ks [2] = new Keyframe (1, FinalDamageInPercent / 100);
               
                DamageReductionGraph = new AnimationCurve (ks);
        }
       
        void FixedUpdate()
        {
                Quaternion CurrentStep = gameObject.transform.rotation;
               
                transform.LookAt (PreviousStep, transform.up);
                RaycastHit hit = new RaycastHit();
                float Distance = Vector3.Distance (PreviousStep, transform.position);
                if (Distance == 0.0f)
                        Distance = 1e-05f;
                //Debug.Log(Distance);
                if(Physics.Raycast(PreviousStep, transform.TransformDirection(Vector3.back), out hit, Distance * 0.9999f) && (hit.transform.gameObject != gameObject))
                {
                        Instantiate(particleHit, hit.point, Quaternion.FromToRotation(Vector3.up, hit.normal));
                        SendDamage(hit.transform.gameObject);
                }
               
                gameObject.transform.rotation = CurrentStep;
               
                PreviousStep = gameObject.transform.position;
        }
       
        void DestroyNow ()
        {
                Destroy(this);
        }

        void SendDamage(GameObject Hit)
        {
                Hit.SendMessage ("ApplyDamage", CurrentDamage * GetDamageCoefficient(), SendMessageOptions.DontRequireReceiver);
                Destroy(gameObject);
        }
       
        float GetDamageCoefficient()
        {
                float Value = 1.0f;
                float CurrentTime = Time.time - StartTime;
                Value = DamageReductionGraph.Evaluate(CurrentTime / TimeToDestruct);
               
                return Value;
        }
}
 
DKV666
UNец
 
Сообщения: 5
Зарегистрирован: 12 сен 2022, 11:11

Re: Скрипт для стрельбы пулями на сверхвысоких скоростях

Сообщение DKV666 10 май 2023, 08:33

Допиленная версия:

- исправлены собственные ошибки и синтаксис
- добавлены комментарии
- добавлен LayerMask позволяющий в инспекторе задать слои с которыми взаимодействует снаряд
- в версии кода для Unity 2022.2 LayerMask применяется автоматически и к Rigidbody (https://docs.unity3d.com/2022.2/Documentation/ScriptReference/Rigidbody-includeLayers.html)
- Добавлена проверка наличия Rigidbody у снаряда.
- Проверка наличия партикля и его использования.
- на указанных версиях Unity проверена работа скриптов.

Для версии Unity 2021.3:
Синтаксис:
Используется csharp
using System.Collections;
using System.Collections;
using UnityEngine;

public class BulletMove : MonoBehaviour {
       
        [Header("Стартовая скорость")]
        [SerializeField]
        private int startSpeed = 500;
       
        [Header("Время жизни снаряда")]
        [SerializeField]
        private float timeToDestruct = 10;
       
        [Header("Урон при попадании")]
        [SerializeField]
        private float damage = 20;
       
        [Header("Использовать ли случайное число урона")]
        [SerializeField]
        private bool randomDamage = true;
               
                [Header("Минимальный лимит рандома случайного урона")]
                [SerializeField]
                private float minRandLimit = -5;
               
                [Header("Максимальный лимит рандома случайного урона")]
                [SerializeField]
                private float maxRandLimit = 5;
       
        [Header("Использовать снижение урона")]
        [SerializeField]
        private bool damageReduction = true;
       
                [Header("Точка (в %) начала снижения урона")]
                [SerializeField]
                private float startPoinOfDamageReduction = 20;
               
                [Header("Урон не ниже %")]
                [SerializeField]
                private float finalDamageInPercent = 20;
               
                private AnimationCurve damageReductionGraph;
               
       
        [Header("Слои с которыми взаимодействует снаряд")]
        [SerializeField]
        private LayerMask layersIs = -1;
       
        [Header("Использовать партикль в точке попадания")]
        [SerializeField]
        private bool useParticle = true;
       
        [Header("Партикль в точке попадания")]
        [SerializeField]
        private GameObject particleHit;
       
        private Vector3 previousStep;
        private float startTime;
        private float timeStartDamageReduction;
        private float currentDamage;
        private Rigidbody gameObjectRigidbody;
       
        private void Awake (){
               
                // задаём уничтожение снаряда через время
                Destroy(gameObject, timeToDestruct);
               
                // получаем Rigidbody
                gameObjectRigidbody = gameObject.GetComponent<Rigidbody>();
               
                // создаём Rigidbody если его нету
                if(gameObjectRigidbody == null){
                       
                        gameObject.AddComponent<Rigidbody>();
                        gameObjectRigidbody = gameObject.GetComponent<Rigidbody>();
                       
                        Debug.LogError ("BulletMove - у снаряда отсутствуем Rigidbody!!! Добавьте объекту Rigidbody!!!");
                }
               
                // запускаем снаряд
                gameObjectRigidbody.velocity = transform.TransformDirection(Vector3.forward * startSpeed);
               
                previousStep = gameObject.transform.position;
                startTime = Time.time;
                timeStartDamageReduction = timeToDestruct * startPoinOfDamageReduction / 100.0f;
                currentDamage = damage;
               
               
                // создаём AnimationCurve для использования снижения урона
                if(randomDamage){

                        currentDamage += Random.Range(minRandLimit, maxRandLimit);
                       
                        Keyframe[] ks;
                                ks = new Keyframe [3];
                               
                                ks [0] = new Keyframe (0, 1);
                                ks [1] = new Keyframe (startPoinOfDamageReduction / 100, 1);
                                ks [2] = new Keyframe (1, finalDamageInPercent / 100);
                               
                                damageReductionGraph = new AnimationCurve (ks);
                }
               
               
        }
           
        private void FixedUpdate(){
               
                Quaternion CurrentStep = gameObject.transform.rotation;
                transform.LookAt (previousStep, transform.up);
                RaycastHit hit = new RaycastHit();
                float Distance = Vector3.Distance (previousStep, transform.position);
               
                if (Distance == 0.0f){
                       
                        Distance = 1e-05f;
                }
               
               
                // отслеживаем было ли препятствие на пути снаряда
                if( Physics.Raycast(previousStep, transform.TransformDirection(Vector3.back), out hit, Distance * 0.9999f, layersIs) && (hit.transform.gameObject != gameObject) )
                {      
                        //Debug.Log("BulletMove - попадание "+Time.time);
                       
                        // если исполуем партикль и он есть
                        if( useParticle && particleHit != null ){
                               
                                Instantiate(particleHit, hit.point, Quaternion.FromToRotation(Vector3.up, hit.normal));
                        }
                       
                        // сообщаем урон цели
                        SendDamage(hit.transform.gameObject);
                }
               
               
                gameObject.transform.rotation = CurrentStep;  
                previousStep = gameObject.transform.position;
               
        }
       
       
        // уничтожить объект
        public void DestroyNow (){
               
                Destroy(this);
        }
       
       
        // сообщаем урон цели
        private void SendDamage(GameObject Hit){
               
                Hit.SendMessage ("ApplyDamage", currentDamage * GetDamageCoefficient(), SendMessageOptions.DontRequireReceiver);
                Destroy(gameObject);
        }
       
       
        // получить коэфицент урона по цели
        private float GetDamageCoefficient(){
               
                float valueIs = 1.0f;
               
                if (damageReduction){
                       
                        float currentTime = Time.time - startTime;
                       
                        //Debug.Log ("BulletMove - currentTime: " + currentTime);
                       
                        if (currentTime >= timeStartDamageReduction){
                               
                                valueIs = 1.0f - (1 - finalDamageInPercent / 100) * ((currentTime - timeStartDamageReduction) / ( timeToDestruct - timeStartDamageReduction ) );
                        }
                }
               
                return valueIs;
        }
}
}


Для версии Unity 2022.2:
Синтаксис:
Используется csharp
using System.Collections;
using UnityEngine;

public class BulletMove : MonoBehaviour {
       
        [Header("Стартовая скорость")]
        [SerializeField]
        private int startSpeed = 500;
       
        [Header("Время жизни снаряда")]
        [SerializeField]
        private float timeToDestruct = 10;
       
        [Header("Урон при попадании")]
        [SerializeField]
        private float damage = 20;
       
        [Header("Использовать ли случайное число урона")]
        [SerializeField]
        private bool randomDamage = true;
               
                [Header("Минимальный лимит рандома случайного урона")]
                [SerializeField]
                private float minRandLimit = -5;
               
                [Header("Максимальный лимит рандома случайного урона")]
                [SerializeField]
                private float maxRandLimit = 5;
       
        [Header("Использовать снижение урона")]
        [SerializeField]
        private bool damageReduction = true;
       
                [Header("Точка (в %) начала снижения урона")]
                [SerializeField]
                private float startPoinOfDamageReduction = 20;
               
                [Header("Урон не ниже %")]
                [SerializeField]
                private float finalDamageInPercent = 20;
               
                private AnimationCurve damageReductionGraph;
               
       
        [Header("Слои с которыми взаимодействует снаряд")]
        [SerializeField]
        private LayerMask layersIs = -1;
       
        [Header("Использовать партикль в точке попадания")]
        [SerializeField]
        private bool useParticle = true;
       
        [Header("Партикль в точке попадания")]
        [SerializeField]
        private GameObject particleHit;
       
        private Vector3 previousStep;
        private float startTime;
        private float timeStartDamageReduction;
        private float currentDamage;
        private Rigidbody gameObjectRigidbody;
       
       
       
       
        private void Awake (){
               
                // задаём уничтожение снаряда через время
                Destroy(gameObject, timeToDestruct);
               
                // получаем Rigidbody
                gameObjectRigidbody = gameObject.GetComponent<Rigidbody>();
               
                // создаём Rigidbody если его нету
                if(gameObjectRigidbody == null){
                       
                        gameObject.AddComponent<Rigidbody>();
                        gameObjectRigidbody = gameObject.GetComponent<Rigidbody>();
                       
                        Debug.LogError ("BulletMove - у снаряда отсутствуем Rigidbody!!! Добавьте объекту Rigidbody!!!");
                }
               
                // запускаем снаряд
                gameObjectRigidbody.velocity = transform.TransformDirection(Vector3.forward * startSpeed);
               
                previousStep = gameObject.transform.position;
                startTime = Time.time;
                timeStartDamageReduction = timeToDestruct * startPoinOfDamageReduction / 100.0f;
                currentDamage = damage;
               
               
                // создаём AnimationCurve для использования снижения урона
                if(randomDamage){

                        currentDamage += Random.Range(minRandLimit, maxRandLimit);
                       
                        Keyframe[] ks;
                                ks = new Keyframe [3];
                               
                                ks [0] = new Keyframe (0, 1);
                                ks [1] = new Keyframe (startPoinOfDamageReduction / 100, 1);
                                ks [2] = new Keyframe (1, finalDamageInPercent / 100);
                               
                                damageReductionGraph = new AnimationCurve (ks);
                }
               
                // задаём слои которые будет использовать физика
                gameObjectRigidbody.includeLayers = layersIs;
        }
       
       
       
        private void FixedUpdate(){
               
                Quaternion CurrentStep = gameObject.transform.rotation;
                transform.LookAt (previousStep, transform.up);
                RaycastHit hit = new RaycastHit();
                float Distance = Vector3.Distance (previousStep, transform.position);
               
                if (Distance == 0.0f){
                       
                        Distance = 1e-05f;
                }
               
               
                // отслеживаем было ли препятствие на пути снаряда
                if( Physics.Raycast(previousStep, transform.TransformDirection(Vector3.back), out hit, Distance * 0.9999f, layersIs) && (hit.transform.gameObject != gameObject) )
                {      
                        //Debug.Log("BulletMove - попадание "+Time.time);
                       
                        // если исполуем партикль и он есть
                        if( useParticle && particleHit != null ){
                               
                                Instantiate(particleHit, hit.point, Quaternion.FromToRotation(Vector3.up, hit.normal));
                        }
                       
                        // сообщаем урон цели
                        SendDamage(hit.transform.gameObject);
                }
               
               
                gameObject.transform.rotation = CurrentStep;  
                previousStep = gameObject.transform.position;
               
        }
       
       
        // уничтожить объект
        public void DestroyNow (){
               
                Destroy(this);
        }
       
       
        // сообщаем урон цели
        private void SendDamage(GameObject Hit){
               
                Hit.SendMessage ("ApplyDamage", currentDamage * GetDamageCoefficient(), SendMessageOptions.DontRequireReceiver);
                Destroy(gameObject);
        }
       
       
        // получить коэфицент урона по цели
        private float GetDamageCoefficient(){
               
                float valueIs = 1.0f;
               
                if (damageReduction){
                       
                        float currentTime = Time.time - startTime;
                       
                        //Debug.Log ("BulletMove - currentTime: " + currentTime);
                       
                        if (currentTime >= timeStartDamageReduction){
                               
                                valueIs = 1.0f - (1 - finalDamageInPercent / 100) * ((currentTime - timeStartDamageReduction) / ( timeToDestruct - timeStartDamageReduction ) );
                        }
                }
               
                return valueIs;
        }
}
 
Последний раз редактировалось DKV666 11 май 2023, 10:27, всего редактировалось 1 раз.
DKV666
UNец
 
Сообщения: 5
Зарегистрирован: 12 сен 2022, 11:11

След.

Вернуться в Скрипты

Кто сейчас на конференции

Сейчас этот форум просматривают: Yandex [Bot] и гости: 9