Воскресенье, 22 Декабря 2024, 10:36

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

[ Новые сообщения · Игроделы · Правила · Поиск ]
  • Страница 1 из 1
  • 1
Проблема с Unity
SkorpyXДата: Вторник, 03 Ноября 2015, 23:18 | Сообщение # 1
участник
Сейчас нет на сайте
Здравствуйте! Я написал ИИ для зомби, который вроде бы работает, но есть одна ошибка в коде, которую я не могу найти и исправить. Есть префаб зомби, у которого есть триггер, при входе в который, состояние зомби меняется на активное, а состояние mechanim меняется на "Run", если игрок появляется вне триггера, то всё работает нормально, но если игра начинается тогда, когда игрок уже находится в триггере, то анимации назначаются неправильно (вместо анимации бега проигрывается анимация сна, скорее всего я напутал с присвоением триггеров). Пожалуйста, помогите мне, я переписал код полностью несколько раз, но ошибка осталась.
Прилагаю сам js код, скриншот mechanim и видео ошибки:
Код

#pragma strict

enum ZombieState { Active, Inactive };
var state : ZombieState = ZombieState.Inactive;

@Header("Настройки зомби")
var hp : float = 100;
var zombieDeadPrefab : GameObject;
@Space(8)
var armLength : float = 1.5;
var radius : float = 16;
var detectionTreshold : float = 1;
var maxInterest : float = 15;

// Локальные переменные
private var target : Transform;
private var interest : float;

private var agent : NavMeshAgent;
private var animator : Animator;
private var head : Transform;

private var canAttack : boolean = true;

function Start () {
    // Базовая настройка
    agent = GetComponent.<NavMeshAgent>();
    animator = GetComponent.<Animator>();
    head = transform.Find("Armature/Spin/Head");
    
    animator.SetInteger("Run ID", Random.Range(0, 2));
    animator.SetTrigger("Sleep");
}

function Update () {
    StateMachine();
    
    if ((Input.GetKeyDown("e")) || (MobileInput.GetButtonDown("Jump"))) Die();
}

function StateMachine () {
    switch (state) {
     case ZombieState.Active :
      ActiveState();
      break;
  case ZombieState.Inactive :
   InactiveState();
   break;
    }
}

function ActiveState () {
    if (Vector3.Distance(transform.position, target.position) > radius) {
  GoToSleep();
  return;
    }
    
    switch (target.tag) {
  case "Player" :
   RunToTarget();
   AttackTarget();
   break;
  default :
   if (interest <= 0) {
    GoToSleep();
    return;
   }
   
   interest -= Time.deltaTime;
   RunToTarget();
   break;
    }
}

function InactiveState () {
    
}

function GoToSleep () {
    target = null;
    interest = 0;
    agent.ResetPath();
    animator.SetTrigger("Sleep");
    state = ZombieState.Inactive;
}

function SetTarget (tg : Transform) {
    target = tg;
    if (state != ZombieState.Active) animator.SetTrigger("Run");
    state = ZombieState.Active;
}

function RunToTarget () {
    agent.SetDestination(target.position);
    animator.SetFloat("Blend", agent.velocity.magnitude / agent.speed);
}

function AttackTarget () {
    if ((Vector3.Distance(transform.position, target.position) <= armLength) && (canAttack)) {
  animator.SetInteger("Attack ID", Random.Range(0, 3));
  animator.SetTrigger("Attack");
  canAttack = false;
    }
}

function SetCanAttack () {
    canAttack = true;
}

function Hit () {
    if (target == null) return;
}

function Die () {
    var dead : ZombieDead = Instantiate(zombieDeadPrefab, transform.position, transform.rotation).GetComponent.<ZombieDead>();
    
    dead.zombie = transform;
    dead.zombieMaterial = GetComponentInChildren.<SkinnedMeshRenderer>().sharedMaterial;
    dead.zombieVelocity = agent.velocity;
    dead.SetupMyself();
    
    Destroy(gameObject);
}

function OnTriggerEnter (other : Collider) {
    if ((state == ZombieState.Active) && (target.tag == "Player")) return;
    
    if (other.tag == "Player") {
  SetTarget(other.transform);
  return;
    }
    
    if (other.attachedRigidbody == null) return;
    if (other.attachedRigidbody.velocity.magnitude < detectionTreshold) return;
    
    if (target == null) {
  SetTarget(other.transform);
  interest = maxInterest;
    }
    
    if (other.attachedRigidbody.velocity.magnitude < target.GetComponent.<Rigidbody>().velocity.magnitude) return;
    
    SetTarget(other.transform);
    interest = maxInterest;
}


Видео в процессе загрузки...

Добавлено (03 ноября 2015, 23:18)
---------------------------------------------
Добавил видео (модель зомби не украдена с Unturned :D):


Сообщение отредактировал SkorpyX - Вторник, 03 Ноября 2015, 23:25
KamiRoninДата: Вторник, 03 Ноября 2015, 23:37 | Сообщение # 2
почти ветеран
Сейчас нет на сайте
Возможно событие OnTriggerEnter в проблемном случае происходит у тебя на таком этапе инициализации зомби, что получается такой результат.

попробуй задействовать OnTriggerStay с дополнительными условиями срабатывания в нем..
задействуй отладку - нужно выявить с какими состояниями и переменными попадает зомби в коллайдер..


Мыслю - значит программирую...
Конструктивная критика - умных ведет к совершенству...
Великие умы обсуждают идеи, средние - обсуждают поступки, а малые - людей.


Сообщение отредактировал KamiRonin - Среда, 04 Ноября 2015, 08:20
SkorpyXДата: Среда, 04 Ноября 2015, 00:09 | Сообщение # 3
участник
Сейчас нет на сайте
KamiRonin, спасибо за ответ! Мне начинает казаться, что это баг Unity. Я проводил тест с Debug.Log, в ходе которого выясил, что сначала идёт событие старта, а потом триггера, но когда задействуется аниматор, то происходит такая штука:
Как правильно:
Код
Start {
animator.SetTrigger("Sleep");
}

OnTriggerEnter {
animator.SetTrigger("Run");
}

Как происходит:
Start {
OnTriggerEnter {
animator.SetTrigger("Run");
}

animator.SetTrigger("Sleep");
}

Получается, что событие триггера происходит как бы в середине события старта, такое вообще возможно?

Добавлено (04 ноября 2015, 00:03)
---------------------------------------------
В старте ведь я присваивал Sleep, а во время входа в триггер выводит Idle. Возможно я понял в чём дело...

Добавлено (04 ноября 2015, 00:08)
---------------------------------------------
Действительно! Если я правильно понял, то она возникает из за того, что OnTriggerEnter вызывается во время перехода между Idle и Sleep, который длится 0.1 секунду.

Добавлено (04 ноября 2015, 00:09)
---------------------------------------------
Так и есть, решением оказалось присвоение Sleep статуса начального состояния (до этого был Idle).
dzrone3488Дата: Суббота, 07 Ноября 2015, 03:53 | Сообщение # 4
участник
Сейчас нет на сайте
Я бы вместо триггера использовал Vector3.Distance. Меньше запар

Я делаю игры, а вы в них играете! :)
Моя группа по созданию игр - www.vk.com/dzrone

SkorpyXДата: Суббота, 07 Ноября 2015, 17:52 | Сообщение # 5
участник
Сейчас нет на сайте
dzrone3488, мой скрипт подразумевает, что целью может быть не только игрок, но и любой объект с Rigidbody и амплитудой скорости больше detectionTreshold, что и показано на видео

Сообщение отредактировал SkorpyX - Суббота, 07 Ноября 2015, 20:33
  • Страница 1 из 1
  • 1
Поиск:

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