[TUTORIAL] Script Simples De AI Com Comportamentos e Eventos
5 participantes
Página 1 de 1
[TUTORIAL] Script Simples De AI Com Comportamentos e Eventos
Eai pessoal blz?
Hoje venho compartilhar um prototipo de script de Inteligencia Artificial Inimiga, que apresenta Estados e Eventos.
Use como quiser, o script esta todo comentado para facil entendimento/edição.
Script Da Vida:
Hoje venho compartilhar um prototipo de script de Inteligencia Artificial Inimiga, que apresenta Estados e Eventos.
Use como quiser, o script esta todo comentado para facil entendimento/edição.
Script Da Vida:
- Código:
using UnityEngine;
using System.Collections;
// CLASSE BASICA PRA CALCULO DE VIDA/DANO
public class HealthBehaviour : MonoBehaviour {
// QUANTIDADE DE VIDA MAXIMA
public int maxHealth = 100;
// BOOLEANO REPRESENTANDO SE ESTA MORTO
public bool IsDead{ get; protected set;}
// VIDA ATUAL
public int CurrentHealth{ get; protected set;}
// delegate PARA OS EVENTO DE VIDA
public delegate void HealthEvent(GameObject source, GameObject attacker, int previusHealth, int currentHealth);
// EVENTO QUANDO A VIDA ACABAR(MORRER)
public static event HealthEvent onHealthOver;
// EVENTO QUANDO A VIDA MUDAR(AUMENTAR OU DIMINUIR)
public static event HealthEvent onHealthChange;
// METODO PARA TIRAR VIDA
// dmg SERIA A QUANTIDADE DE DANO
// attacker QUEM ATACOU
public void TakeDamage(int dmg, GameObject attacker)
{
// APENAS TIRAR VIDA SE ESTIVER VIVO NE?
if (IsDead) return;
// ARMAZENA A VIDA ANTERIOR PARA PASSAR AO EVENTO
int previusHealth = CurrentHealth;
// REDUZ A VIDA ATUAL PELA QUANTIDADE DE DANO PASSADA
CurrentHealth -= dmg;
// SE A VIDA ZEROU
if (CurrentHealth <= 0) {
CurrentHealth = 0;
// MORREU
IsDead = true;
// EXECUTA O EVENTO onHealthOver(MORRER)
if (onHealthOver != null)
onHealthOver (gameObject, attacker, previusHealth, CurrentHealth);
if (onHealthChange != null)
// EXECUTA O EVENTO onHealthChange
onHealthChange (gameObject, attacker, previusHealth, CurrentHealth);
}
else // NAO MORREU
{
if (onHealthChange != null)
// EXECUTA O EVENTO onHealthChange
onHealthChange (gameObject, attacker, previusHealth, CurrentHealth);
}
}
}
- Código:
/*******************************************
AUTHOR: MANAWYDAN
SCRIPT: INIMIGO BASICO COM ESTADOS E EVENTOS
VERSION: 0.1
TESTADO NA UNITY: 5.3.5f1
USO: USO LIVRE COMO QUISER
*/
using UnityEngine;
using System.Collections;
// ESTADOS DO INIMIGO, EM CADA ESTADO FAZER DETERMINADA AÇAO
public enum EnemyStates
{
IDLE = 0, // PARADO
ALERT = 1, // EM ALERTA
HUNT = 2, // CAÇANDO
ATTACK = 3, // ATACANDO
DAMAGE = 4, // PERDENDO VIDA
DYING = 5, // MORRENDO
DEAD = 6 // MORTO
}
// ADICIONA ESSES 3 COMPONENSTES AUTOMATICAMENTE
[RequireComponent(typeof(NavMeshAgent))]
[RequireComponent(typeof(Animator))]
[RequireComponent(typeof(Rigidbody))]
// CLASSE PRINCIPAL, DERIVADA DA CLASS HealthBehaviour
public class EnemyAI : HealthBehaviour {
//ESTADO ATUAL, A PRINCIPIO IDLE
public EnemyStates currentState = 0;
// REFERENCIA AO NavMeshAgent
private NavMeshAgent agent;
// REFERENCIA AO Animator
private Animator animator;
// REFERENCIA AO Rigidbody
private Rigidbody myRigidbody;
// REFERENCIA AO Transform
private Transform myTransform;
// REFERENCIA AO Transform DO JOGADOR
public static Transform playerTransform;
// CLASSE COM VARIAVEIS DE DETECÇAO
public EnemyDetection DetectionSettings;
// TIMER PARA CONTAR O TEMPO DE DETECÇAO ATUAL
private float currentTimeToDetectView = 0;
// TIMER PARA CONTAR O TEMPO EM QUE ESTA NO ESTADO DAMAGE
private float currentTimeToDamage = 0;
// DISTANCIA DO JOGADOR
private float playerDistance = 0;
// TIMER PARA CONTAR TEMPO QUE ESTA ATACANDO
private float currentAttackRate = 0;
// TIMER PARA CONTAR TEMPO QUE ESTA MORRENDO
private float currentDyingTime = 0;
// TIMER ATUAL PARA DETECTAR SE EXISTE INIMIGO A FRENTE
private float currentTimeToDetectEnemyForward = 0;
// TEMPO PARA CADA VERIFICACAO SE EXISTE INIMIGO A FRENTE
public float timeToDetectEnemyForward = 2f;
// FORCA PARA APLICAR SE EXISTIR INIMIGO A FRENTE, PARA NAO DEIXAR OS INIMIGOS "GRUDADOS"
public float forceToOffset = 3f;
// DELEGATE PARA OS EVENTOS DO INIMIGO, source(FONTE) SERIA O INIMIGO QUE ATIVOU O EVENTO
public delegate void EnemyEvent(GameObject source);
// EVENTO QUANDO MUDA PARA O ESTADO "DAMAGE"
public static event EnemyEvent onEnemyChangeToDamage;
// EVENTO QUANDO MUDA PARA O ESTADO "IDLE"
public static event EnemyEvent onEnemyChangeToIdle;
// EVENTO QUANDO MUDA PARA O ESTADO "ALERT"
public static event EnemyEvent onEnemyChangeToAlert;
// EVENTO QUANDO MUDA PARA O ESTADO "HUNT"
public static event EnemyEvent onEnemyChangeToHunt;
// EVENTO QUANDO MUDA PARA O ESTADO "ATTACK"
public static event EnemyEvent onEnemyChangeToAttack;
// EVENTO QUANDO MUDA PARA O ESTADO "DYING"
public static event EnemyEvent onEnemyChangeToDying;
// EVENTO QUANDO MUDA PARA O ESTADO "DEAD"
public static event EnemyEvent onEnemyChangeToDead;
// EVENTO QUANDO INIMIGO OUVIR SOM
public static event EnemyEvent onEnemyHearSound;
void Awake()
{
// PEGA REFERENCIA DO NavMeshAgent
agent = GetComponent<NavMeshAgent>();
// PEGA REFERENCIA DO Animator
animator = GetComponent<Animator>();
// PEGA REFERENCIA DO Rigidbody
myRigidbody = GetComponent<Rigidbody>();
// PEGA REFERENCIA DO TRANSFORM DO JOGADOR, O MESMO DEVE TER A TAG "Player"
playerTransform = GameObject.FindGameObjectWithTag ("Player").transform;
// PEGA REFERENCIA DO TRANSFORM
myTransform = transform;
// SETA O VALOR DA "POSICAO DE PARADA" PARA O VALOR QUE DEFINIMOS
agent.stoppingDistance = DetectionSettings.stopDistance;
// SETA A VIDA ATUAL PARA VIDA CHEIA
CurrentHealth = maxHealth;
// QUANDO OS EVENTOS FOREM ATIVADOS DEFINIMOS PARA EXECUTAR NOSSAS FUNCOES
onEnemyChangeToIdle += onEnemyChangeToIdle_Callback;
onEnemyChangeToAlert += onEnemyChangeToAlert_Callback;
onEnemyChangeToDamage += onEnemyChangeToDamage_Callback;
onEnemyChangeToHunt += onEnemyChangeToHunt_Callback;
onEnemyChangeToAttack += onEnemyChangeToAttack_Callback;
onEnemyChangeToDying += onEnemyChangeToDying_Callback;
onEnemyChangeToDead += onEnemyChangeToDead_Callback;
onEnemyHearSound += onEnemyHearSound_Callback;
onHealthChange += onHealthChange_Callback;
onHealthOver += onHealthOver_Callback;
}
void Update()
{
// VERIFICAMOS O ESTADO ATUAL DO INIMIGO PARA EXECUTARMOS OS DEVIDOS METODOS
switch(currentState)
{
//SE ESTIVER NO ESTADO IDLE
case EnemyStates.IDLE:
// EXECUTA AS FUNCOES DO ESTADO IDLE, E ASSIM SUCESSIVAMENTE
Idle_b ();
break;
case EnemyStates.ALERT:
Alert_b ();
break;
case EnemyStates.HUNT:
Hunt_b ();
break;
case EnemyStates.DAMAGE:
Damage_b ();
break;
case EnemyStates.ATTACK:
Attack_b ();
break;
case EnemyStates.DYING:
Dying_b ();
break;
case EnemyStates.DEAD:
Dead_b ();
break;
}
}
// FUNCAO PARA MUDAR O ESTADO ATUAL DO INIMIGO
public void SetState(EnemyStates state)
{
// ESTADO ATUAL RECEBE O VALOR QUE PASSARMOS
currentState = state;
// VERIFICA O NOVO ESTADO ATUAL
switch(currentState)
{
// SE FOR IDLE
case EnemyStates.IDLE:
// VERIFICA SE O EVENTO NAO FOR NULO
if(onEnemyChangeToIdle != null)
// E ENTAO, CHAMA O EVENTO, PASSANDO O INIMIGO COMO FONTE...
onEnemyChangeToIdle (gameObject);
break;
case EnemyStates.ALERT:
if(onEnemyChangeToAlert != null)
onEnemyChangeToAlert (gameObject);
break;
case EnemyStates.HUNT:
if(onEnemyChangeToHunt != null)
onEnemyChangeToHunt (gameObject);
break;
case EnemyStates.ATTACK:
if(onEnemyChangeToAttack != null)
onEnemyChangeToAttack (gameObject);
break;
case EnemyStates.DAMAGE:
if(onEnemyChangeToDamage != null)
onEnemyChangeToDamage (gameObject);
break;
case EnemyStates.DYING:
if(onEnemyChangeToDying != null)
onEnemyChangeToDying (gameObject);
break;
case EnemyStates.DEAD:
if(onEnemyChangeToDead != null)
onEnemyChangeToDead (gameObject);
break;
}
}
// METODO UTIL PARA ESPERAR DETERMINADOS SEGUNDOS
void Wait(float t)
{
while (t > 0)
t -= Time.deltaTime;
}
// METODO PARA SEGUIR O ALVO(NO MOMENTO O JOGADOR)
void FollowTarget()
{
// INCREMENTA O CONTADOR
currentTimeToDetectEnemyForward += Time.deltaTime;
// SE O TEMPO DETERMINADO CHEGAR
if(currentTimeToDetectEnemyForward>timeToDetectEnemyForward)
{
// ZERA O CONTADOR PARA CONTAR NOVAMENTE, "INFINITAMENTE"
currentTimeToDetectEnemyForward = 0;
// EXECUTA O METODO PARA NAO DEIXAR OS INIMIGOS "GRUDADOS"
AvoidEnemysForward ();
// ESPERA 0.1 SEGUNDOS
Wait (0.1f);
// ATIVAR O RIGIDBODY
myRigidbody.isKinematic = true;
// ESPERA 0.1 SEGUNDOS
Wait (0.1f);
// DESATIVAR O RIGIDBODY
myRigidbody.angularVelocity = Vector3.zero;
myRigidbody.isKinematic = false;
}
// MOVE O INIMIGO PARA A POSICAO DO JOGADOR
agent.SetDestination(playerTransform.position);
}
// METODO QUE "EMPURRA" O INIMIGO PARA O LADO, PARA UQE O MESMO NAO "GRUDE" NO INIMIGO DA FRENTE
void AvoidEnemysForward()
{
// CRIAMOS UM Vector3 PARA CALCULAR A DIRECAO DA FORÇA
Vector3 offset = Vector3.zero;
// CRIAMOS UM RaycastHit PARA SABER QUEM COLIDIU COM O Raycast
RaycastHit hit;
// EXECUTA O RAYCAST, COM UM RAIO QUE VAI DA POSICAO DO INIMIGO PARA FRENTE
if(Physics.Raycast(transform.position,transform.forward,out hit, DetectionSettings.enemyCheckDistance))
{
// EXISTE UM INIMIGO NA NOSSA FRENTE?
if(hit.collider.CompareTag("Enemy")){
// EXECUTA O RAYCAST, COM UM RAIO QUE VAI DA POSICAO DO INIMIGO PARA DIREITA
if (Physics.Raycast (transform.position, transform.right, out hit, DetectionSettings.enemyCheckDistance)) {
// EXISTE MAIS 1 INIMIGO A DIREITA?
if(hit.collider.CompareTag("Enemy"))
{
// EXECUTA O RAYCAST, COM UM RAIO QUE VAI DA POSICAO DO INIMIGO PARA ESQUERDA
if (Physics.Raycast (transform.position, -transform.right, out hit, DetectionSettings.enemyCheckDistance)) {
// ACRECENTAMOS +1 EM X E Z DO NOSSO VETOR
offset.x++;
offset.z++;
}
else
{
// ADICIONAMOS +1 APENAS EM Z
offset.z++;
}
}
}
else
{
// ADICIONAMOS +1 APENAS EM X
offset.x++;
}
}
}
// ADICIONAMOS UM FORÇA COM BASE NO VETOR, E COM A "POTENCIA" QUE SETAMOS ANTERIORMENTE
// DO TIPO IMPULSE, PARA FAZER O INIMIGO CONTORNAR, UM POSSIVEL INIMIGO A SUA FRENTE
myRigidbody.AddForce(offset*forceToOffset,ForceMode.Impulse);
//SETAMOS A VELOCIDADE ANGULAR PARA ZERO PARA NAO FICAR EVIDENTE QUE "EMPURRAMOS" O INIMIGO COM FISICA
myRigidbody.angularVelocity = Vector3.zero;
}
// METODO PARA FAZER O INIMIGO GIRAR, UTIL NO ESTADO DE ALERTA
void Turn()
{
myTransform.Rotate (0, DetectionSettings.turnVelocity*Time.deltaTime, 0);
}
// ESSE METODO EXECUTA QUANDO O EVENTO onHealthChange OCORRE,
// AKI VOCE PODE FAZER QUAL ACAO QUE QUISER
// source SERA O "INIMIGO" QUE TEVE SUA VIDA MODIFICADA
// attacker SERA QUEM O ATACOU, O PLAYER?
// previusH A QUANTIDADE DE VIDA QUE ELE TINHA ANTERIORMENTE
// curHealth A QUANTIDADE DE VIDA ATUAL
void onHealthChange_Callback(GameObject source, GameObject attacker, int previusH, int curHealth)
{
// VERIFICAMOS SE O source SERA ESSE INIMIGO, POIS ESSE METODO SERA CHAMADO PARA TODOS QUE O "SE INSCREVERAM"
if(source == gameObject)
{
// AKI VERIFICAMOS SE ELE PERDEU VIDA, E SE NAO MORREU
if(previusH > curHealth && curHealth >0)
{
// COMO PERDEU VIDA, MUDA PARA O ESTADO DAMAGE(PERDA DE VIDA)
animator.SetTrigger ("damage");
SetState (EnemyStates.DAMAGE);
}
}
}
// ESSE METODO EXECUTA QUANDO O EVENTO onHealthOver OCORRE,
// AKI VOCE PODE FAZER QUAL ACAO QUE QUISER
// source SERA O "INIMIGO" QUE MORREU
// attacker SERA QUEM O MATOU, O PLAYER?
// previusH A QUANTIDADE DE VIDA QUE ELE TINHA ANTERIORMENTE
// curHealth A QUANTIDADE DE VIDA ATUAL, SEMPRE 0
void onHealthOver_Callback(GameObject source, GameObject attacker, int previusH, int curHealth)
{
// VERIFICAMOS SE O source SERA ESSE INIMIGO, POIS ESSE METODO SERA CHAMADO PARA TODOS QUE O "SE INSCREVERAM"
if(source == gameObject)
{
// MUDAMOS PARA O ESTADO MORRENDO
SetState (EnemyStates.DYING);
}
}
// ESSE METODO EXECUTA QUANDO O EVENTO onEnemyChangeToIdle OCORRE,
// AKI VOCE PODE FAZER QUAL ACAO QUE QUISER
// source SERA O "INIMIGO" QUE ACABA DE MUDAR PARA O ESTADO IDLE
void onEnemyChangeToIdle_Callback(GameObject source)
{
// VERIFICAMOS SE O source SERA ESSE INIMIGO, POIS ESSE METODO SERA CHAMADO PARA TODOS QUE O "SE INSCREVERAM"
if(source == gameObject)
{
// FAZEMOS ELE PARAR DE MOVER
agent.Stop();
agent.enabled = false;
agent.enabled = true;
}
}
// ESSE METODO EXECUTA QUANDO O EVENTO onEnemyChangeToAlert OCORRE,
// AKI VOCE PODE FAZER QUAL ACAO QUE QUISER
// source SERA O "INIMIGO" QUE ACABA DE MUDAR PARA O ESTADO ALERT
void onEnemyChangeToAlert_Callback(GameObject source)
{
// VERIFICAMOS SE O source SERA ESSE INIMIGO, POIS ESSE METODO SERA CHAMADO PARA TODOS QUE O "SE INSCREVERAM"
if(source == gameObject)
{
// FAZEMOS ELE PARAR DE MOVER
agent.Stop();
agent.enabled = false;
agent.enabled = true;
}
}
// ESSE METODO EXECUTA QUANDO O EVENTO onEnemyChangeToHunt OCORRE,
// AKI VOCE PODE FAZER QUAL ACAO QUE QUISER
// source SERA O "INIMIGO" QUE ACABA DE MUDAR PARA O ESTADO HUNT
void onEnemyChangeToHunt_Callback(GameObject source)
{
// VERIFICAMOS SE O source SERA ESSE INIMIGO, POIS ESSE METODO SERA CHAMADO PARA TODOS QUE O "SE INSCREVERAM"
if (source == gameObject) {
}
}
// ESSE METODO EXECUTA QUANDO O EVENTO onEnemyChangeToDamage OCORRE,
// AKI VOCE PODE FAZER QUAL ACAO QUE QUISER
// source SERA O "INIMIGO" QUE ACABA DE MUDAR PARA O ESTADO DAMAGE
void onEnemyChangeToDamage_Callback(GameObject source)
{
// VERIFICAMOS SE O source SERA ESSE INIMIGO, POIS ESSE METODO SERA CHAMADO PARA TODOS QUE O "SE INSCREVERAM"
if(source == gameObject)
{
// FAZEMOS ELE PARAR DE MOVER
agent.Stop();
agent.enabled = false;
agent.enabled = true;
// RESETAMOS O TIMER DE DANO PARA QUE ELE CONTE DENOVO
currentTimeToDamage = 0;
}
}
// ESSE METODO EXECUTA QUANDO O EVENTO onEnemyChangeToAttack OCORRE,
// AKI VOCE PODE FAZER QUAL ACAO QUE QUISER
// source SERA O "INIMIGO" QUE ACABA DE MUDAR PARA O ESTADO ATTACK
void onEnemyChangeToAttack_Callback(GameObject source)
{
// VERIFICAMOS SE O source SERA ESSE INIMIGO, POIS ESSE METODO SERA CHAMADO PARA TODOS QUE O "SE INSCREVERAM"
if(source == gameObject)
{
// O QUE FAZER AKI? QUE TAL TOCAR UM SOM PARA QUE FIQUE CLARO QUE O INIMIGO VAI COMEÇAR A ATACAR?
}
}
// ESSE METODO EXECUTA QUANDO O EVENTO onEnemyChangeToDying OCORRE,
// AKI VOCE PODE FAZER QUAL ACAO QUE QUISER
// source SERA O "INIMIGO" QUE ACABA DE MUDAR PARA O ESTADO DYING
void onEnemyChangeToDying_Callback(GameObject source)
{
// VERIFICAMOS SE O source SERA ESSE INIMIGO, POIS ESSE METODO SERA CHAMADO PARA TODOS QUE O "SE INSCREVERAM"
if(source == gameObject)
{
// FAZEMOS ELE PARAR DE MOVER, JA QUE ESTA MORRENDO
agent.Stop();
agent.enabled = false;
myRigidbody.isKinematic = true;
// DESATIVAMOS O RIGIDBODY E OS COLISORES QUE PODERAM ATRAPALHAR
Collider[] cols = GetComponents<Collider>();
foreach(Collider c in cols)
{
c.enabled = false;
}
// AKI O INIMIGO PODERIA FAZER UAM ANIMACAO DE MORRENDO PQ N?
}
}
// ESSE METODO EXECUTA QUANDO O EVENTO onEnemyChangeToDead OCORRE,
// AKI VOCE PODE FAZER QUAL ACAO QUE QUISER
// source SERA O "INIMIGO" QUE ACABA DE MUDAR PARA O ESTADO DEAD
void onEnemyChangeToDead_Callback(GameObject source)
{
// VERIFICAMOS SE O source SERA ESSE INIMIGO, POIS ESSE METODO SERA CHAMADO PARA TODOS QUE O "SE INSCREVERAM"
if(source == gameObject)
{
// AKI VOCE PODE COLOCAR AS ACOES QUE ACONTECEM QUANDO ELE MORREU, DROPAR ITEM QUEM SABE?
}
}
// ESSE METODO EXECUTA QUANDO O EVENTO onEnemyHearSound OCORRE,
// AKI VOCE PODE FAZER QUAL ACAO QUE QUISER
// source SERA O "INIMIGO" QUE ACABA DE MUDAR PARA O ESTADO DEAD
void onEnemyHearSound_Callback(GameObject source)
{
// VERIFICAMOS SE O source SERA ESSE INIMIGO, POIS ESSE METODO SERA CHAMADO PARA TODOS QUE O "SE INSCREVERAM"
if(source == gameObject)
{
// AKI PODEMOS COLOCAR AÇOES PARA QUANDO O INIMIGO OUVIR UM SOM
// PODERIAMOS POR EXEMPLO: VERIFICAR OS INIMIGOS PROXIMO A ESTE QUE OUVIU O SOM
// E "ALERTAR" A ELES QUE TEM ALGO DE ERRADO AKI POR PERTO
}
}
// ESSE METODO ADICIONA UMA QUANTIDADE DE SOM PARA A DETECCAO POR SOM
// ammount SERA A QUANTIDADE DE SOM A ADICIONAR
// soundPos A POSICAO DE EXECUCAO DO SOM
// USAREMOS ISSO PARA QUE QUANTO MAIS LONGE O SOM ESTIVER DO INIMIGO
// MENOS ELE "OUVE"
public void AddSoundToDetection(float ammount, Vector3 soundPos)
{
// CALCULAMOS A DISTANCIA ENTRE O SOM E O INIMIGO
float soundDistance = Vector3.Distance(soundPos,myTransform.position);
// SE A DISTANCIA FOR MAIOR QUE A DISTANCIA MAXIMA DE "AUDICAO", NAO FAZEMOS NADA E RETORNAMOS
if(soundDistance>=DetectionSettings.soundMaxHearArea) return;
// CASO CONTRARIO, DIMINUIMOS O VALOR DE ammount COM BASE NA DISTANCIA
ammount -= (soundDistance/DetectionSettings.soundMaxHearArea)*ammount;
// ADICIONAMOS O QUANTIDADE DE SOM PARA O VERIFICADOR
DetectionSettings.soundAmmountDetected += ammount;
// NAO DEIXAMOS O SOM PASSAR DE 100
DetectionSettings.soundAmmountDetected = Mathf.Clamp (DetectionSettings.soundAmmountDetected,0,100f);
// DESENCADEAMOS O EVENTO DE OUVIR O SOM
onEnemyHearSound (gameObject);
// VERIFICAMOS SE A QUANTIDADE DE SOM ATUAL FOI SUFICIENTE PARA FAZER O INIMIGO IR PARA O ESTADO ALERT
if(DetectionSettings.soundAmmountDetected>=DetectionSettings.soundAmmountToDetect && currentState == EnemyStates.IDLE)
{
// MUDAMOS PARA O ESTADO ALERT
SetState (EnemyStates.ALERT);
}
}
// METODO QUE VERIFICA SE O PLAYER ESTA NA VIDAO DO INIMIGO
void CheckVision()
{
// CRIAMOS UM Vector3 COM A DIFERENÇA ENTRA A OS "OLHOS" DO INIMIGO E A POSICAO DO PLAYER
Vector3 dir = playerTransform.position - DetectionSettings.eyeTransform.position;
// CALCULAMOS O ANGULO ENTRE O PLAYER E OS "OLHOS" DO INIMGO
float angle = Vector3.Angle(dir,DetectionSettings.eyeTransform.forward);
// SE ESTA DENTRO DO CAMPO DE VISAO DO INIMIGO
if(angle<DetectionSettings.fieldOfViewAngle*0.5f)
{
// CRIAMOS UM RaycastHit
RaycastHit hit;
// CRIAMOS UM Raycast PARA VERIFICAR SE O PLAYER ESTA PROXIMO AO INIMIGO
if(Physics.Raycast(DetectionSettings.eyeTransform.position,dir.normalized,out hit, DetectionSettings.fieldOfViewRange))
{
// SE FOR O PLAYER
if(hit.collider.CompareTag("Player"))
// MUDA PARA O ESTADO HUNT(CAÇANDO O PLAYER)
SetState (EnemyStates.HUNT);
}
}
}
// METODO QUE SERA EXECUTADO ENQUANTO O INIMIGO ESTIVER NO ESTADO IDLE
void Idle_b(){
// INCREMENTA O TIMER PARA PODER CHECAR SE O PLAYER ESTA NA VISAO
currentTimeToDetectView += Time.deltaTime;
// SE O TEMPO DETERMINADO PASSOU
if (currentTimeToDetectView > DetectionSettings.timeToDetectView) {
// RESETA PARA CONTAR DENOVO
currentTimeToDetectView = 0;
// VERIFICA SE O PLAYER ESTA NA VISAO
CheckVision ();
}
// SE A DETECCAO DE SOM ESTA MUITO ALTA
if(DetectionSettings.soundAmmountDetected>=DetectionSettings.soundAmmountToDetect)
{
// MUDA PARA O ESTADO ALERT
SetState(EnemyStates.ALERT);
}
animator.SetBool ("isWalk", false);
}
// METODO QUE SERA EXECUTADO ENQUANTO O INIMIGO ESTIVER NO ESTADO ALERT
void Alert_b(){
// RESFRIA A DETECÇAO POR SOM
DetectionSettings.soundAmmountDetected -= DetectionSettings.soundMultiplyToIdle * Time.deltaTime;
// SE A DETECAO POR SOM FOR ZERADA
if (DetectionSettings.soundAmmountDetected <= 0) {
DetectionSettings.soundAmmountDetected = 0;
// VOLTA PARA O ESTADO IDLE
SetState (EnemyStates.IDLE);
}
// CASO CONTRARIO
else
{
// VERIFICA POR VISAO
CheckVision ();
}
// FAZ O INIIGO FICAR GIRANDO A PROCURA DO PLAYER
Turn ();
animator.SetBool ("isWalk", false);
}
// METODO QUE SERA EXECUTADO ENQUANTO O INIMIGO ESTIVER NO ESTADO HUNT
void Hunt_b(){
// CALCULA DISTANCIA ENTRE INIMIGO E O JOGADOR
playerDistance = Vector3.Distance(myTransform.position,playerTransform.position);
// SE ESTA FORA DO CAMPO DE VISAO
if (playerDistance > DetectionSettings.fieldOfViewRange) {
// VOLTA PRO ESTADO ALERT
SetState (EnemyStates.ALERT);
}
// SE ESTIVER MUITO PROXIMO
else if (playerDistance <= DetectionSettings.distanceToAttack) {
// MUDA PARA O ESTADO DE ATAQUE
SetState (EnemyStates.ATTACK);
}
// SEGUE O PLAYER
FollowTarget ();
animator.SetBool ("isWalk", true);
}
// METODO QUE SERA EXECUTADO ENQUANTO O INIMIGO ESTIVER NO ESTADO DAMAGE
void Damage_b(){
// INCREMENTA O CONTADOR, PARA SAIR DO ESTADO DAMAGE
currentTimeToDamage += Time.deltaTime;
if(currentTimeToDamage>DetectionSettings.timeToDamage)
{
// RESETA O CONTADOR E VOLTA PARA O ESTADO HUNT
currentTimeToDamage = 0;
SetState (EnemyStates.HUNT);
}
}
// METODO QUE SERA EXECUTADO ENQUANTO O INIMIGO ESTIVER NO ESTADO ATTACK
void Attack_b(){
// INCREMENTA O CONTADOR PARA PODER ATACAR
currentAttackRate += Time.deltaTime;
if(currentAttackRate>DetectionSettings.attackRate)
{
//TODO: ATAQUE, AKI POODE UTILIZAR OS METODOS PARA TIRAR VIDA
currentAttackRate = 0;
animator.SetTrigger ("attack");
}
// CALCULA A DISTANCIA DO JOGADOR
playerDistance = Vector3.Distance(myTransform.position,playerTransform.position);
// SE ESTIVER MUITO LONGE
if(playerDistance>DetectionSettings.distanceToAttack)
{
// VOLTA PARA O ESTADO HUNT
SetState (EnemyStates.HUNT);
}
}
// METODO QUE SERA EXECUTADO ENQUANTO O INIMIGO ESTIVER NO ESTADO DYING
void Dying_b(){
// INCREMENTA O CONTADOR
currentDyingTime += Time.deltaTime;
if(currentDyingTime>DetectionSettings.dyingTime)
{
// QUANDO O TEMPO DETERMINADO PASSAR, MUDA PARA O ESTADO DEAD
currentDyingTime = 0;
SetState (EnemyStates.DEAD);
}
}
// METODO QUE SERA EXECUTADO ENQUANTO O INIMIGO ESTIVER NO ESTADO DEAD,
// POSSIVELMENTE SERA EXECUTA UMA UNICA VEZ
void Dead_b(){
// RETIRA OS EVENTOS PARA NAO DAR ERRO
onEnemyChangeToIdle -= onEnemyChangeToIdle_Callback;
onEnemyChangeToAlert -= onEnemyChangeToAlert_Callback;
onEnemyChangeToDamage -= onEnemyChangeToDamage_Callback;
onEnemyChangeToHunt -= onEnemyChangeToHunt_Callback;
onEnemyChangeToAttack -= onEnemyChangeToAttack_Callback;
onEnemyChangeToDying -= onEnemyChangeToDying_Callback;
onEnemyChangeToDead -= onEnemyChangeToDead_Callback;
onEnemyHearSound -= onEnemyHearSound_Callback;
onHealthChange -= onHealthChange_Callback;
onHealthOver -= onHealthOver_Callback;
// DESTROI O INIMIGO, JA QUE ELE MORREU
Destroy(gameObject);
}
}
[System.Serializable]
// CLASSE PARA "ORGANIZAR" AS VARIAVEIS DE DETECCAO E ETC
public class EnemyDetection
{
// ANGULO MAXIMO DE VISAO
[Range(0,359f)]public float fieldOfViewAngle = 180f;
// DISTANCIA MAXIMA DE VISAO
public float fieldOfViewRange = 20f;
// TEMPO PARA VERIFICAR A VISAO
[Range(0.1f,5f)]public float timeToDetectView = 2f;
// QUANTIDADE DE SOM PARA MUDAR PARA O ESTADO ALERT
[Range(0,100f)]public float soundAmmountToDetect = 45f;
// QUANTIDADE DE SOM DETECTADA ATUALMENTE
public float soundAmmountDetected = 0;
// QUANTIDADE DE SOM PARA DIMINUIR, PARA VOLTAR AO ESTADO IDLE
public float soundMultiplyToIdle = 10f;
// DISTANCIA MAXIMA QUE PODE OUVIR UM SOM
public float soundMaxHearArea = 25f;
// TEMPO PARA SAIR DO ESTADO DAMAGE
public float timeToDamage = 1f;
// TEMPO DE CADA ATAQUE
public float attackRate = 2f;
// DISTANCIA MINIMA PARA ATACAR
public float distanceToAttack = 2f;
// TEMPO PARA SAIR DO ESTADO DYING E IR PARA O DEAD(MORRER)
public float dyingTime = 1.5f;
// VELOCIDADE QUE GIRA ENQUANTO ESTA NO ESTADO ALERT
public float turnVelocity = 15f;
// DISTANCIA PARA PARAR DO NAV MESH AGENT
public float stopDistance = 1.8f;
// DISTANCIA PARA VERIFICAR INIMIGOS A FRENTE, PARA TENTAR CONTORNA-LOS
public float enemyCheckDistance = 1.7f;
// POSICAO DOS OLHOS PARA VERIFICAR VISAO, PODE SER O PROPRIO TRANSFORM DO INIMIGO
public Transform eyeTransform;
}
Edit:
Upei o package os scripts e uma cena de teste:
https://mega.nz/#!0Z8DmaQL!bZgcPInokmDgrUcJDtmnC1cOjHZIp5n_ypG9AG2Dn04Última edição por Manawydan em Qui Ago 18, 2016 9:29 pm, editado 2 vez(es) (Motivo da edição : Uploado do package)
Re: [TUTORIAL] Script Simples De AI Com Comportamentos e Eventos
Muito bom, direto aparece alguem aqui no fórum com duvidas sobre AI, esse script vai ajudar bastante
Re: [TUTORIAL] Script Simples De AI Com Comportamentos e Eventos
Ja pg uma vez para o Marcos mas vc sabe fazer AI para trafego de carro.
Chilinger- MembroAvançado
- PONTOS : 4093
REPUTAÇÃO : 42
Idade : 30
Respeito as regras :
Re: [TUTORIAL] Script Simples De AI Com Comportamentos e Eventos
Pode fazer um video ensinando a instalar os dois scripts nao consegui fazer rancar dano do player
nao sei o que é esse Eye transform
nao sei o que é esse Eye transform
Eduardoro39- Avançado
- PONTOS : 3259
REPUTAÇÃO : 11
Idade : 24
Respeito as regras :
Re: [TUTORIAL] Script Simples De AI Com Comportamentos e Eventos
entao esse script é apenas um prototipo, voce teria que fazer o seu script de player derivar de HealthBehaviour, e quando quissese que o inimigo tirasse vida é só executar o método
TakeDamage que esta presenta em HealthBehaviour. eyeTransform seria a posicao do olho do inimigo, ou seja a posicao que voce quer que ele lance o raycast para verificar a visao, se quiser pode colocar o transform do proprio inimigo.
Exemplo:
E como esse script é um prototipo voce pode editar e modificar como quiser.
Se for usa a AI do jeito que esta voce pode editar a linha 555 por isso:
Eu não coloquei esse codigo por padrao pra tentar deixar a AI mais generica pra voce tirar vida como quiser, é so executar o método TakeDamage.
E tambem usei o animator so pra mostrar como fazer a AI trocar de animacoes, se quiser pode apagar as partes de animacoes, caso contrario se qusier usar desta forma vai ter que criar um Animator Controller deste jeito:
Tente Fazer o que eu disse, pq essa AI é Basica-Intermediaria e usa varias coisas pra funcionar, se nao conseguir eu tento fazer um package e upo aki.
TakeDamage que esta presenta em HealthBehaviour. eyeTransform seria a posicao do olho do inimigo, ou seja a posicao que voce quer que ele lance o raycast para verificar a visao, se quiser pode colocar o transform do proprio inimigo.
Exemplo:
- Código:
using UnityEngine;
using System.Collections;
// TEM QUE DERIVAR DE HealthBehaviour INVEZ DE MonoBehaviour
public class PlayerBehaviour : HealthBehaviour
{
// RESTO DO CODIGO DO SEU PLAYER
}
E como esse script é um prototipo voce pode editar e modificar como quiser.
Se for usa a AI do jeito que esta voce pode editar a linha 555 por isso:
- Código:
playerTransform.GetComponent<HealthBehaviour>().TakeDamage(100,gameObject);
Eu não coloquei esse codigo por padrao pra tentar deixar a AI mais generica pra voce tirar vida como quiser, é so executar o método TakeDamage.
E tambem usei o animator so pra mostrar como fazer a AI trocar de animacoes, se quiser pode apagar as partes de animacoes, caso contrario se qusier usar desta forma vai ter que criar um Animator Controller deste jeito:
Tente Fazer o que eu disse, pq essa AI é Basica-Intermediaria e usa varias coisas pra funcionar, se nao conseguir eu tento fazer um package e upo aki.
Re: [TUTORIAL] Script Simples De AI Com Comportamentos e Eventos
upa o package nao consegui fazer rancar vida
Eduardoro39- Avançado
- PONTOS : 3259
REPUTAÇÃO : 11
Idade : 24
Respeito as regras :
Re: [TUTORIAL] Script Simples De AI Com Comportamentos e Eventos
Upei o package no mega o link esta no primeiro post.
Eu usei um modelo da asset Store para testar a AI e tambem peguei o fps controler para o movimento do player. voce vai ter que criar a tag Enemy e aplicar nos inimigos.
Lembrando que esta AI é um prototipo logo voces podem editar/ modificar como quiser, ela é apenas uma base. Se voce ler os comentarios do script fica mais facil entender como as cosias funcionam, boa sorte!
Eu usei um modelo da asset Store para testar a AI e tambem peguei o fps controler para o movimento do player. voce vai ter que criar a tag Enemy e aplicar nos inimigos.
Lembrando que esta AI é um prototipo logo voces podem editar/ modificar como quiser, ela é apenas uma base. Se voce ler os comentarios do script fica mais facil entender como as cosias funcionam, boa sorte!
Re: [TUTORIAL] Script Simples De AI Com Comportamentos e Eventos
Vlw só que nao consegui instalar as animaçoes ja ta la só que nao acontece nada
Eduardoro39- Avançado
- PONTOS : 3259
REPUTAÇÃO : 11
Idade : 24
Respeito as regras :
Re: [TUTORIAL] Script Simples De AI Com Comportamentos e Eventos
Estranho aki ta funcionando normal. Voce criou a Tag Enemy e colocou nos inimigos?
Verifique se o Animator do inimigo esta linkado as animações em Motion, igual a imagem abaixo:
Verifique tambem se o Animator Controller esta linkado nas AI:
Verifique tambem os parametros do animator controller e suas transições aki esta tudo ok, ai deveria estar tambem. Aparece algum erro no console?
Verifique se o Animator do inimigo esta linkado as animações em Motion, igual a imagem abaixo:
Verifique tambem se o Animator Controller esta linkado nas AI:
Verifique tambem os parametros do animator controller e suas transições aki esta tudo ok, ai deveria estar tambem. Aparece algum erro no console?
Re: [TUTORIAL] Script Simples De AI Com Comportamentos e Eventos
o que é isso VERIFICAMOS SE O source SERA ESSE INIMIGO, POIS ESSE METODO SERA CHAMADO PARA TODOS QUE O "SE INSCREVERAM"
Eduardoro39- Avançado
- PONTOS : 3259
REPUTAÇÃO : 11
Idade : 24
Respeito as regras :
Re: [TUTORIAL] Script Simples De AI Com Comportamentos e Eventos
Aqui eu coloquei para tirar vida no inspetor, mais tenho uma duvida a vida do player e a do inimigo estao com mesmo nome ?
[list=linenums]
[*]//TODO: ATAQUE, AKI POODE UTILIZAR OS METODOS PARA TIRAR VIDA
[*] currentAttackRate = 0;
[*] animator.SetTrigger ("attack");
maxHealth - 10;
}
[/list]
- Código:
C#
[list=linenums]
[*]//TODO: ATAQUE, AKI POODE UTILIZAR OS METODOS PARA TIRAR VIDA
[*] currentAttackRate = 0;
[*] animator.SetTrigger ("attack");
maxHealth - 10;
}
[/list]
Re: [TUTORIAL] Script Simples De AI Com Comportamentos e Eventos
Voce pode fazer o player derivar de HealthBebaviour ou pode adicionar o mesmo como um componente.
Se for fazer o metodo 1, entao voce pode chamar o metodo TakeDamage do alvo que quer tirar vida, ou seja se quer tirar vida do player voce deve acessar o script do player e executar o metodo TakeDamage.
Se for fazer o metodo 2, entao voce pode usar um GetComponent e pegar o script HealthBehavior do alvo e executar o metodo TakeDamage do alvo.
Se for fazer o metodo 1, entao voce pode chamar o metodo TakeDamage do alvo que quer tirar vida, ou seja se quer tirar vida do player voce deve acessar o script do player e executar o metodo TakeDamage.
Se for fazer o metodo 2, entao voce pode usar um GetComponent e pegar o script HealthBehavior do alvo e executar o metodo TakeDamage do alvo.
Re: [TUTORIAL] Script Simples De AI Com Comportamentos e Eventos
Hummmm entendi, e parabens pelo tutorial
Tópicos semelhantes
» [TUTORIAL] Script super simples Para ficar de Dia e de Noite Automaticamente.
» [TUTORIAL] FAZENDO UM SCRIPT DE "FLASHLIGHT' SIMPLES
» [TUTORIAL] Script de AI para Zombie [Simples]
» [TUTORIAL] Um simples script para botão de play
» [TUTORIAL] Como spawnar inimigos [Tutorial simples]
» [TUTORIAL] FAZENDO UM SCRIPT DE "FLASHLIGHT' SIMPLES
» [TUTORIAL] Script de AI para Zombie [Simples]
» [TUTORIAL] Um simples script para botão de play
» [TUTORIAL] Como spawnar inimigos [Tutorial simples]
Página 1 de 1
Permissões neste sub-fórum
Não podes responder a tópicos