Esta es la segunda parte del tutorial
"Creación de un juego de Tower Defense en Unity" . Estamos creando un juego de género de torre de defensa en Unity, y al final de la
primera parte , aprendimos cómo colocar y actualizar monstruos. También tenemos un enemigo atacando cookies.
Sin embargo, ¡el enemigo aún no sabe dónde mirar! Además, un ataque solo parece extraño. En esta parte del tutorial, agregaremos oleadas de enemigos y monstruos armados para que puedan defender una galleta preciosa.
Llegar al trabajo
Abra el proyecto en Unity, que detuvimos en la última parte. Si se unió a nosotros en este momento, descargue el
proyecto borrador y abra
TowerDefense-Part2-Starter .
Abre
GameScene desde la carpeta
Scenes .
Convertir enemigos
Al final del tutorial anterior, el enemigo aprendió a moverse por el camino, pero parece que no tiene idea de dónde mirar.
Abra el script
MoveEnemy.cs en el IDE y agregue el siguiente método para solucionar la situación.
private void RotateIntoMoveDirection() {
RotateIntoMoveDirection
gira al enemigo para que siempre
RotateIntoMoveDirection
hacia adelante. Lo hace de la siguiente manera:
- Calcula la dirección actual del error, restando la posición del waypoint actual de la posición del siguiente punto.
- Utiliza
Mathf.Atan2
para determinar el ángulo en radianes hacia donde newDirection
dirige newDirection
(el punto cero está a la derecha). Multiplica el resultado por 180 / Mathf.PI
, convirtiendo el ángulo en grados. - Finalmente, obtiene el elemento secundario Sprite y gira los grados de
rotationAngle
del eje. Observe que rotamos al niño , no al padre, de modo que la tira de energía que agreguemos más tarde permanezca horizontal.
En
Update()
, reemplace el comentario
// TODO:
próxima llamada a
RotateIntoMoveDirection
:
RotateIntoMoveDirection();
Guarde el archivo y regrese a Unity. Corre la escena; ahora el enemigo sabe a dónde se está moviendo.
Ahora el error sabe a dónde va.
El único enemigo no se ve muy impresionante. ¡Necesitamos hordas! ¡Y como en cualquier juego de defensa de torres, las hordas corren en oleadas!
Informar al jugador
Antes de comenzar a mover las hordas, debemos advertir al jugador sobre la inminente batalla. Además, vale la pena mostrar el número de onda actual en la parte superior de la pantalla.
Varios GameObjects requieren la información de la
onda , por lo que la
agregaremos al componente
GameManagerBehavior del
GameManager .
Abra
GameManagerBehavior.cs en el IDE y agregue las siguientes dos variables:
public Text waveLabel; public GameObject[] nextWaveLabels;
waveLabel
almacena un enlace a la etiqueta de salida del número de onda en la esquina superior derecha de la pantalla.
nextWaveLabels
almacena dos GameObjects que crean una combinación de animación que mostraremos al comienzo de una nueva ola:
Guarde el archivo y regrese a Unity. Seleccione
GameManager en la
Jerarquía . Haga clic en el círculo a la derecha de la
etiqueta Wave y en el cuadro de diálogo
Seleccionar texto , seleccione
WaveLabel en la pestaña
Escena .
Ahora configure el
Tamaño para las
etiquetas de la
próxima ola en
2 . Ahora configure el
Elemento 0 en
NextWaveBottomLabel , y para el
Elemento 1 NextWaveTopLabel es lo mismo que hicimos con Wave Label.
Así es como debería verse ahora el comportamiento de Game ManagerSi el jugador pierde, entonces no debería ver un mensaje sobre la próxima ola. Para manejar esta situación, regrese a
GameManagerBehavior.cs y agregue otra variable:
public bool gameOver = false;
En
gameOver
almacenaremos el valor de si el jugador perdió.
Aquí nuevamente usamos la propiedad para sincronizar los elementos del juego con la ola actual. Agregue el siguiente código a
GameManagerBehavior
:
private int wave; public int Wave { get { return wave; } set { wave = value; if (!gameOver) { for (int i = 0; i < nextWaveLabels.Length; i++) { nextWaveLabels[i].GetComponent<Animator>().SetTrigger("nextWave"); } } waveLabel.text = "WAVE: " + (wave + 1); } }
Crear una variable privada, propiedad y getter ya debería ser algo familiar para usted. Pero con el setter, nuevamente, todo es un poco más interesante.
Asignamos a
wave
nuevo
value
.
Luego verificamos si el juego ha terminado. De lo contrario,
recorra todas las etiquetas
nextWaveLabels ; estas etiquetas tienen un componente
Animator . Para habilitar la animación
Animator ,
definimos un activador
nextWave .
Finalmente, configuramos el
text
de
waveLabel
para
wave + 1
. ¿Por qué
+1
? La gente común no comienza a contar desde cero (sí, esto es extraño).
En
Start()
establecemos el valor de esta propiedad:
Wave = 0;
Comenzamos el conteo con el número
0 Wave
.
Guarde el archivo y ejecute la escena en Unity. La etiqueta Wave mostrará correctamente 1.
Para un jugador, todo comienza con la ola 1.Olas: crea montones de enemigos
Puede parecer obvio, pero para atacar con una horda es necesario crear más enemigos, aunque no sabemos cómo hacerlo. Además, no debemos crear la próxima ola hasta que se destruya la actual.
Es decir, el juego debería poder reconocer la presencia de enemigos en la escena, y las
etiquetas son una buena manera de identificar los objetos del juego aquí.
Etiquetado enemigo
Selecciona el
enemigo prefabricado en el Navegador de proyectos. En la parte superior del
Inspector, haga clic en la lista desplegable
Etiqueta y seleccione
Agregar etiqueta .
Crea una
etiqueta llamada
Enemy .
Selecciona el
enemigo prefabricado. En el
Inspector, establece
la etiqueta de Enemigo para ello.
Definiendo oleadas de enemigos
Ahora necesitamos establecer la ola de enemigos. Abra
SpawnEnemy.cs en el IDE y agregue la siguiente implementación de clase antes de
SpawnEnemy
:
[System.Serializable] public class Wave { public GameObject enemyPrefab; public float spawnInterval = 2; public int maxEnemies = 20; }
Wave contiene
enemyPrefab
: la base para crear instancias de todos los enemigos en esta ola,
spawnInterval
: tiempo entre enemigos en la ola en segundos y
maxEnemies
: la cantidad de enemigos creados en esta ola.
La clase es
serializable , es decir, podemos cambiar sus valores en el Inspector.
Agregue las siguientes variables a la clase
SpawnEnemy
:
public Wave[] waves; public int timeBetweenWaves = 5; private GameManagerBehavior gameManager; private float lastSpawnTime; private int enemiesSpawned = 0;
Aquí establecemos las variables para generar enemigos, que es muy similar a cómo movimos enemigos entre puntos en la ruta.
Ponemos las olas de los enemigos individuales en
waves
y hacemos un seguimiento de la cantidad de enemigos creados y el tiempo en que se crearon en
enemiesSpawned
y
lastSpawnTime
.
Después de todas estas muertes, los jugadores necesitan tiempo para respirar, así que establece
timeBetweenWaves
en 5 segundos.
Reemplace el contenido de
Start()
siguiente código.
lastSpawnTime = Time.time; gameManager = GameObject.Find("GameManager").GetComponent<GameManagerBehavior>();
Aquí asignamos a
lastSpawnTime
valor de la hora actual, es decir, la hora en que se inició el script después de cargar la escena. Luego obtenemos el
GameManagerBehavior
ya familiar.
Agregue el siguiente código a
Update()
:
Analicémoslo paso a paso:
- Obtenemos el índice de la onda actual y verificamos si es la última.
- Si es así, calculamos el tiempo transcurrido después del engendro enemigo anterior y verificamos si es hora de crear un enemigo. Aquí tenemos en cuenta dos casos. Si este es el primer enemigo en la ola, verificamos si
timeInterval
es timeInterval
que timeBetweenWaves
. De lo contrario, verificamos si timeInterval
es timeInterval
que spawnInterval
ondas. En cualquier caso, verificamos que no hemos creado todos los enemigos en esta ola. - Si es necesario, genera al enemigo, creando una instancia de
enemyPrefab
. También aumenta el valor de los enemiesSpawned
. - Comprueba el número de enemigos en la pantalla. Si no están allí, y este fue el último enemigo en la ola, entonces creamos la próxima ola. También al final de la ola, le damos al jugador el 10 por ciento de todo el oro restante.
- Después de derrotar a la última ola, aquí se juega una animación de victoria en el juego.
Establecer intervalos de generación
Guarde el archivo y regrese a Unity. Seleccione el objeto
Carretera en la
Jerarquía . En el
Inspector, establezca el
tamaño del objeto
Ondas en
4 .
Por ahora, selecciona un objeto
Enemy para los cuatro elementos como
Enemy Prefab . Configure los campos
Spawn Interval y
Max Enemies de la siguiente manera:
- Elemento 0 : Intervalo de generación: 2.5 , Enemigos máximos: 5
- Elemento 1 : Intervalo de generación: 2 , Enemigos máximos: 10
- Elemento 2 : Intervalo de generación: 2 , Enemigos máximos: 15
- Elemento 3 : Intervalo de generación: 1 , Enemigos máximos: 5
El esquema final debería verse así:
Por supuesto, puede experimentar con estos valores para aumentar o disminuir la complejidad.
Lanza el juego. Si! ¡Los escarabajos han comenzado el viaje hacia tu galleta!
Tarea adicional: agrega diferentes tipos de enemigos
Ningún juego de defensa de la torre puede considerarse completo con un solo tipo de enemigo. Afortunadamente, también hay
Enemy2 en la carpeta
Prefabs .
En el
Inspector, seleccione
Prefabs \ Enemy2 y agregue el script
MoveEnemy . Establezca
Velocidad en
3 y establezca
la etiqueta Enemigo . ¡Ahora puedes usar este enemigo rápido para que el jugador no se relaje!
Actualización de la vida del jugador
A pesar de que hordas de enemigos atacan la galleta, el jugador no sufre daño. Pero pronto lo arreglaremos. El jugador debe sufrir si permite que el enemigo se acerque sigilosamente.
Abra
GameManagerBehavior.cs en el IDE y agregue las siguientes dos variables:
public Text healthLabel; public GameObject[] healthIndicator;
Usamos
healthLabel
para acceder al valor de vida del jugador, y
healthIndicator
para acceder a los cinco pequeños monstruos verdes que mastican galletas: simplemente simbolizan la salud del jugador; Es más divertido que un indicador de salud estándar.
Gestión de la salud
Ahora agrega una propiedad que almacena la salud del jugador en
GameManagerBehavior
:
private int health; public int Health { get { return health; } set {
Así es como gestionamos la salud del jugador. Y nuevamente, la parte principal del código se encuentra en el setter:
- Si reducimos la salud del jugador, usamos el componente
CameraShake
para crear un hermoso efecto de sacudida. Este script está incluido en el proyecto descargable y no lo consideraremos aquí. - Actualizamos la variable privada y la etiqueta de estado en la esquina superior izquierda de la pantalla.
- Si la salud se ha reducido a 0 y el final del juego aún no ha llegado,
gameOver
en true
e inicie la animación gameOver
. - Eliminamos uno de los monstruos de las cookies. Si los desactivamos, esta parte se puede escribir más fácilmente, pero aquí apoyamos la reincorporación en caso de que se agregue salud.
Inicializamos
Health
en
Start()
:
Health = 5;
Establecemos
Health
en
5
cuando la escena comienza a reproducirse.
Una vez hecho todo esto, ahora podemos actualizar la salud del jugador cuando el error llega a la cookie. Guarde el archivo y vaya al IDE al script
MoveEnemy.cs .
Cambio de salud
Para cambiar su estado, busque el comentario en
Update()
con las palabras
// TODO:
y reemplácelo con este código:
GameManagerBehavior gameManager = GameObject.Find("GameManager").GetComponent<GameManagerBehavior>(); gameManager.Health -= 1;
Entonces obtenemos el
GameManagerBehavior
y restamos la unidad de su
Health
.
Guarde el archivo y regrese a Unity.
Seleccione un
GameManager en la
Jerarquía y seleccione
HealthLabel para su
Etiqueta de salud .
Expanda el objeto
Cookie en la
Jerarquía y arrastre sus cinco indicadores de salud
secundarios a la
matriz de indicadores de salud de GameManager : los indicadores de salud serán pequeños monstruos verdes que comen galletas.
Ejecute la escena y espere hasta que los errores lleguen a la galleta. No hagas nada hasta que pierdas.
Venganza monstruo
Monstruos en su lugar? Si ¿Atacan los enemigos? ¡Sí, y se ven amenazantes! ¡Es hora de responder a estos animales!
Para hacer esto, necesitamos lo siguiente:
- Carril de salud para que el jugador sepa qué enemigos son fuertes y cuáles son débiles.
- Detectar enemigos dentro del alcance de un monstruo
- Tomar una decisión: a qué enemigo dispararle
- Un montón de conchas
Barra de salud enemiga
Para implementar la banda de salud, utilizamos dos imágenes: una para el fondo oscuro y la segunda (la barra verde es un poco más pequeña) escalaremos de acuerdo con la salud del enemigo.
Arrastre desde el
Navegador de proyectos a la escena
Prefabs \ Enemy .
Luego, en la
Jerarquía, arrastre y suelte
Imágenes \ Objetos \ HealthBarBackground en
Enemy para agregarlo como elemento secundario.
En el
Inspector, establezca la
Posición del HealthBarBackground en
(0, 1, -4) .
Luego, en el
Navegador de proyectos, seleccione
Imágenes \ Objetos \ Barra de salud y asegúrese de que su
Pivote esté a la
izquierda . Luego agréguelo como hijo de
Enemy en la
Jerarquía y establezca su valor de
Posición (-0.63, 1, -5) . Para
X Scale, establezca el valor en
125 .
Agregue un nuevo script de
C # llamado
HealthBar al objeto del juego
HealthBar . Más tarde lo cambiaremos para que cambie la longitud de la barra de salud.
Después de seleccionar un objeto
Enemigo en la
Jerarquía , asegúrese de que su posición sea
(20, 0, 0) .
Haga clic en
Aplicar en la parte superior del
Inspector para guardar todos los cambios como parte del prefabricado. Finalmente, elimine el objeto
Enemigo en la
Jerarquía .
Ahora repita todos estos pasos para agregar una barra de salud para
Prefabs \ Enemy2 .
Cambiar la longitud de la barra de salud
Abra el IDE
HealthBar.cs y agregue las siguientes variables:
public float maxHealth = 100; public float currentHealth = 100; private float originalScale;
En
maxHealth
la salud máxima del enemigo, y en
currentHealth
, la salud restante. Finalmente, en
originalScale
es el tamaño inicial de la barra de salud.
Guarde el objeto
originalScale
en
Start()
:
originalScale = gameObject.transform.localScale.x;
Almacenamos el valor
x
de la propiedad
localScale
.
Establezca la escala de la barra de estado agregando el siguiente código a
Update()
:
Vector3 tmpScale = gameObject.transform.localScale; tmpScale.x = currentHealth / maxHealth * originalScale; gameObject.transform.localScale = tmpScale;
Podemos copiar
localScale
en una variable temporal porque no podemos cambiar su valor
x por separado. Luego calculamos la nueva escala
x en función del estado actual del escarabajo y nuevamente asignamos el valor
localScale
a una variable temporal.
Guarde el archivo e inicie el juego en Unity. Sobre los enemigos verás rayas de salud.
Mientras el juego se está ejecutando, expande uno de los objetos
Enemigos (Clon) en la
Jerarquía y selecciona su
Barra de salud secundaria. Cambie su valor de
Salud actual y vea cómo cambia su barra de salud.
Detección de enemigos dentro del alcance.
Ahora nuestros monstruos necesitan descubrir a qué enemigos apuntar. Pero antes de que te des cuenta de esta oportunidad, debes preparar Monster y Enemy.
Seleccione Project Browser
Prefabs \ Monster y agregue el componente
Circle Collider 2D en el
Inspector .
Establezca el parámetro
Radio del colisionador en
2.5 ; esto indicará el radio de ataque de los monstruos.
Seleccione la casilla de verificación
Is Trigger para que los objetos pasen por esta área en lugar de colisionar con ella.
Finalmente, en la parte superior del
Inspector , configura la
Capa del Monstruo para
Ignorar Raycast . En el cuadro de diálogo, haga clic en
Sí, cambiar hijos . Si no se selecciona Ignorar Raycast, el colisionador responderá a los eventos de clic del mouse. Esto será un problema porque los monstruos bloquean los eventos destinados a los objetos de Openspot debajo de ellos.
Para asegurarnos de que el enemigo sea detectado en el área de activación, debemos agregarle un colisionador y un cuerpo rígido, porque Unity envía eventos de activación solo cuando un cuerpo rígido está unido a uno de los colisionadores.
En el
Navegador de proyectos, seleccione
Prefabs \ Enemy . Agregue el componente
2D de Rigidbody y seleccione
Cinemática para
Tipo de cuerpo . Esto significa que el cuerpo no se verá afectado por la física.
Agregue
Circle Collider 2D con un
radio de
1 . Repita estos pasos para
Prefabs \ Enemy 2 .
Los disparadores están configurados, por lo que los monstruos entenderán que los enemigos están dentro de su radio de acción.
Necesitamos preparar una cosa más: un guión que le dice a los monstruos cuando el enemigo es destruido para que no generen una excepción mientras continúan disparando.
Cree un nuevo script de
C # llamado
EnemyDestructionDelegate y agréguelo a los
prefabricados Enemy y
Enemy2 .
Abra
EnemyDestructionDelegate.cs en el IDE y agregue la siguiente declaración de delegación:
public delegate void EnemyDelegate (GameObject enemy); public EnemyDelegate enemyDelegate;
Aquí creamos un
delegate
, es decir, un contenedor para una función que se puede pasar como una variable.
Nota : los delegados se usan cuando un objeto del juego debe notificar activamente los cambios a otros objetos del juego. Lea más sobre los delegados en la documentación de Unity .
Agregue el siguiente método:
void OnDestroy() { if (enemyDelegate != null) { enemyDelegate(gameObject); } }
Cuando se destruye un objeto de juego, Unity llama automáticamente a este método y verifica al delegado por desigualdad
null
. En nuestro caso, lo llamamos con
gameObject
como parámetro. Esto permite a todos los encuestados registrados como delegados saber que el enemigo está destruido.
Guarde el archivo y regrese a Unity.
Les damos a los monstruos una licencia para matar
Y ahora los monstruos pueden detectar enemigos dentro del radio de su acción. Agregue un nuevo script de
C # a la prefabricación de
Monster y
asígnele el nombre
ShootEnemies .
Abra
ShootEnemies.cs en el IDE y agregue la siguiente construcción para acceder a
Generics
.
using System.Collections.Generic;
Agrega una variable para rastrear a todos los enemigos dentro del alcance:
public List<GameObject> enemiesInRange;
En enemigos en rango almacenaremos a todos los enemigos dentro del alcance.
Inicialice el campo en
Start()
.
enemiesInRange = new List<GameObject>();
Al principio, no hay enemigos en el radio de acción, por lo que creamos una lista vacía.
¡Llena la lista de
enemiesInRange
en
enemiesInRange
! Agregue el siguiente código al script:
- En
OnEnemyDestroy
eliminamos al enemigo de los enemigos en enemiesInRange
. Cuando un enemigo pisa un gatillo alrededor de un monstruo, se OnTriggerEnter2D
. - Luego agregamos el enemigo a la lista de enemigos
enemiesInRange
y agregamos el evento OnEnemyDestroy
. Por lo tanto, garantizamos que tras la destrucción del enemigo se OnEnemyDestroy
a OnEnemyDestroy
. No queremos que los monstruos gasten municiones en enemigos muertos, ¿verdad? - En
OnTriggerExit2D
eliminamos al enemigo de la lista y anulamos el registro del delegado. Ahora sabemos qué enemigos están al alcance.
Guarde el archivo e inicie el juego en Unity. Para asegurarte de que todo funciona, coloca el monstruo, selecciónalo y sigue los cambios en la lista de
enemiesInRange
en
enemiesInRange
en el
enemiesInRange
.
Selección de objetivo
Los monstruos ahora saben qué enemigo está al alcance. Pero, ¿qué harán cuando haya varios enemigos en el radio?
¡Por supuesto, atacarán al más cercano al hígado!
Abra el script
MoveEnemy.cs IDE y agregue un nuevo método que calcule este monstruo:
public float DistanceToGoal() { float distance = 0; distance += Vector2.Distance( gameObject.transform.position, waypoints [currentWaypoint + 1].transform.position); for (int i = currentWaypoint + 1; i < waypoints.Length - 1; i++) { Vector3 startPosition = waypoints [i].transform.position; Vector3 endPosition = waypoints [i + 1].transform.position; distance += Vector2.Distance(startPosition, endPosition); } return distance; }
El código calcula la longitud del camino aún no recorrido por el enemigo. Para hacer esto, usa
Distance
, que se calcula como la distancia entre dos instancias de
Vector3
.
Usaremos este método más adelante para averiguar qué objetivo atacar. Sin embargo, si bien nuestros monstruos no están armados ni indefensos, primero lo haremos.
Guarde el archivo y regrese a Unity para comenzar a configurar sus shells.
Vamos a darles a los monstruos conchas. ¡Muchas conchas!
Arrastre desde el Navegador de proyectos a la
escena Imágenes / Objetos / Bullet1 . Establezca la posición en
z en
-2 : las posiciones en x e y no son importantes, porque las configuramos cada vez que creamos una nueva instancia del proyectil durante la ejecución del programa.
Agregue un nuevo script de
C # llamado
BulletBehavior , y luego en el IDE agregue las siguientes variables:
public float speed = 10; public int damage; public GameObject target; public Vector3 startPosition; public Vector3 targetPosition; private float distance; private float startTime; private GameManagerBehavior gameManager;
speed
determina la velocidad de los proyectiles; El
damage
claro en el nombre.
target
,
startPosition
y
targetPosition
determinan la dirección del proyectil.
distance
y
startTime
rastrean la posición actual del proyectil.
gameManager
recompensa al jugador cuando mata al enemigo.
Asigne los valores de estas variables en
Start()
:
startTime = Time.time; distance = Vector2.Distance (startPosition, targetPosition); GameObject gm = GameObject.Find("GameManager"); gameManager = gm.GetComponent<GameManagerBehavior>();
startTime
establecemos el valor del tiempo actual y calculamos la distancia entre las posiciones de inicio y objetivo. Además, como siempre, lo conseguimos GameManagerBehavior
.Para controlar el movimiento del proyectil, agregue el Update()
siguiente código:
- Calculamos la nueva posición del proyectil, utilizando
Vector3.Lerp
para la interpolación entre las posiciones inicial y final. - Si el proyectil llega
targetPosition
, verificamos si todavía existe target
. - Obtenemos el componente del
HealthBar
objetivo y reducimos su salud por el tamaño del damage
proyectil. - Si la salud del enemigo se reduce a cero, entonces la destruimos, reproducimos el efecto de sonido y recompensamos al jugador por su precisión.
Guarde el archivo y regrese a Unity.Hacemos grandes conchas
¿No sería genial si el monstruo comienza a disparar más proyectiles a niveles altos? Afortunadamente, esto es fácil de implementar.Arrastre el objeto de juego Bullet1 desde la Jerarquía a la pestaña Proyecto para crear una prefabrica de proyectiles. Elimine el objeto original de la escena; ya no lo necesitaremos.Duplicar el prefabricado Bullet1 dos veces . Nombra las copias de Bullet2 y Bullet3 .Seleccione Bullet2 . En el Inspector , configure el campo Sprite componente Sprite Procesador de valor Images / Objetos / Bullet2. Entonces haremos que Bullet2 sea un poco más que Bullet1.Repita el procedimiento para cambiar el sprite del prefabricado Bullet3 a Imágenes / Objetos / Bullet3 .Más adelante en Bullet Behavior , ajustaremos la cantidad de daño causado por los proyectiles.Seleccione el Bullet1 prefabricado en la pestaña Proyecto . En el Inspector, verá Bullet Behavior (Script) , en el que puede establecer Damage en 10 para Bullet1 , 15 para Bullet2 y 20 para Bullet3 - o cualquier otro valor que te guste.Nota : Cambié los valores para que a niveles más altos el precio del daño se vuelva más alto. Esto evita que la actualización permita al jugador actualizar monstruos en los mejores puntos.
Conchas prefabricadas: el tamaño aumenta con el nivelCambiar el nivel de conchas
Asigna diferentes proyectiles a diferentes niveles de monstruos, para que los monstruos más fuertes destruyan a los enemigos más rápido.Abra MonsterData.cs en el IDE y agregue a las MonsterLevel
siguientes variables: public GameObject bullet; public float fireRate;
Así que establecemos la prefabricación del proyectil y la frecuencia de fuego para cada nivel de monstruos. Guarde el archivo y regrese a Unity para completar la configuración del monstruo.Seleccione el monstruo prefabricado en el Navegador de proyectos . En el Inspector, expanda Niveles en el componente Monster Data (Script) . Establezca la tasa de fuego de cada elemento en 1 . Luego configure el parámetro Bullet del Elemento 0, 1 y 2 en Bullet1 , Bullet2 y Bullet3 .Los niveles de monstruos deben establecerse de la siguiente manera:Los proyectiles matan enemigos? Si! ¡Abramos el fuego!Fuego abierto
Abra ShootEnemies.cs en el IDE y agregue las siguientes variables: private float lastShotTime; private MonsterData monsterData;
Como su nombre lo indica, estas variables rastrean el tiempo del último disparo de monstruo, así como la estructura MonsterData
que contiene información sobre el tipo de proyectiles de monstruos, la frecuencia del fuego, etc.Establezca los valores de estos campos en Start()
: lastShotTime = Time.time; monsterData = gameObject.GetComponentInChildren<MonsterData>();
Aquí asignamos el lastShotTime
valor de la hora actual y tenemos acceso al componente de MonsterData
este objeto.Agregue el siguiente método para implementar el disparo: void Shoot(Collider2D target) { GameObject bulletPrefab = monsterData.CurrentLevel.bullet;
- Obtenemos las posiciones inicial y objetivo de la bala. Establezca la posición z igual a z
bulletPrefab
. Anteriormente, establecimos la posición prefabricada del proyectil en z para que el proyectil aparezca debajo del monstruo disparador, pero por encima de los enemigos. - Creamos una instancia de un nuevo shell utilizando el
bulletPrefab
apropiado MonsterLevel
. Asignar startPosition
y targetPosition
proyectil. - Hacemos que el juego sea más interesante: cuando el monstruo dispara, comienza la animación del disparo y reproduce el sonido del láser.
Poniendo todo junto
Es hora de poner todo junto. Define el objetivo y haz que el monstruo lo mire.En el script ShootEnemies.cs, agregue a Update()
este código: GameObject target = null;
Considere este código paso a paso.- Determina el propósito del monstruo. Comenzamos a la máxima distancia posible en
minimalEnemyDistance
. Damos la vuelta en un ciclo de todos los enemigos dentro del alcance y hacemos del enemigo un nuevo objetivo si su distancia a la galleta es menor que la más pequeña actual. - Llamamos
Shoot
si el tiempo transcurrido es mayor que la frecuencia de disparo del monstruo y establecemos el lastShotTime
valor de la hora actual. - Calculamos el ángulo de rotación entre el monstruo y su objetivo. Rotamos al monstruo a este ángulo. Ahora él siempre mirará al objetivo.
Guarde el archivo e inicie el juego en Unity. Los monstruos comenzarán a proteger desesperadamente las cookies. Finalmente hemos terminado!A donde ir ahora
El proyecto terminado se puede descargar desde aquí .Hicimos un gran trabajo en este tutorial y ahora tenemos un gran juego.Aquí hay algunas ideas para un mayor desarrollo del proyecto:- Más tipos de enemigos y monstruos.
- Diferentes rutas de enemigos.
- Diferentes niveles de juego
Cada uno de estos aspectos requerirá cambios mínimos y puede hacer que el juego sea más divertido. Si creas un nuevo juego basado en este tutorial, estaré encantado de jugarlo, así que comparte un enlace.En esta entrevista se pueden encontrar ideas interesantes sobre cómo crear un juego exitoso de defensa de la torre .