Problema com AI
4 participantes
Página 1 de 1
Problema com AI
Pessoal, estou escrevendo um script de AI para os meus inimigos e estou com um problema.
Quando o player dispara os inimigos se deslocam para os esconderijos mais próximos. Eu queria que dois inimigos não ocupassem o mesmo local ao mesmo tempo. Sou iniciante em programação e não faço ideia de como fazer isso. Se alguém puder me ajudar ou indicar algum tutorial para isso eu agradeceria muito.
Esse é o meu script
Quando o player dispara os inimigos se deslocam para os esconderijos mais próximos. Eu queria que dois inimigos não ocupassem o mesmo local ao mesmo tempo. Sou iniciante em programação e não faço ideia de como fazer isso. Se alguém puder me ajudar ou indicar algum tutorial para isso eu agradeceria muito.
Esse é o meu script
- Código:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
[RequireComponent(typeof(AudioSource))]
public class Enemies : MonoBehaviour
{
public enum Status
{
Patrol,
AttackPlayer,
Idle,
Dead
};
Status enemiesStatus = Status.Patrol;
public GameObject dropAmmoCanvas;
private GameObject player;
public AudioClip shoot;
AudioSource gun;
public float speed;
private float waitTime;
public float startWaitTime;
public List<Transform> moveSpots;
public List<Transform> hideSpots;
private int randomSpot;
public int nearestHideSpotIndex = 0;
private bool canAttack = true;
private bool playerIsShooting = false;
public bool isDead = false;
private int minDam = 0;
private int maxDam = 8;
private int minFrequency = 3;
private int maxFrequency = 6;
private int minDroppedAmmo = 0;
private int maxDroppedAmmo = 10;
public int droppedAmmo;
void Start()
{
player = GameObject.FindWithTag("Player");
gun = GetComponent<AudioSource>();
waitTime = startWaitTime;
randomSpot = Random.Range(0, moveSpots.Count);
}
void Update()
{
switch (enemiesStatus)
{
case Status.AttackPlayer:
CheckNearestHideSpot();
transform.position = Vector2.MoveTowards(transform.position, hideSpots[nearestHideSpotIndex].position, speed * Time.deltaTime);
Attack();
break;
case Status.Patrol:
transform.position = Vector2.MoveTowards(transform.position, moveSpots[randomSpot].position, speed * Time.deltaTime);
if (Vector2.Distance(transform.position, moveSpots[randomSpot].position) < 0.2f)
{
if (waitTime <= 0)
{
randomSpot = Random.Range(0, moveSpots.Count);
waitTime = startWaitTime;
}
else
{
waitTime -= Time.deltaTime;
}
}
break;
case Status.Idle:
StopAllCoroutines();
break;
case Status.Dead:
StopAllCoroutines();
GetComponent<Animator>().SetBool("died", true);
droppedAmmo = Random.Range(minDroppedAmmo, maxDroppedAmmo);
if(dropAmmoCanvas != null && droppedAmmo > 0)
{
dropAmmoCanvas.gameObject.SetActive(true);
}
break;
}
if(Input.GetMouseButtonDown(0) && player.GetComponent<Weapon>().isReloading == false && player.GetComponent<Weapon>().isDryFire == false && !EventSystem.current.IsPointerOverGameObject())
{
if (player.GetComponent<Player>().life > 0)
{
playerIsShooting = true;
}
}
if (playerIsShooting && player.GetComponent<Player>().life > 0)
{
enemiesStatus = Status.AttackPlayer;
}
if (player.GetComponent<Player>().life <= 0)
{
enemiesStatus = Status.Idle;
}
if (isDead)
{
enemiesStatus = Status.Dead;
}
}
void Attack()
{
if (canAttack && playerIsShooting)
{
StartCoroutine(Attacking());
}
}
void CheckNearestHideSpot()
{
float maxDistance = 99999999999999999;
for (int x = 0; x < hideSpots.Count; x++)
{
float actualHideSpotDistance = Vector2.Distance(transform.position, hideSpots[x].transform.position);
if (actualHideSpotDistance < maxDistance)
{
maxDistance = actualHideSpotDistance;
nearestHideSpotIndex = x;
}
}
}
IEnumerator Attacking()
{
canAttack = false;
yield return new WaitForSeconds(Random.Range(minFrequency, maxFrequency));
gun.PlayOneShot(shoot,0.4f);
player.GetComponent<Player>().life -= Random.Range(minDam, maxDam);
canAttack = true;
}
}
abraao36- Membro
- PONTOS : 2019
REPUTAÇÃO : 5
Respeito as regras :
Re: Problema com AI
Você Pode Fazer o Npc lançar um Raycast no lugar onde ele esta indo, caso do Hit colidir com algum outro Npc neste local, Ele vai para outro esconderijo.
Você Tambem poderia verificar Qual Lugar irá ser ocupado, exemplo:
Este Método "CheckNearestHideSpot()" Define para onde o npc vai.
- Crie booleanas a Quantidade depende de quantos lugares ele pode se esconder.
(vamos supor que os Npc só possa se esconder em 5 lugares).
- Então Irei Criar um vetor do tipo bool com 5 posições -> private bool[] LugarOcupado = new bool[5];
- Agora é só Verificar se o Lugar Escolhido está ocupado, Caso Não esteja o npc pode ir para lá:
Caso o Npc Morra é só fazer o seu lugar ficar desocupado.
Você Tambem poderia verificar Qual Lugar irá ser ocupado, exemplo:
Este Método "CheckNearestHideSpot()" Define para onde o npc vai.
- Crie booleanas a Quantidade depende de quantos lugares ele pode se esconder.
(vamos supor que os Npc só possa se esconder em 5 lugares).
- Então Irei Criar um vetor do tipo bool com 5 posições -> private bool[] LugarOcupado = new bool[5];
- Agora é só Verificar se o Lugar Escolhido está ocupado, Caso Não esteja o npc pode ir para lá:
- Código:
void CheckNearestHideSpot()
{
float maxDistance = 99999999999999999;
for (int x = 0; x < hideSpots.Count; x++)
{
float actualHideSpotDistance = Vector2.Distance(transform.position, hideSpots[x].transform.position);
if (actualHideSpotDistance < maxDistance && !LugarOcupado[x])
{
maxDistance = actualHideSpotDistance;
LugarOcupado[x] = true;
nearestHideSpotIndex = x;
}
}
}
Caso o Npc Morra é só fazer o seu lugar ficar desocupado.
- Código:
case Status.Dead:
StopAllCoroutines();
GetComponent<Animator>().SetBool("died", true);
droppedAmmo = Random.Range(minDroppedAmmo, maxDroppedAmmo);
if(dropAmmoCanvas != null && droppedAmmo > 0)
{
dropAmmoCanvas.gameObject.SetActive(true);
}
LugarOcupado[nearestHideSpotIndex] = false;
break;
Magnatah- Instrutor
- PONTOS : 3549
REPUTAÇÃO : 209
Idade : 24
Áreas de atuação : Dєรєиvσlvєdσя Wєb(Fяσит-єиd), Blєиdєя, υиiтy, C#, ρнρ є Jαvαรcяiρт.
Respeito as regras :
Re: Problema com AI
Não deu certo. Tentei com os seus códigos e não mudou nada. Eles continuavam ocupando o mesmo local e não dava nenhum erro. Depois tentei com o Raycast e também não mudou nada kkk. Por fim fiz isso aqui
Coloquei esse script nos hidespots.
E fiz essa modificação na void CheckNearestHideSpot:
Agora está acusando esse erro toda vez que os inimigos tentam ocupar o mesmo local, mas acho que foi o mais perto que chegou de dar certo kkkk.
NullReferenceException: Object reference not set to an instance of an object
Enemies.CheckNearestHideSpot () (at Assets/Scripts/Enemies.cs:153)
Enemies.Update () (at Assets/Scripts/Enemies.cs:63)
Coloquei esse script nos hidespots.
- Código:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HideSpots : MonoBehaviour
{
private GameObject soldier;
public bool estaOcupado = false;
void Start()
{
soldier = GameObject.FindWithTag("Soldier");
}
void Update()
{
if(Vector2.Distance(transform.position, soldier.transform.position) < 0.02f)
{
estaOcupado = true;
}
}
}
E fiz essa modificação na void CheckNearestHideSpot:
- Código:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
[RequireComponent(typeof(AudioSource))]
public class Enemies : MonoBehaviour
{
public enum Status
{
Patrol,
AttackPlayer,
Idle,
Dead
};
Status enemiesStatus = Status.Patrol;
public GameObject dropAmmoCanvas;
private GameObject player;
public AudioClip shoot;
AudioSource gun;
public float speed;
private float waitTime;
public float startWaitTime;
public List<Transform> moveSpots;
public List<Transform> hideSpots;
private int randomSpot;
public int nearestHideSpotIndex = 0;
private bool canAttack = true;
private bool playerIsShooting = false;
public bool isDead = false;
private int minDam = 0;
private int maxDam = 8;
private int minFrequency = 3;
private int maxFrequency = 6;
private int minDroppedAmmo = 0;
private int maxDroppedAmmo = 10;
public int droppedAmmo;
void Start()
{
player = GameObject.FindWithTag("Player");
gun = GetComponent<AudioSource>();
waitTime = startWaitTime;
randomSpot = Random.Range(0, moveSpots.Count);
}
void Update()
{
switch (enemiesStatus)
{
case Status.AttackPlayer:
CheckNearestHideSpot();
transform.position = Vector2.MoveTowards(transform.position, hideSpots[nearestHideSpotIndex].position, speed * Time.deltaTime);
Attack();
break;
case Status.Patrol:
transform.position = Vector2.MoveTowards(transform.position, moveSpots[randomSpot].position, speed * Time.deltaTime);
if (Vector2.Distance(transform.position, moveSpots[randomSpot].position) < 0.2f)
{
if (waitTime <= 0)
{
randomSpot = Random.Range(0, moveSpots.Count);
waitTime = startWaitTime;
}
else
{
waitTime -= Time.deltaTime;
}
}
break;
case Status.Idle:
StopAllCoroutines();
break;
case Status.Dead:
StopAllCoroutines();
GetComponent<Animator>().SetBool("died", true);
droppedAmmo = Random.Range(minDroppedAmmo, maxDroppedAmmo);
if(dropAmmoCanvas != null && droppedAmmo > 0)
{
dropAmmoCanvas.gameObject.SetActive(true);
}
break;
}
if(Input.GetMouseButtonDown(0) && player.GetComponent<Weapon>().isReloading == false && player.GetComponent<Weapon>().isDryFire == false && !EventSystem.current.IsPointerOverGameObject())
{
if (player.GetComponent<Player>().life > 0)
{
playerIsShooting = true;
}
}
if (playerIsShooting && player.GetComponent<Player>().life > 0)
{
enemiesStatus = Status.AttackPlayer;
}
if (player.GetComponent<Player>().life <= 0)
{
enemiesStatus = Status.Idle;
}
if (isDead)
{
enemiesStatus = Status.Dead;
}
}
void Attack()
{
if (canAttack && playerIsShooting)
{
StartCoroutine(Attacking());
}
}
void CheckNearestHideSpot()
{
float maxDistance = 99999999999999999;
for (int x = 0; x < hideSpots.Count; x++)
{
float actualHideSpotDistance = Vector2.Distance(transform.position, hideSpots[x].transform.position);
if (actualHideSpotDistance < maxDistance)
{
maxDistance = actualHideSpotDistance;
nearestHideSpotIndex = x;
RaycastHit hit;
if(Physics.Raycast(transform.position, hideSpots[nearestHideSpotIndex].position, out hit, 500))
{
if (hit.transform.gameObject.GetComponent<HideSpots>().estaOcupado)
{
nearestHideSpotIndex++;
}
else if (hit.transform.gameObject.GetComponent<HideSpots>().estaOcupado == false)
{
nearestHideSpotIndex = x;
}
}
}
}
}
IEnumerator Attacking()
{
canAttack = false;
yield return new WaitForSeconds(Random.Range(minFrequency, maxFrequency));
gun.PlayOneShot(shoot,0.4f);
player.GetComponent<Player>().life -= Random.Range(minDam, maxDam);
canAttack = true;
}
}
Agora está acusando esse erro toda vez que os inimigos tentam ocupar o mesmo local, mas acho que foi o mais perto que chegou de dar certo kkkk.
NullReferenceException: Object reference not set to an instance of an object
Enemies.CheckNearestHideSpot () (at Assets/Scripts/Enemies.cs:153)
Enemies.Update () (at Assets/Scripts/Enemies.cs:63)
abraao36- Membro
- PONTOS : 2019
REPUTAÇÃO : 5
Respeito as regras :
Re: Problema com AI
- Então Irei Criar um vetor do tipo bool com 5 posições -> private bool[] LugarOcupado = new bool[5];
ffabim- MembroAvançado
- PONTOS : 3356
REPUTAÇÃO : 69
Respeito as regras :
Re: Problema com AI
eu sei que é obvio, mas verifique se o algum hideSpots está sem o script "HideSpots".
Magnatah- Instrutor
- PONTOS : 3549
REPUTAÇÃO : 209
Idade : 24
Áreas de atuação : Dєรєиvσlvєdσя Wєb(Fяσит-єиd), Blєиdєя, υиiтy, C#, ρнρ є Jαvαรcяiρт.
Respeito as regras :
Re: Problema com AI
Fiz essa etapa.ffabim escreveu:- Então Irei Criar um vetor do tipo bool com 5 posições -> private bool[] LugarOcupado = new bool[5];
abraao36- Membro
- PONTOS : 2019
REPUTAÇÃO : 5
Respeito as regras :
Re: Problema com AI
Verifiquei. Todos estão com o script.Magnatah escreveu:eu sei que é obvio, mas verifique se o algum hideSpots está sem o script "[size=39]HideSpots".[/size]
abraao36- Membro
- PONTOS : 2019
REPUTAÇÃO : 5
Respeito as regras :
Re: Problema com AI
Faz esse tipo de verificação no Raycast:
Os hideSpots Tem que Star com o nome "HideSpots"
Os hideSpots Tem que Star com o nome "HideSpots"
- Código:
if (Physics.Raycast(transform.position, hideSpots[nearestHideSpotIndex].position, out hit, 500))
{
if (hit.transform.gameObject.name == "HideSpots")
{
if (hit.transform.gameObject.GetComponent<HideSpots>().estaOcupado)
{
nearestHideSpotIndex++;
}
else if (hit.transform.gameObject.GetComponent<HideSpots>().estaOcupado == false)
{
nearestHideSpotIndex = x;
}
}
}
Magnatah- Instrutor
- PONTOS : 3549
REPUTAÇÃO : 209
Idade : 24
Áreas de atuação : Dєรєиvσlvєdσя Wєb(Fяσит-єиd), Blєиdєя, υиiтy, C#, ρнρ є Jαvαรcяiρт.
Respeito as regras :
Re: Problema com AI
O erro sumiu mas voltaram a ocupar o mesmo local. Deixei a bool "estaOcupado" ativa em um dos hidespots e o inimigo foi para ela do mesmo jeito.
abraao36- Membro
- PONTOS : 2019
REPUTAÇÃO : 5
Respeito as regras :
Re: Problema com AI
deve ser por causa da linha 149. Remove Ela
"nearestHideSpotIndex = x;"
"nearestHideSpotIndex = x;"
Última edição por Magnatah em Qui Jul 25, 2019 10:11 pm, editado 1 vez(es)
Magnatah- Instrutor
- PONTOS : 3549
REPUTAÇÃO : 209
Idade : 24
Áreas de atuação : Dєรєиvσlvєdσя Wєb(Fяσит-єиd), Blєиdєя, υиiтy, C#, ρнρ є Jαvαรcяiρт.
Respeito as regras :
Re: Problema com AI
Deu na mesma. Amanhã vou criar outra cena e tentar corrigir esse problema.
abraao36- Membro
- PONTOS : 2019
REPUTAÇÃO : 5
Respeito as regras :
Re: Problema com AI
Eu sei Porque o Primeiro Método Que Fiz Deu Errado, O Array Que Eu Criei "LugarOcupado[]" é um atributo que cada npc tem ou seja, Se voce tem 5 Npcs utilizando o script "Enemies" irá existir 5 Atributos "LugarOcupado[]".
Deixe ela Etatica.
"Métodos e variáveis estáticas são elementos que pertencem à classe e não ao objeto".
Só lembrando coloquei 5 posições como exemplo, Coloque a Quantidade de HideSpots da sua cena.
Deixe ela Etatica.
"Métodos e variáveis estáticas são elementos que pertencem à classe e não ao objeto".
- Código:
public static bool[] LugarOcupado = new bool[5];
Só lembrando coloquei 5 posições como exemplo, Coloque a Quantidade de HideSpots da sua cena.
Magnatah- Instrutor
- PONTOS : 3549
REPUTAÇÃO : 209
Idade : 24
Áreas de atuação : Dєรєиvσlvєdσя Wєb(Fяσит-єиd), Blєиdєя, υиiтy, C#, ρнρ є Jαvαรcяiρт.
Respeito as regras :
Re: Problema com AI
Voce pode criar um dictionary e nele voce colocar as posiçoes para onde o inimigo ou npc ir e uma bool para definir se tiver true = vazio se tiver false = cheio.
https://www.devmedia.com.br/quick-tips-usando-o-dictionary-no-csharp/15172
https://www.devmedia.com.br/quick-tips-usando-o-dictionary-no-csharp/15172
Chilinger- MembroAvançado
- PONTOS : 4093
REPUTAÇÃO : 42
Idade : 30
Respeito as regras :
Re: Problema com AI
Magnatah escreveu:Eu sei Porque o Primeiro Método Que Fiz Deu Errado, O Array Que Eu Criei "LugarOcupado[]" é um atributo que cada npc tem ou seja, Se voce tem 5 Npcs utilizando o script "Enemies" irá existir 5 Atributos "LugarOcupado[]".
Deixe ela Etatica.
"Métodos e variáveis estáticas são elementos que pertencem à classe e não ao objeto".
- Código:
public static bool[] LugarOcupado = new bool[5];
Só lembrando coloquei 5 posições como exemplo, Coloque a Quantidade de HideSpots da sua cena.
Agora parece que começou a funcionar porém encontrei alguns problemas.
O primeiro era que os inimigos estavam saindo do seu hidespot para ir para um hidespot onde eu tinha acabado de matar um npc. Esse problema eu consegui resolver criando a booleana "isAlreadyHided".
O segundo é que em algumas situações dois inimigos continuam indo para o mesmo hidespot. No caso estou testando com três hidespots e três inimigos. Dois vão para o local certo e um acaba indo para o hidespot errado. Ainda não consegui encontrar o padrão desse comportamento. As vezes dois npcs também parecem inverter suas posições um acaba indo para o hidespot mais próximo do outro. Verifiquei todos os npcs e hidespots e todos possuem os mesmos parâmetros.
O código está assim agora:
- Código:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
[RequireComponent(typeof(AudioSource))]
public class Enemies : MonoBehaviour
{
public enum Status
{
Patrol,
AttackPlayer,
Idle,
Dead
};
Status enemiesStatus = Status.Patrol;
public GameObject dropAmmoCanvas;
private GameObject player;
public AudioClip shoot;
AudioSource gun;
public float speed;
private float waitTime;
public float startWaitTime;
public List<Transform> moveSpots;
public List<Transform> hideSpots;
private int randomSpot;
public int nearestHideSpotIndex;
private bool canAttack = true;
private bool playerIsShooting = false;
public bool isDead = false;
public static bool[] LugarOcupado = new bool[3];
private bool isAlreadyHided = false;
private int minDam = 0;
private int maxDam = 8;
private int minFrequency = 3;
private int maxFrequency = 6;
private int minDroppedAmmo = 0;
private int maxDroppedAmmo = 10;
public int droppedAmmo;
void Start()
{
player = GameObject.FindWithTag("Player");
gun = GetComponent<AudioSource>();
waitTime = startWaitTime;
randomSpot = Random.Range(0, moveSpots.Count);
}
void Update()
{
switch (enemiesStatus)
{
case Status.AttackPlayer:
CheckNearestHideSpot();
if (isAlreadyHided == false)
{
transform.position = Vector2.MoveTowards(transform.position, hideSpots[nearestHideSpotIndex].position, speed * Time.deltaTime);
}
Attack();
break;
case Status.Patrol:
transform.position = Vector2.MoveTowards(transform.position, moveSpots[randomSpot].position, speed * Time.deltaTime);
if (Vector2.Distance(transform.position, moveSpots[randomSpot].position) < 0.2f)
{
if (waitTime <= 0)
{
randomSpot = Random.Range(0, moveSpots.Count);
waitTime = startWaitTime;
}
else
{
waitTime -= Time.deltaTime;
}
}
break;
case Status.Idle:
StopAllCoroutines();
break;
case Status.Dead:
StopAllCoroutines();
GetComponent<Animator>().SetBool("died", true);
droppedAmmo = Random.Range(minDroppedAmmo, maxDroppedAmmo);
if(dropAmmoCanvas != null && droppedAmmo > 0)
{
dropAmmoCanvas.gameObject.SetActive(true);
}
LugarOcupado[nearestHideSpotIndex] = false;
break;
}
if(Input.GetMouseButtonDown(0) && player.GetComponent<Weapon>().isReloading == false && player.GetComponent<Weapon>().isDryFire == false && !EventSystem.current.IsPointerOverGameObject())
{
if (player.GetComponent<Player>().life > 0)
{
playerIsShooting = true;
}
}
if (playerIsShooting && player.GetComponent<Player>().life > 0)
{
enemiesStatus = Status.AttackPlayer;
}
if (player.GetComponent<Player>().life <= 0)
{
enemiesStatus = Status.Idle;
}
if (isDead)
{
enemiesStatus = Status.Dead;
}
if(Vector2.Distance(transform.position,hideSpots[nearestHideSpotIndex].position) < 0.01f)
{
isAlreadyHided = true;
}
}
void Attack()
{
if (canAttack && playerIsShooting)
{
StartCoroutine(Attacking());
}
}
void CheckNearestHideSpot()
{
float maxDistance = 99999999999999999;
for (int x = 0; x < hideSpots.Count; x++)
{
float actualHideSpotDistance = Vector2.Distance(transform.position, hideSpots[x].transform.position);
if (actualHideSpotDistance < maxDistance && !LugarOcupado[x])
{
maxDistance = actualHideSpotDistance;
LugarOcupado[x] = true;
nearestHideSpotIndex = x;
}
}
}
IEnumerator Attacking()
{
canAttack = false;
yield return new WaitForSeconds(Random.Range(minFrequency, maxFrequency));
gun.PlayOneShot(shoot,0.4f);
player.GetComponent<Player>().life -= Random.Range(minDam, maxDam);
canAttack = true;
}
}
abraao36- Membro
- PONTOS : 2019
REPUTAÇÃO : 5
Respeito as regras :
Re: Problema com AI
Chilinger escreveu:Voce pode criar um dictionary e nele voce colocar as posiçoes para onde o inimigo ou npc ir e uma bool para definir se tiver true = vazio se tiver false = cheio.
https://www.devmedia.com.br/quick-tips-usando-o-dictionary-no-csharp/15172
Vou dar uma olhada e tentar usar.
abraao36- Membro
- PONTOS : 2019
REPUTAÇÃO : 5
Respeito as regras :
Tópicos semelhantes
» Problema no Network
» Problema com o ThirdPersonController
» Problema com NullReferenceException
» Problema com Triggers
» Problema com TAGS
» Problema com o ThirdPersonController
» Problema com NullReferenceException
» Problema com Triggers
» Problema com TAGS
Página 1 de 1
Permissões neste sub-fórum
Não podes responder a tópicos