Пятница, 26 Апреля 2024, 16:18

Приветствую Вас Гость

[ Новые сообщения · Игроделы · Правила · Поиск ]
  • Страница 1 из 2
  • 1
  • 2
  • »
Форум игроделов » Движки для разработки игр и сложные системы разработки » Unity » Прокачка персонажа / Повышение уровня
Прокачка персонажа / Повышение уровня
ArtemSДата: Вторник, 03 Октября 2017, 18:08 | Сообщение # 1
почетный гость
Сейчас нет на сайте
Товарищи, подскажите как сделать чтобы при гибели противник передавал переменную getXp (количество опыта) игровому контроллеру.

Имеется противник и игрок, игрок стреляет и убивает врага ..пробую через нул, но не получается через if (enemy1 == null).

Код

//переменные для опыта
    public int xp;
    int curXp = 0;
    int maxXp = 50;

    //переменные для уровня
    int lvl = 1;
    public int maxLvl = 10;

    public Slider slider;
    public EnemyHealth enemy1;

    void Awake () {

        //задаются значения слайдера
        slider.value = xp;
        slider.maxValue = maxXp;
    }

    void Update() {
        
        if (enemy1 == null)
        {
            curXp = enemy1.getXp;
            xp += curXp;                        
            slider.value = xp;
        }        
    }


хуяк, хуяк и в продакшн
afqДата: Вторник, 03 Октября 2017, 18:15 | Сообщение # 2
Разработчик
Сейчас нет на сайте
А ты enemy1 при смерти присваиваешь null?
ArtemSДата: Среда, 04 Октября 2017, 04:24 | Сообщение # 3
почетный гость
Сейчас нет на сайте
afq, нет. я думал он автоматически присваивается если объект уничтожается со сцены...

хуяк, хуяк и в продакшн
drcrackДата: Среда, 04 Октября 2017, 08:48 | Сообщение # 4
старожил
Сейчас нет на сайте
Цитата
afq, нет. я думал он автоматически присваивается если объект уничтожается со сцены...

все верно, == перегружен и сравнение c null возвращает true если обьект уничтожен через Destroy/DestroyImmediate
т.е. код должен работать (ну, за исключением той мелочи что он должен прибавлять экспу каждый кадр после убийства врага)
ищи ошибку в логике, в других скриптах, покажи для начала тот где уничтожается враг


Сообщение отредактировал drcrack - Среда, 04 Октября 2017, 09:30
CleverRusДата: Среда, 04 Октября 2017, 09:31 | Сообщение # 5
почетный гость
Сейчас нет на сайте
Прописать в классе врага условие его смерти и установить булевую переменную, а в апдейте прокачки ставишь условие с этой булевой переменной.
HerrPotapovДата: Среда, 04 Октября 2017, 13:28 | Сообщение # 6
заслуженный участник
Сейчас нет на сайте
ArtemS, и никого не смутило, что сначала мы убеждаемся, что enemy == null, а в следующей же строке пытаемся вызвать метод на enemy (который вообще-то null)
Очень криво с точки зрения архитектуры. Либо пиши GameController и метод в нем который будет вызываться врагом при смерти и начислять экспу игроку, либо в методе смерти у врага проверяй кто его убил и если это игрок - начисляй экспу


Discord: alpotapov#1741

Интервью с разработчиком WarCastle - Читаем и вникаем!
afqДата: Среда, 04 Октября 2017, 13:58 | Сообщение # 7
Разработчик
Сейчас нет на сайте
HerrPotapov,
Цитата
а в следующей же строке пытаемся вызвать метод на enemy (который вообще-то null)

Да точно. xp так не начислится.
ArtemS, сделай в текущем классе функция начисления xp, а enemy1 дай ссылку на твой класс, и когда enemy1 будет уничтожатся, пусть он вызовет функция начисления xp.
drcrackДата: Среда, 04 Октября 2017, 15:01 | Сообщение # 8
старожил
Сейчас нет на сайте
Цитата
ArtemS, и никого не смутило, что сначала мы убеждаемся, что enemy == null, а в следующей же строке пытаемся вызвать метод на enemy (который вообще-то null)

Цитата
Да точно. xp так не начислится.

Это не тот null, который null. Тут перегруженный == который возвращает true при сравнении с null если обьект разрушен. Но при этом как обьект C# он все еще существует и ты можешь делать с ним все что ты в принципе можешь делать с обьектом (кроме того что унаследовано от классов юнити, все эти вещи будут бросать исключение), например прочитать значение поля (вызова метода тут кстати не вижу)


Сообщение отредактировал drcrack - Среда, 04 Октября 2017, 15:03
ArtemSДата: Среда, 04 Октября 2017, 18:42 | Сообщение # 9
почетный гость
Сейчас нет на сайте
drcrack, сделал чтобы curXP лишь раз была больше 0, и после сложения вновь 0 становилась.
Код

curXp = enemy1.GetComponent<EnemyHealth>().getXp;
xp += curXp;                        
slider.value = xp;
curXp = 0;            


Код

//блок с переменными не показываю ибо их дохрена и они сейчасне нужны

public int getXp = 10;

//не стал писать код где взаимодействие с триггерами и коллизиями а лишь интересующую часть показываю

if (health <= 0)
            {
                Death();                
            }

public void Death()
    {       
        Destroy(gameObject);
        Destroy(slider);                    
    }


afq, честно так и не понял как присвоить gameObject = null;...можешь пояснить ?

CleverRus, попробывал...добавил в метот Death() bool die = true. И уже в скрипте на ХР прописал if (enemy1.GetComponent<EnemyHealth>().die == true), но у меня все равно нечего не работает.

Код

public void Death()
    {
        die = true;
        Destroy(gameObject);
        Destroy(slider);                      
    }


и сделал проверку в скрипте на игроке

Код

void Update() {
        
        if (enemy1.GetComponent<EnemyHealth>().die == true)
        {
            GetExp();
            Debug.Log(enemy1.GetComponent<EnemyHealth>().die);
            xp += curXp;                        
            slider.value = xp;
            curXp = 0;
            Debug.Log(enemy1.GetComponent<EnemyHealth>().die);
        }        
    }

    public void GetExp()
    {
        curXp = enemy1.GetComponent<EnemyHealth>().getXp;
        enemy1.GetComponent<EnemyHealth>().die = false;
    }


HerrPotapov, у меня проблема в том, что в update у скрипта не проходит if.


хуяк, хуяк и в продакшн
drcrackДата: Среда, 04 Октября 2017, 18:54 | Сообщение # 10
старожил
Сейчас нет на сайте
После
Код
Destroy(gameObject);

Вот это уже не будет работать:
Код
enemy1.GetComponent<EnemyHealth>()

Может поэтому и "не проходит if"

А вообще как уже сказали, все очень криво и лучше все это удалить и сделать с нуля нормально
Ну или хотя бы скинь проект целиком, по отрывкам скриптов сложно понять че там у тебя происходит
afqДата: Среда, 04 Октября 2017, 19:24 | Сообщение # 11
Разработчик
Сейчас нет на сайте
ArtemS, ты указал что будет класс
Код

    public EnemyHealth enemy1;

Я имел ввиду, что ты классу присвоишь null, когда нужно. Я наверное не то подумал. Ты же к объекту класс привязываешь. Тогда, прежде чем удалить объект, сделай то что нужно ( присвоение xp ), а потом удаляй объект.

У тебя enemy1 объект чтоли, раз ты хочешь компонент класса получить?

Я вообще не пойму как ты сделал, ты что, на том же объекте, который будет уничтожатся, решил присвоить xp, а кому?

Попробуй так.
Код

/* указатель на объект */
GameObject enemy;
/* указатель на класс */
EnemyHealth enemy1;

void Start ( )
{
  enemy = GameObject.Find ( "название объекта, который расположен в списке слева" );
  enemy1 = enemy.GetComponent<EnemyHealth>();
  ...
  /* создай отдельный поток, чтобы он проверялся не в кадре, а в потоке, так он не будет замедлять покадровое обновление */
StartCoroutine ( wa () );
}
IEnumerator wa ( )
{
  while ( true ) {
  /* здесь проверяй, умер ли объект */
  if ( enemy1.die == true ) {
    totalxp += enemy1.xp;
  /* после присвоения, удаляй объкт */
   DestroyObject ( enemy );
  /* если, проверить только один объект, то добавь break, иначе обходись без break и меняй так,
      чтобы разных можно было бы убить. Когда не нужно больше проверять, напиши
      StopCoroutine ( wa () );
  break;
  }
  yield return null;
  }
}

Значит в классе, в том, который к объекту приклеплен, устанавливаешь public bool die в true, когда нужно и всё.

Надеюсь это поможет.

Ещё предлагаю почитать книгу "Искусство создания сценариев в Unity", вдруг пригодится.

Добавлено (04 октября 2017, 19:23)
---------------------------------------------
Я отредактировал сообщение, добавил
Код

   DestroyObject ( enemy );


Добавлено (04 октября 2017, 19:23)
---------------------------------------------
Это было сделано с учётом одного врага, чтобы было легче увидеть все.

Добавлено (04 октября 2017, 19:24)
---------------------------------------------
еще добавил в StartCoroutine. ( забыл )
Код

  yield return null;


Сообщение отредактировал afq - Четверг, 05 Октября 2017, 07:19
drcrackДата: Среда, 04 Октября 2017, 20:32 | Сообщение # 12
старожил
Сейчас нет на сайте
Код
/* указатель на объект */
GameObject enemy;
/* указатель на класс */
EnemyHealth enemy1;

и то и другое — ссылки на обьекты

Код
/* создай отдельный поток, чтобы он проверялся не в кадре, а в потоке, так он не будет замедлять покадровое обновление */
StartCoroutine ( wa () );

корутины работают в основном потоке, эта оптимизация бессмысленна, она ничего не ускорит
кроме того, она никогда не завершится и будет добавлять экспу каждый кадр после смерти врага
точнее, даже не добавлять а изменять общее количество опыта игрока на то, которое дается за одного этого врага

Код
Ещё предлагаю почитать книгу "Искусство создания сценариев в Unity", вдруг пригодится.

если эта книжка и вдохновила тебя на эти корявые примеры, ее лучше не читать ))

тсу лучше скинуть проект целиком, только так можно будет понять где проблема

PS
Код
enemy1.die

Это свойство должно называться isDead


Сообщение отредактировал drcrack - Среда, 04 Октября 2017, 20:36
afqДата: Среда, 04 Октября 2017, 21:09 | Сообщение # 13
Разработчик
Сейчас нет на сайте
drcrack,
Цитата
кроме того, она никогда не завершится
.
Я не ошибся, она же даже не в while? Выполнится один раз и все.
Цитата

totalxp = enemy1.xp;

Да, не подумал. Бывает, и о чем я думал.
Цитата
если эта книжка и вдохновила тебя на эти корявые примеры, ее лучше не читать ))

Я ее когда читал, не все понимал, потому как и c# плохо знал и все еще наверное многого незнаю. Но там написано то, что если мне понадобиться, я знаю точно, что там есть это, и когда нужно будет, прочту может быть вновь. Это не тоже самое, что читать
комментарии. Там любое предложение что-то значит.

Цитата
Это свойство должно называться isDead

Почему так? Потому что логично?

Цитата
и то и другое — ссылки на обьекты

А что, EnemyHealth разве не класс? Я думал что это класс, который прикреплен к объекту.

А отредактировал то сообщение.

Вот он например в Update поставил debug.log, это тоже лучше в IEnumerator coroutine делать. В книге той, которую я приводил в пример советовалось не производить вычисления в update, в update например делать мелкие вычисления. Также не забывал о свойствах, которые выполняются как события если то или иное присвоено, такое тоже можно в update, все равно, уже не в update будет выполнятся.


Сообщение отредактировал afq - Четверг, 05 Октября 2017, 07:20
drcrackДата: Среда, 04 Октября 2017, 21:44 | Сообщение # 14
старожил
Сейчас нет на сайте
Цитата
А что, EnemyHealth разве не класс? Я думал что это класс, который прикреплен к объекту.

https://msdn.microsoft.com/ru-ru/library/ey4ke239(v=vs.90).aspx

Цитата
Почему так? Потому что логично?

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

Цитата
А отредактировал то сообщение.

да, теперь вообще полная дичь)

Цитата
В книге той, которую я приводил в пример советовалось не производить вычисления в update, в update например делать мелкие вычисления.

все скрипты, включая корутины, выполняются в одном потоке и нет никакой разницы, в update они или где-то еще, тяжелые вычисления каждый кадр в любом случае будут просаживать фпс
кроме того, все обьекты юнити бросают исключения при попытке сделать с ними что-то из других потоков, даже банально Time.time ты прочитать не сможешь если вручную создашь второй поток
afqДата: Среда, 04 Октября 2017, 21:53 | Сообщение # 15
Разработчик
Сейчас нет на сайте
drcrack, так это что получается, EnemyHealt на gui рисуется, или что это за объект? Не пойму вообще. Ладно. Потом пойму.

Добавлено (04 октября 2017, 21:52)
---------------------------------------------
drcrack, так ты мне ссылку на классы дал. Я под объекты подразумевал только объекты unity3d.

Цитата
да, теперь вообще полная дичь)

смешно.

Цитата
в update они или где-то еще, тяжелые вычисления каждый кадр в любом случае будут просаживать фпс

Поэтому чтобы вычисления не производит в кадре, делают в IEnumerator coroutine, в такое случае уже не в кадре будут вычисляться, и не будет нагрузки на fps.

Добавлено (04 октября 2017, 21:53)
---------------------------------------------
drcrack, может тебе тоже стоит книжку почитать? Или ты считаешь себя умнее автора?


Сообщение отредактировал afq - Четверг, 05 Октября 2017, 07:20
drcrackДата: Среда, 04 Октября 2017, 22:02 | Сообщение # 16
старожил
Сейчас нет на сайте
Цитата
Поэтому чтобы вычисления не производит в кадре, делают в ienumerable, в такое случае уже не в кадре будут вычисляться, и не будет нагрузки на fps.

то что ты написал (yield return null внутри while) будет выполняться каждый кадр после всех Update и влиять на фпс точно также как влияло бы, если бы было написано в Update
и дело не в том, что ты как-то плохо написал (это самый обычный паттерн), просто по-другому не получится) если тебе нужно что-то делать каждый кадр, то придется делать это каждый кадр, в Update, в корутине или еще каким-то способом

иначе можно было бы вообще весь код перенести в корутины, убрать апдейты и было бы 500 фпс всегда

Цитата
Или ты считаешь себя умнее автора?

автор мог написать все правильно, а вот ты мог просто не до конца понять что именно он хотел сказать

скачал книгу, автор все верно пишет:

то что я выделил как раз включает в себя корутины
в конце также сказано, что нужно делать: использовать события
и это как раз будет очень в тему: умирает моб — вызываются колбеки — начисляется экспа, и не надо ничего проверять в каждом кадре


Сообщение отредактировал drcrack - Среда, 04 Октября 2017, 22:20
afqДата: Четверг, 05 Октября 2017, 06:59 | Сообщение # 17
Разработчик
Сейчас нет на сайте
drcrack, а где написано тогда, что в coroutine замедляет кадр, если к кадрам относится например update и т.д. Я помню, где-то в книге об этом читал.

Вот смотри.
click

Особенно строку прочти.
Цитата
. Корутины - прекрасное средство когда моделируется поведение, растянутое на несколько кадров.

Так что это выполняется не каждый кадр, а не зависимо от кадров.
drcrackДата: Четверг, 05 Октября 2017, 09:28 | Сообщение # 18
старожил
Сейчас нет на сайте
Добавь скрипт на сцену и наслаждайся: https://pastebin.com/sepRCmvy
(Если недостаточно сильно лагает, добавь еще один 0 в кол-во итераций, я под свой слабый проц на ноуте делал)
А потом подумай, как так получается, ведь в скрипте нету Update
afqДата: Четверг, 05 Октября 2017, 09:57 | Сообщение # 19
Разработчик
Сейчас нет на сайте
drcrack, я может потом посмотрю. А что, в update если этот цикл вставишь, не будет тормозить? Вот такой
Код


            for (var i = 0; i < 10000000; i++) {
                x = Mathf.Sqrt(x);
            }

        

А что если сделать так?
Код

  IEnumerator Slow() {

        var x = float.MaxValue;

        while (true) {

            for (var i = 0; i < 10000000; i++) {
                x = Mathf.Sqrt(x);
                yield return null;
            }

            yield return null;
        }

    }

Можешь проверить, будет лагать?


Сообщение отредактировал afq - Четверг, 05 Октября 2017, 09:59
ArtemSДата: Четверг, 05 Октября 2017, 17:58 | Сообщение # 20
почетный гость
Сейчас нет на сайте
drcrack, afq, все я решил проблему. Беда в том что у меня несколько объектов на сцене и нужно было у каждого проверку делать) а я ж и не знал)))))
Код

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class PlayerExp : MonoBehaviour {

    //переменные для опыта
    public int xp;
    int curXp = 0;
    int maxXp = 50;

    //переменные для уровня
    int lvl = 1;
    public int maxLvl = 10;

    public Slider slider;
    public EnemyHealth enemy1;

    void Awake () {

        //задаются значения слайдера
        slider.value = xp;
        slider.maxValue = maxXp;
    }

    void Update() {

        GameObject[] enemy = GameObject.FindGameObjectsWithTag("Enemy");
        
        foreach (GameObject tr in enemy)
        {
            enemy1 = tr.GetComponent<EnemyHealth>();
            if (enemy1.die == true) enemy1Death();
        }

        
      
           
    }

    public void enemy1Death()
    {
        Destroy(enemy1.gameObject);
        curXp = enemy1.getXp;
        xp += curXp;
        slider.value = xp;
        curXp = 0;
    }
}


хуяк, хуяк и в продакшн

Сообщение отредактировал ArtemS - Четверг, 05 Октября 2017, 18:22
Форум игроделов » Движки для разработки игр и сложные системы разработки » Unity » Прокачка персонажа / Повышение уровня
  • Страница 1 из 2
  • 1
  • 2
  • »
Поиск:

Все права сохранены. GcUp.ru © 2008-2024 Рейтинг