Падение ФПС из-за скрипта турели)=

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

Падение ФПС из-за скрипта турели)=

Сообщение BANNERTM 10 июн 2012, 21:40

Есть скрипт турели:
Синтаксис:
Используется csharp
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class cannon : MonoBehaviour {
       
 Transform target; // цель
public Transform sp;//spawn point (спавн пулей)
public Transform bullet;//пуля
public float attackRange = 30.0f;
public float shootAngleDistance = 10.0f;
public float gundamag = 30;    

       
float _time = 5.0f;
double t = 0.3f;//число для счетчика выстрелов
       
float objectdefault_y_position = 21.55736f;    
 
void FindClosestEnemy(){
               
                GameObject closest=null;
                float distance = 5000f;
       
               
                foreach(var enemy in Enemy_test_Scrpt.AllEnemies)
  {
               
                var diff=(enemy.transform.position-transform.position);
                var curDistance=diff.sqrMagnitude;     
                if(curDistance<distance)
                        {
                                closest=enemy;
                                distance=curDistance;
                               
                        }
       
  }    
               
        target=closest.transform;      
               

        }

void Awake(){

}
void Start(){

        }

void Update(){
                       
               
        FindClosestEnemy();
                       
       
               
//Пушка ищет ближайшую цель
               
               
               
       
if (target == null) //если не нашла то ретурн
return;
 
        //повороачиваем пушку к цели    
   var targetPoint = target.position;
   var targetRotation = Quaternion.LookRotation (targetPoint - transform.position, Vector3.up);
   transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 4.0f);

   var forward = transform.TransformDirection(Vector3.forward);
   var targetDir = target.position - transform.position;
 ////повороачиваем пушку к цели
               
RaycastHit hit;
       
                if(Physics.Raycast(transform.position,transform.forward,out hit,200f)){//стрельба
                        //Debug.DrawLine( transform.position, target.position, Color.red);
        Pause ();//пауза  
                               
                               
                        if(t>=0.5){//ждем пока счетчик обнулится       
                       
                        if(hit.transform.gameObject.layer!=4){ 
                       
                                hit.transform.gameObject.GetComponent<Enemy_test_Scrpt>().target_health-=gundamag;     
                                        }
                       
                               
                        t=0.3;//счетчик выстрела обнуляем               
                        }
                               
                }//DrawScript
        }
               
void Pause(){//пауза
               
if(t<0.5){
t+=Time.deltaTime*(1.0/_time); 
}      
        }
}
 


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




public class Enemy_test_Scrpt : MonoBehaviour {
        public  float target_health=100;
        public GameObject target_follow;
       
       
        public static List<GameObject> AllEnemies = new List<GameObject>();
       void Awake()
       {
            AllEnemies.Add(gameObject);
       }
       void OnDestroy()
       {
            AllEnemies.Remove(gameObject);
       }
       
        void Start () {

        }
       
       
  void Update () {


        if(target_health<=0){
                        Destroy(transform.gameObject);
                Destroy(target_follow);
               
               
                }      
        }
       
       
       
}
 


Проблема заключается в том что функция FindClosestEnemy() жрет огромное количество фпс, если разместить ее в update(), а если функцию поместить в awake() или start() , то пушка ищет только одну цель(а они появляются во время игры(instantiate)) , как быть подскажите - буду премного благодарен
BANNERTM
UNITрон
 
Сообщения: 241
Зарегистрирован: 26 фев 2012, 00:13

Re: Падение ФПС из-за скрипта турели)=

Сообщение Egoor 10 июн 2012, 23:00

Самый простейший вариант, дешево и сердито - вызывай функцию через несколько кадров, например:
Синтаксис:
Используется csharp
int time =0;
...
void Update(){
time++;

if(time==60){    
FindClosestEnemy();
time=0;
}
}
 
Everybody Lies
Аватара пользователя
Egoor
UNец
 
Сообщения: 47
Зарегистрирован: 10 июн 2012, 11:11

Re: Падение ФПС из-за скрипта турели)=

Сообщение BANNERTM 10 июн 2012, 23:23

Egoor писал(а):Самый простейший вариант, дешево и сердито - вызывай функцию через несколько кадров, например:
Синтаксис:
Используется csharp
int time =0;
...
void Update(){
time++;

if(time==60){    
FindClosestEnemy();
time=0;
}
}
 

Нет, все равно фпс падает также, да и потом мне нужна часая прверка ближайшей цели
BANNERTM
UNITрон
 
Сообщения: 241
Зарегистрирован: 26 фев 2012, 00:13

Re: Падение ФПС из-за скрипта турели)=

Сообщение BANNERTM 10 июн 2012, 23:34

И вообще как можно переделать функцию FindClosestEnemy? Для оптимизации
BANNERTM
UNITрон
 
Сообщения: 241
Зарегистрирован: 26 фев 2012, 00:13

Re: Падение ФПС из-за скрипта турели)=

Сообщение Good1101 11 июн 2012, 03:08

поменьше создавайте новых переменных в методе
Синтаксис:
Используется csharp
            GameObject closest=null;
            float distance = 5000f;
void FindClosestEnemy(){
                           
                foreach(var enemy in Enemy_test_Scrpt.AllEnemies)
               {
               
                var diff=(enemy.transform.position-transform.position);

                if(diff.sqrMagnitude<distance)
                        {
                                closest=enemy;
                                distance=curDistance;
                               break;
                        }
       
  }    
               
        target=closest.transform;      
               

        }

вот так попробуйте может что изменится, а вообще в цикле все дело, если очень много enemy то наверно лучше отказатся от него, можно например повесть большой тригер, и брать в таргет цель которая вошла в тригер. или что то еще. или быть может через корутину проверять...
Как тут стрелять?
Аватара пользователя
Good1101
Адепт
 
Сообщения: 1100
Зарегистрирован: 17 ноя 2011, 14:07
  • ICQ

Re: Падение ФПС из-за скрипта турели)=

Сообщение Good1101 11 июн 2012, 04:24

Да, скорее всего предложенный выше способ вам не подойдет поэтому попробуйте следующим образом, обрабатывать метод FindClosestEnemy в отдельном потоке. не скажу что он будет вызываться каждый кадр, но будет так - прошел весь цикл, подождал 1 кадр и пошел по новой.
зато в своем потоке независимо от упдейта. Скажу только что я так никогда не пробовал делать, кроме того что соорудил мальнький примерчик только что, и возможно будут последствия, но попробовать стоит. (popcorn)
Синтаксис:
Используется csharp
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
public class cannon : MonoBehaviour
{

    Transform target; // цель
    public Transform sp;//spawn point (спавн пулей)
    public Transform bullet;//пуля
    public float attackRange = 30.0f;
    public float shootAngleDistance = 10.0f;
    public float gundamag = 30;
    float delta;


    float _time = 5.0f;
    double t = 0.3f;//число для счетчика выстрелов

    float objectdefault_y_position = 21.55736f;

    void FindClosestEnemy()
    {

        GameObject closest = null;

        while (true)
        {
            float distance = 5000f;
            foreach (var enemy in Enemy_test_Scrpt.AllEnemies)
            {

                var diff = (enemy.transform.position - transform.position);
                var curDistance = diff.sqrMagnitude;
                if (curDistance < distance)
                {
                    closest = enemy;
                    distance = curDistance;

                }

            }

            target = closest.transform;
            Thread.Sleep((int)delta * 1000);
        }

    }

    void Awake()
    {

    }
    void Start()
    {

        Thread thread = new Thread(FindClosestEnemy);
        thread.Start();
    }

    void Update()
    {

        delta = Time.deltaTime;



        //Пушка ищет ближайшую цель




        if (target == null) //если не нашла то ретурн
            return;

        //повороачиваем пушку к цели    
        var targetPoint = target.position;
        var targetRotation = Quaternion.LookRotation(targetPoint - transform.position, Vector3.up);
        transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 4.0f);

        var forward = transform.TransformDirection(Vector3.forward);
        var targetDir = target.position - transform.position;
        ////повороачиваем пушку к цели

        RaycastHit hit;

        if (Physics.Raycast(transform.position, transform.forward, out hit, 200f))
        {//стрельба
            //Debug.DrawLine( transform.position, target.position, Color.red);
            Pause();//пауза  


            if (t >= 0.5)
            {//ждем пока счетчик обнулится      

                if (hit.transform.gameObject.layer != 4)
                {

                    hit.transform.gameObject.GetComponent<Enemy_test_Scrpt>().target_health -= gundamag;
                }


                t = 0.3;//счетчик выстрела обнуляем              
            }

        }//DrawScript
    }

    void Pause()
    {//пауза

        if (t < 0.5)
        {
            t += Time.deltaTime * (1.0 / _time);
        }
    }
}
 

если будут ошибки пишите исправим. ;)
Как тут стрелять?
Аватара пользователя
Good1101
Адепт
 
Сообщения: 1100
Зарегистрирован: 17 ноя 2011, 14:07
  • ICQ

Re: Падение ФПС из-за скрипта турели)=

Сообщение AndreyMust19 11 июн 2012, 07:57

В каждом кадре ты проверяешь координаты до каждого противника в сцене. Для этого придумали ставить триггер-коллайдер в зоне обзора и проверять расстояние только до тех, кто в него попали. Твоя же турель реально не будет стрелять на 5000 метров?
Вместо foreach используй просто for. Функция Physics.Raycast не очень быстро работает, поэтому положи ее в FixedUpdate и запускай только через 0.2-0.5 секунд. К тому же вы пускаете луч в каждом кадре, а проверяете результат его работы только каждые 0,2 секунды. Не проще пускать луч только тогда когда он вам нужен?
И зачем сделал смерть при падении здоровья ниже нуля в Update? Это надо делать в отдельном методе нанесения урона, а переменную здоровья делать закрытой для остальных скриптов.
Нужна помощь? Сами, сами, сами, сами, сами... делаем все сами
AndreyMust19
Адепт
 
Сообщения: 1119
Зарегистрирован: 07 июн 2011, 13:19

Re: Падение ФПС из-за скрипта турели)=

Сообщение BANNERTM 11 июн 2012, 11:18

Good1101 писал(а):Да, скорее всего предложенный выше способ вам не подойдет поэтому попробуйте следующим образом, обрабатывать метод FindClosestEnemy в отдельном потоке. не скажу что он будет вызываться каждый кадр, но будет так - прошел весь цикл, подождал 1 кадр и пошел по новой.
зато в своем потоке независимо от упдейта. Скажу только что я так никогда не пробовал делать, кроме того что соорудил мальнький примерчик только что, и возможно будут последствия, но попробовать стоит. (popcorn)
Синтаксис:
Используется csharp
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
public class cannon : MonoBehaviour
{

    Transform target; // цель
    public Transform sp;//spawn point (спавн пулей)
    public Transform bullet;//пуля
    public float attackRange = 30.0f;
    public float shootAngleDistance = 10.0f;
    public float gundamag = 30;
    float delta;


    float _time = 5.0f;
    double t = 0.3f;//число для счетчика выстрелов

    float objectdefault_y_position = 21.55736f;

    void FindClosestEnemy()
    {

        GameObject closest = null;

        while (true)
        {
            float distance = 5000f;
            foreach (var enemy in Enemy_test_Scrpt.AllEnemies)
            {

                var diff = (enemy.transform.position - transform.position);
                var curDistance = diff.sqrMagnitude;
                if (curDistance < distance)
                {
                    closest = enemy;
                    distance = curDistance;

                }

            }

            target = closest.transform;
            Thread.Sleep((int)delta * 1000);
        }

    }

    void Awake()
    {

    }
    void Start()
    {

        Thread thread = new Thread(FindClosestEnemy);
        thread.Start();
    }

    void Update()
    {

        delta = Time.deltaTime;



        //Пушка ищет ближайшую цель




        if (target == null) //если не нашла то ретурн
            return;

        //повороачиваем пушку к цели    
        var targetPoint = target.position;
        var targetRotation = Quaternion.LookRotation(targetPoint - transform.position, Vector3.up);
        transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * 4.0f);

        var forward = transform.TransformDirection(Vector3.forward);
        var targetDir = target.position - transform.position;
        ////повороачиваем пушку к цели

        RaycastHit hit;

        if (Physics.Raycast(transform.position, transform.forward, out hit, 200f))
        {//стрельба
            //Debug.DrawLine( transform.position, target.position, Color.red);
            Pause();//пауза  


            if (t >= 0.5)
            {//ждем пока счетчик обнулится      

                if (hit.transform.gameObject.layer != 4)
                {

                    hit.transform.gameObject.GetComponent<Enemy_test_Scrpt>().target_health -= gundamag;
                }


                t = 0.3;//счетчик выстрела обнуляем              
            }

        }//DrawScript
    }

    void Pause()
    {//пауза

        if (t < 0.5)
        {
            t += Time.deltaTime * (1.0 / _time);
        }
    }
}
 

если будут ошибки пишите исправим. ;)


Неа , не работает - пишет get_transform can only be called from the main thread.
А что там с тригерамми? Я никогда с ними не имел дело. Как они работают?
P.S если что пишу стратегию - туреллей и целей может быть достаточно много. Какие есть эффективные способы поиска ближайшей цели?
BANNERTM
UNITрон
 
Сообщения: 241
Зарегистрирован: 26 фев 2012, 00:13

Re: Падение ФПС из-за скрипта турели)=

Сообщение artk 11 июн 2012, 11:34

вы каждый кадр иницилизируете и удаляете кучу переменных.
лучше использовать физику для поиска целей, чем перебор всех врагов и проверка их расстояния.
Зачем вам каждый кадр искать цель? Используйте коротины и проверяйте расстояние уже на захваченной цели.
Последний раз редактировалось artk 11 июн 2012, 12:15, всего редактировалось 1 раз.
Аватара пользователя
artk
Старожил
 
Сообщения: 749
Зарегистрирован: 22 май 2011, 12:22

Re: Падение ФПС из-за скрипта турели)=

Сообщение jetyb 11 июн 2012, 12:10

var diff = (enemy.transform.position - transform.position);

Брать компонент Transform у каждого объекта каждую проверку долго. Лучше сразу ссылаться на компоненты transform от enemies.
http://unity3d.com/support/documentatio ... ation.html

Можно не перебирать всех врагов на сцене, а завести динамический список врагов, который изменяется только при вхождении в область туррели.
jetyb
Адепт
 
Сообщения: 1486
Зарегистрирован: 31 окт 2011, 17:21

Re: Падение ФПС из-за скрипта турели)=

Сообщение Syberex 11 июн 2012, 12:16

artk писал(а):Не используйте return в Update, епта!

А что тут не так? Только быстрый выход из Update :-?

Во первых просто Update изменить на FixedUpdate() - это грубо, но станет заметно легче :)
Потому уже код вылизывать...

2 BANNERTM
Ты используешь diff.sqrMagnitude - это квадрат расстояния, оно быстрее вычисляется - от того и дистанция 5000? ;)
Или тогда возведи его в квадрат ...
Аватара пользователя
Syberex
Адепт
 
Сообщения: 2292
Зарегистрирован: 14 янв 2011, 20:35
Откуда: Кострома
  • Сайт

Re: Падение ФПС из-за скрипта турели)=

Сообщение BANNERTM 11 июн 2012, 12:36

Syberex писал(а):
artk писал(а):Не используйте return в Update, епта!

А что тут не так? Только быстрый выход из Update :-?

Во первых просто Update изменить на FixedUpdate() - это грубо, но станет заметно легче :)
Потому уже код вылизывать...

2 BANNERTM
Ты используешь diff.sqrMagnitude - это квадрат расстояния, оно быстрее вычисляется - от того и дистанция 5000? ;)
Или тогда возведи его в квадрат ...


Fixed update немного помог, но мне для других скриптов fixed update тоже нужен и проверять нужно там намного чаще! А нельзя ли создать свой update?
BANNERTM
UNITрон
 
Сообщения: 241
Зарегистрирован: 26 фев 2012, 00:13

Re: Падение ФПС из-за скрипта турели)=

Сообщение DDDENISSS 11 июн 2012, 18:43

Что-то я не понял как FixedUpdate мог помочь? Ведь он чаще вызывается.
Лучше использовать Physics.OverlapSphere
А еще лучше if( Time.frameCount%3 == 0 ) Physics.OverlapSphere хотя это лучше по времени сделать.
И чем foreach хуже чем for?
Аватара пользователя
DDDENISSS
UNIверсал
 
Сообщения: 439
Зарегистрирован: 11 сен 2011, 20:33

Re: Падение ФПС из-за скрипта турели)=

Сообщение BANNERTM 11 июн 2012, 19:47

DDDENISSS писал(а):Что-то я не понял как FixedUpdate мог помочь? Ведь он чаще вызывается.
Лучше использовать Physics.OverlapSphere
А еще лучше if( Time.frameCount%3 == 0 ) Physics.OverlapSphere хотя это лучше по времени сделать.
И чем foreach хуже чем for?


А что делает Physics.OverLapSphere? Да я понял что он возвращает коллайдеры которые в попали в сферу! Но как пушка поймет какой коллайдер ближе?
BANNERTM
UNITрон
 
Сообщения: 241
Зарегистрирован: 26 фев 2012, 00:13

Re: Падение ФПС из-за скрипта турели)=

Сообщение DDDENISSS 11 июн 2012, 21:04

Physics.OverlapSphere возвращает объекты описывающие боксы, которых попали в сферу. Это будет максимально быстро.
Ближайший объект из них найти уже просто.
Аватара пользователя
DDDENISSS
UNIверсал
 
Сообщения: 439
Зарегистрирован: 11 сен 2011, 20:33

След.

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

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

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 8