Unity Artificial Intelligence
-
Upload
andreapine -
Category
Documents
-
view
498 -
download
3
Transcript of Unity Artificial Intelligence
By: Deodato Pechir.
UNITY 3D REFERENCE SCRIPTING
INDICE DINAMICO – REFERENCIA DE SCRIPTING
MENU:
1. AI. BASIC PATROL.
2. AI. VISIBLE RANGE & FOLLOW.
3. AI. OUT OF RANGE & HIDE.
4. AI. ENEMY ATTACK.
5. WAYPOINT & PATHFINDIGS.
6. MULTI WAYPOINTS & PATHFINDNGS.
Nota: Si quieres regresar al Índice haz click sobre el Cubo en la parte superior derecha de cada página
3
www.3dboxweb.com
1. ARTIFICIAL INTELLIGENCE BASIC PATROL
4
www.3dboxweb.com
ARTIFICIAL INTELLIGENCE – BASIC PATROL:
1. Cargamos el paquete Basic_AI, y haremos que el personaje camine por sí solo, y detecte que cuando se acerque a un muro este
gire a la derecha.
//Variables para controlar AI
var GirarVelocidad : float = 2;
var VelocidadCaminar : float = 5;
var Distancia : float = 3;
function Update () {
// Dibujar una línea que sea como el Raycast para saber con que colisiona
Debug.DrawRay (transform.position, transform.forward*Distancia, Color.white);
// Uso del Raycast para lanzar un rayo hacia enfrente y detecte cuando colisione.
if (Physics.Raycast (transform.position, transform.forward, Distancia)){
//ROTAR
//Si "RotarDerecha=true" hacer que gire continuamente a la derecha.
transform.Rotate (Vector3.up, 90 * GirarVelocidad * Time.deltaTime);
}else{
//MOVER
transform.Translate (Vector3.forward * VelocidadCaminar * Time.deltaTime);
}
}
5
www.3dboxweb.com
2. Ahora haremos que el personaje gire hacia la izquierda/Derecha a determinado tiempo, para darle variedad:
//Variables para controlar AI
var Distancia : float = 3;
var GirarVelocidad : float = 2;
var VelocidadCaminar : float = 5;
var RotarDerecha: boolean = true;
var Segundos : float = 10;
function Update () {
// Dibujar una línea que sea como el Raycast para saber con que colisiona
Debug.DrawRay (transform.position, transform.forward*Distancia, Color.white);
// Uso del Raycast para lanzar un rayo hacia enfrente y detecte cuando colisione.
if (Physics.Raycast (transform.position, transform.forward, Distancia)){
//ROTACION
if(RotarDerecha){
//Si "RotarDerecha=true" hacer que gire continuamente a la derecha.
transform.Rotate (Vector3.up, 90 * GirarVelocidad * Time.deltaTime);
}else{
//Si "RotarDerecha=false" hacer que gire continuamente a la Izquierda.
transform.Rotate (Vector3.up, -90 * GirarVelocidad * Time.deltaTime);
}
}else{
//CAMINAR
transform.Translate (Vector3.forward * VelocidadCaminar * Time.deltaTime);
}
}
6
www.3dboxweb.com
Opción 1: Cambiar la rotación Izquierda a Derecha en base a tiempo.
function CambiarGiro(){
// Cambiar la variable de boleano true/false.
RotarDerecha = !RotarDerecha;
}
//Activar la corrutina que hace que cambie de giro el player cada cantidad de segundos.
InvokeRepeating ("CambiarGiro", 0, Segundos);
Opción 2: Cambiar la rotación Izquierda a Derecha en base a funciones del teclado.
function Update () {
if (Input.GetKeyDown (KeyCode.Z)){
Desactivar();
}else if (Input.GetKeyDown (KeyCode.X)){
Activar();
}
}
//-------------------------------------------------------------------------
function Desactivar (){
//Cancelar corrutina de Cambio de Giro
CancelInvoke("CambiarGiro");
// Desativar la velocidad
VelocidadCaminar = 0;
//Imprimir AI
Debug.Log ("Desactivar AI");
}
function Activar (){
//Activar de nuevo el caminar
VelocidadCaminar = 5;
//Activar corrutina de Cambio de Giro
InvokeRepeating ("CambiarGiro", 0, Segundos);
//Imprimir AI
Debug.Log ("Activar AI");
}
7
www.3dboxweb.com
2. A.I. VISIBLE RANGE & FOLLOW
8
www.3dboxweb.com
ARTIFICIAL INTELLIGENCE –VISIBLE RANGE & FOLLOW:
1. Cargamos el paquete “AI_SceneFollow” y en la carpeta de Prefab, agregamos Enemigo y Jugador (Rigidbody y Collider).
2. Script “AI_RangeVisibleFollow” y lo asignamos al “Prefab_Enemigo” para que quede asignado a cada enemigo de la escena.
3. El “Jugador” ya tiene asignado los controles básicos de “1ra Persona” (Character Controller, Motor y FPSInput Controller).
Haremos que cuando el personaje se acerque al enemigo de acuerdo a una cierta distancia cuando lo visualiza, el enemigo gire
suavemente hacia el jugador y comience a seguirlo hasta, pero manteniendo una distancia cuando este totalmente cerda del jugador,
y el jugador hasta que salga de su rango de visión dejara de seguirlo.
[Los colores son en base a los pasos de scripting]
var Jugador : Transform;
var LineaBusqueda : int = 7;
var LineaAtaque : int = 2;
var GirarEnemigo : int = 6;
var CaminarEnemigo : int = 5;
function Update(){
// Línea de ataque del "Enemigo" seguir/atacar | La distancia del Enemigo y Jugador.
Debug.DrawRay (transform.position, transform.forward * LineaBusqueda, Color.white);
var DistanciaJugador= Vector3.Distance (transform.position, Jugador.position);
// Si entra en la "Linea Ataque" pero no pasa la "DistanciaAtaque" (cuan cerca jugador-enemigo).
if (DistanciaJugador <= LineaBusqueda && DistanciaJugador >= LineaAtaque){
//ROTAR
// Obtener "Angulo" donde esta el personaje para que Gire. | Suavisar al "Angulo" de rotacion con Lerp.
var Angulo = Quaternion.LookRotation(Jugador.position - transform.position);
transform.rotation = Quaternion.Slerp(transform.rotation, Angulo, Time.deltaTime * GirarEnemigo);
//MOVER
transform.Translate(Vector3.forward*CaminarEnemigo*Time.deltaTime);
}
}
9
www.3dboxweb.com
3. AI. OUT OF RANGE & HIDE
10
www.3dboxweb.com
ARTIFICIAL INTELLIGENCE –OUT OF RANGE & HIDE:
1. Cargamos el paquete “AI_SceneHide” y en la carpeta de Prefab, agregamos Enemigo y Jugador (Rigidbody y Collider).
2. Script “AI_RangeHide” y lo asignamos al “Prefab_Enemigo” para que quede asignado a cada enemigo de la escena.
3. El “Jugador” ya tiene asignado los controles básicos de “1ra Persona” (Character Controller, Motor y FPSInput Controller).
Haremos que cuando el personaje se esconda detrás de un muro o un objeto que no permita ver al enemigo al Jugador este
simplemente no esté en su rango de ataque.
[Los colores son en base a los pasos de scripting]
//Variable para cargar al Jugador
var Jugador : Transform;
function Update(){
//Variable para obtener info de las colisiones
var HitRay : RaycastHit;
// Saber si esta colisionando con Jugador o se cruza algo mas entre ellos y dejarlo en el HitRay.
if (Physics.Linecast (transform.position, Jugador.position, HitRay)){
//Saber que objeto de interpone o cruza entre Enemigo-Jugador
if (HitRay.collider.gameObject.name == "Prefab_Jugador"){
// Línea de Búsqueda -> "Personaje" Visible
Debug.DrawLine (transform.position, Jugador.position, Color.green);
}else{
// Linea de Busqueda -> "Personaje" NO Visible
Debug.DrawLine (transform.position, Jugador.position, Color.red);
}
}
}
11
www.3dboxweb.com
4. A.I. ENEMY ATTACK
12
www.3dboxweb.com
ARTIFICIAL INTELLIGENCE – ENEMY ATTACK (RANGE VISIBLE & ATTACK):
1. Cargamos “AI_Scene EnemyAttack” y en la carpeta de Prefab, agregamos Enemigo y Jugador (Rigidbody y Collider).
2. Script “AI_ EnemyAttack” y lo asignamos al “Prefab_Enemigo” para que quede asignado a cada enemigo de la escena.
3. El “Jugador” ya tiene asignado los controles básicos de “1ra Persona” (Character Controller, Motor y FPSInput Controller).
Nota: Ahora combinaremos las técnicas de: “Visible Range & Follow” y “Out of Range & Hide”, para hacer que el “enemigo” nos
ataque cuando estemos dentro de su área visible, este gire hacia nosotros y nos siga, pero cuando estemos detrás de un muro ya no
podrá vernos.
var LineaBusqueda : int = 7; var LineaAtaque : int = 2; var GirarEnemigo : int = 6; var CaminarEnemigo : int = 5; PASO 1: JUNTAR VARIABLES
//SCRIPT: RANGE TO FOLLOW function Update(){ // Linea de Busqueda del "Personaje", hacia donde se encuentra. Debug.DrawLine (transform.position, Jugador.position, Color.green); // Linea de ataque del "Enemigo" siguir/atacar. Debug.DrawRay (transform.position, transform.forward * LineaBusqueda, Color.white); var DistanciaJugador= Vector3.Distance (transform.position, Jugador.position); // Si entra en la "Linea Ataque" pero no pasa la "DistanciaAtaque" if (DistanciaJugador <= LineaBusqueda && DistanciaJugador >= LineaAtaque){ //ROTAR // Obtener "Angulo" donde esta el personaje para que Gire. | Suavisar al "Angulo" de rotacion con Lerp. var Angulo = Quaternion.LookRotation(Jugador.position - transform.position, Vector3.up); transform.rotation = Quaternion.Slerp(transform.rotation, Angulo, Time.deltaTime * GirarEnemigo); //MOVER transform.Translate(Vector3.forward*CaminarEnemigo*Time.deltaTime); } } //-------------------------------------------------------------------------------------------------------------- //SCIPT: RANGE VISIBLE ACTION var Jugador : Transform; var HitRay : RaycastHit; // Saber que cruz o colisiona entre el enemigo y el personaje. if (Physics.Linecast (transform.position, Jugador.position, HitRay)){
if (HitRay.collider.gameObject.name == "Prefab_Jugador"){ // Linea de Busqueda -> "Personaje" Visible Debug.DrawLine (transform.position, Jugador.position, Color.green); PASO 2: PASAR ROTAR/MOVER SI ESTA EN EL RANGO DE BUSQUEDA Y NO ESTA ESCONDIDO. }else{ // Linea de Busqueda -> "Personaje" NO Visible Debug.DrawLine (transform.position, Jugador.position, Color.red); } } PASO 3: PASAR LOS CORCHETES ABAJO
13
www.3dboxweb.com
var Jugador : Transform;
var LineaBusqueda : int = 7;
var LineaAtaque : int = 2;
var GirarEnemigo : int = 6;
var CaminarEnemigo : int = 5;
function Update(){
// Linea de Busqueda del "Personaje", hacia donde se encuentra.
Debug.DrawLine (transform.position, Jugador.position, Color.green);
// Línea de ataque del "Enemigo" seguir/atacar.
Debug.DrawRay (transform.position, transform.forward * LineaBusqueda, Color.white);
var DistanciaJugador= Vector3.Distance (transform.position, Jugador.position);
var HitRay : RaycastHit;
// Saber qué cruz o colisiona entre el enemigo y el personaje.
if (Physics.Linecast (transform.position, Jugador.position, HitRay)){
if (HitRay.collider.gameObject.name == "Prefab_Jugador"){
// Linea de Busqueda -> "Personaje" Visible
Debug.DrawLine (transform.position, Jugador.position, Color.green);
//------------------------------------------------------------------------------------------------------------------------
// Si entra en la "Linea Ataque" pero no pasa la "DistanciaAtaque"
if (DistanciaJugador <= LineaBusqueda && DistanciaJugador >= LineaAtaque){
//ROTAR
// Obtener "Angulo" donde esta el personaje para que Gire. | Suavisar al "Angulo" de rotacion con Lerp.
var Angulo = Quaternion.LookRotation(Jugador.position - transform.position, Vector3.up);
transform.rotation = Quaternion.Slerp(transform.rotation, Angulo, Time.deltaTime * GirarEnemigo);
//MOVER
transform.Translate(Vector3.forward*CaminarEnemigo*Time.deltaTime);
}
//------------------------------------------------------------------------------------------------------------------------
}else{
// Linea de Busqueda -> "Personaje" NO Visible
Debug.DrawLine (transform.position, Jugador.position, Color.red);
}
}
14
www.3dboxweb.com
5. WAYPOINTS & PATHFINDING
15
www.3dboxweb.com
ARTIFICIAL INTELLIGENCE – CREATE WAYPOINTS:
1. Importamos Waypoints.psd, creamos una carpeta con el nombre de “Gizmos” y aquí dentro pondremos el psd.
2. Creamos un Empty Object y lo metemos en un Prefab le asignamos un nuevo script: “AI_Gizmo”.
GIZMO BASICOS:
// Mandar llamar la textura para el Waypoint(debe de estar en Carpeta Gizmos)..
function OnDrawGizmos (){
Gizmos.DrawIcon (transform.position, "NombreImagen.psd");
}
GIZMO ESTILO DEO:
// Extensiones a leer.
enum Extenciones {psd, png, jpg, tga}
//Variables Formato y Extension
var Formatos : Extenciones;
var Textura : Texture;
// Mandar llamar la textura para el Waypoint(debe de estar en Carpeta Gizmos).
function OnDrawGizmos (){
Gizmos.DrawIcon (transform.position, Textura.name + "." + Formatos);
}
16
www.3dboxweb.com
ARTIFICIAL INTELLIGENCE – PATHFINDING:
//VARIABLES
var Waypoint : Transform;
var Speed : float = 5;
var DistanceToWP : float = 1;
//SI NO HAY WAYPOINT SE DESACTIVA EL SCRIPT
function Awake(){
if(Waypoint == null) {
enabled = false;
Debug.LogWarning("No hay WayPoint cargados en: "+name);
}
}
//CONECCION AL WAYPOINT
function OnDrawGizmos(){
if( Waypoint != null) {
Gizmos.color = Color (.6, .6, 1, .7);
Gizmos.DrawLine(transform.position, Waypoint.position);
}
}
//CAMINAR HACIA EL WAYPOINT
function FixedUpdate (){ // Waypoint – Position del persoaje
var vChaToWp = Vector3.Distance(Waypoint.position, transform.position);
if (vChaToWp >= DistanceToWP){
transform.LookAt ( Vector3 (Waypoint.position.x, transform.position.y, Waypoint.position.z) );
transform.position += transform.forward * Time.deltaTime * Speed;
}
}
17
www.3dboxweb.com
6. MULTI WAYPOINTS
18
www.3dboxweb.com
ARTIFICIAL INTLIGENCE - MULTI WAYPOINTS:
//VARIABLES
var Waypoint : Transform[];
var DistanceToWP : float = 1;
var Speed : float = 5;
//SI NO HAY WP DESACTIVAR EL SCRIPT.
function Awake(){
if( Waypoint.length <= 0 ) {
enabled = false;
Debug.LogWarning("No WayPoint Loaded in: "+name);
}
}
//CONECCION A LOS WAYPOINTS
function OnDrawGizmos(){
if( Waypoint.Length > 0 ) {
for(var i : int = 0; i < Waypoint.length; i++) { //Si hay mas de 1 WP se inician las conexiones.
if (i>0){ //inicia del ultimo WP hacia atras, para que no sobre ningun WP (resta).
Gizmos.color = Color (.6, .6, 1, .7);
Gizmos.DrawLine(Waypoint[i].position, Waypoint[i-1].position);
}
}
}
}
19
www.3dboxweb.com
//Variable no publica para iniciar indicar a que Waypoint caminara al llegar a un WP.
private var NextWP : int = 0;
//CAMINAR HACIA LOSWAYPOINTS
function FixedUpdate (){
// Waypoint - Posicion del personaje.
var vChaToWp= Vector3.Distance(Waypoint[NextWP].position, transform.position);
//Caminar hacia el WP en referencia de la distancia
if (vChaToWp >= DistanceToWP){
transform.LookAt ( Vector3 (Waypoint[NextWP].position.x, transform.position.y, Waypoint[NextWP].position.z) );
transform.position += transform.forward * Time.deltaTime * Speed;
}else{ // Obtenemos el total de WP y le restamos 1, para que no llegue al final y trate de ir a otro.
if (NextWP < Waypoint.length -1){ //Hacer que se pase al siguiente WP a caminar, sumando 1 al actual.
NextWP++;
}
}
}
SI SE QUIERE CREAR LOOP AL LLEGAR AL FINAL DEL WP:
var Loop : boolean = true;
//SCRIPT RECORTADO
if (NextWP < Waypoint.length -1){
NextWP++;
} else {
if (Loop){ // Si se llega al ultimo WP, hacemos que se repita
NextWP = 0;
}else{ //Si no hay Loop activado desactivar Script (rendimiento).
enabled =false;
}
}
} }