Los juegos de defensa de torres son increíblemente populares y no hay nada más satisfactorio que ver cómo tus defensas destruyen a los malvados invasores. ¡En este tutorial de dos partes, crearás un juego de defensa de torres usando Unity !
Aprenderás a…
- Crea oleadas de enemigos
- Haga que se muevan siguiendo los puntos de ruta
- Construye y mejora torres para reducir a tus enemigos a nada.
¡Finalmente tendrás un framework de este tipo que podrás ampliar!
Nota : necesitas conocer los conceptos básicos de Unity, como cómo agregar recursos y componentes del juego, comprender las casas prefabricadas y conocer algunos conceptos básicos de C# .
Defensa de la torre en su totalidad
En este tutorial, crearás un juego de defensa de torres en el que los enemigos (insectos) se arrastran hacia las galletas que te pertenecen a ti y a tus secuaces, ¡que por supuesto son monstruos! Puedes colocar y mejorar monstruos en puntos estratégicos para ganar un poco de oro.
Los jugadores deben matar los insectos antes de que se coman las galletas. Cada oleada de enemigos es más difícil de derrotar. El juego termina cuando sobrevives a todas las oleadas (¡victoria!) o cinco enemigos alcanzan la galleta. (¡fallar!)
Aquí hay capturas de pantalla del juego completo:
¡Los monstruos se unen! ¡Protege las galletas!
comenzar
Abra el proyecto TowerDefense-Part1-Starter en Unity .
El proyecto inicial incluye recursos artísticos y sonoros, así como animaciones prediseñadas y algunos guiones útiles. Estos guiones no están directamente relacionados con los juegos de defensa de torres y no se explicarán aquí. Sin embargo, si desea obtener más información sobre la creación de animaciones 2D de Unity, consulte este tutorial de Unity 2D .
El proyecto también contiene casas prefabricadas que luego ampliarás para crear el personaje. Finalmente, el proyecto incluye una escena con su fondo y configuración de interfaz de usuario.
Abra GameScene en la carpeta " Escenas " y configure la relación de aspecto de la vista del juego en 4:3 para asegurarse de que las etiquetas estén alineadas correctamente con el fondo. Deberías ver lo siguiente en la vista Juego:
crédito:
- ¡El arte de este proyecto proviene del paquete de arte gratuito de Vicki Wenderlich! Puedes encontrar gráficos más impresionantes en gameartguppy .
- La música genial proviene de BenSound , ¡tiene bandas sonoras geniales!
- Gracias a Michael Jasper por la genialidad .
Proyecto inicial: ¡compruébalo!
Recursos – ¡Compruebe!
Da tu primer paso hacia la dominación mundial... bueno, me refiero a tu juego de defensa de torres... ¡ya terminaste!
Marcador X: Lugar
Los monstruos sólo se pueden publicar en áreas marcadas con _x_.
Para agregarlos a la escena, arrastre y suelte Imágenes\Objetos\Openspot desde el Explorador de proyectos a la vista Escena. Por ahora, la posición no importa.
Con Openspot seleccionado en Jerarquía, haga clic en Agregar componente en el Inspector y seleccione Box Collider 2D . Unity muestra colisionadores de cuadros con líneas verdes en la vista de escena. Utilizará este colisionador para detectar clics del mouse en esta ubicación.
Unity detectará automáticamente el tamaño apropiado del colisionador. ¿Qué tan genial es esto?
Siga los mismos pasos para agregar el componente Audio\Audio Source a Openspot . Configure el clip de audio de la fuente de audio en tower_place , que puede encontrar en la carpeta " Audio ", y luego desactive " Reproducir al despertar ".
Necesitas crear 11 puntos más. Si bien es tentador repetir todos estos pasos, Unity tiene una gran solución: ¡ prefabricados !
Arrastre y suelte Openspot desde la Jerarquía a la carpeta Prefabs en el Explorador de proyectos . Luego, su nombre se vuelve azul en la jerarquía para mostrar que está conectado a la casa prefabricada. como esto:
Ahora que tienes tu casa prefabricada, puedes crear tantas copias como necesites. Simplemente arrastre y suelte Openspot desde la carpeta Prefabs en el Explorador de proyectos a la vista de escena. Haga esto 11 veces para crear un total de 12 objetos Openspot en la escena.
Ahora use el Inspector para establecer las posiciones de estos 12 objetos Openspot en las siguientes coordenadas:
- (X: -5,2, Y: 3,5, Z: 0)
- (X: -2,2, Y: 3,5, Z: 0)
- (X: 0,8, Y: 3,5, Z: 0)
- (X: 3,8, Y: 3,5, Z: 0)
- (X: -3,8, Y: 0,4, Z: 0)
- (X: -0,8, Y: 0,4, Z: 0)
- (X: 2,2, Y: 0,4, Z: 0)
- (X: 5,2, Y: 0,4, Z: 0)
- (X: -5,2, Y: -3,0, Z: 0)
- (X: -2,2, Y: -3,0, Z: 0)
- (X: 0,8, Y: -3,0, Z: 0)
- (X: 3,8, Y: -3,0, Z: 0)
Cuando termine, la escena debería verse así.
lugar monstruo
Para facilitar la colocación, la carpeta prefabricada del proyecto contiene un _monster__prefab_part.
Prefabricados Monster: listos para usar
En este punto, consiste en un objeto de juego vacío que contiene las animaciones de disparo de tres sprites diferentes y sus elementos secundarios.
Cada sprite representa un monstruo con un nivel de poder diferente. La casa prefabricada también contiene un componente AudioSource que activas para reproducir un sonido cada vez que el monstruo dispara su láser.
Ahora creará un script que puede colocar Monster en Openspot
En el Explorador de proyectos , seleccione Openspot en la carpeta Prefabs . En el Inspector, haga clic en Agregar componente , luego elija Nuevo script y asígnele el nombre PlaceMonster. Seleccione C sostenido como idioma y haga clic en Crear y agregar. Desde que agregó el script a Openspot _Prefab, todos los Openspots en la escena ahora también tienen el script adjunto. ¡ordenado!
Haga doble clic en el script para abrirlo en el IDE. Luego agregue estas dos variables:
public GameObject monsterPrefab;
private GameObject monster;
Crearás una copia del objeto almacenado en él monsterPrefab
para crear el monstruo y lo almacenarás en él monster
para poder manipularlo durante el juego.
Un monstruo por ubicación
Agrega el siguiente método para permitir solo un monstruo por ubicación:
private bool CanPlaceMonster()
{
return monster == null;
}
Después de CanPlaceMonster()
verificar monster
si la variable todavía está allí null
, si lo está, significa que actualmente no hay ningún monstruo aquí y puedes poner uno.
Ahora agrega el siguiente código para colocar el monstruo cuando el jugador hace clic en este objeto del juego:
void OnMouseUp()
{
if (CanPlaceMonster())
{
monster = (GameObject)
Instantiate(monsterPrefab, transform.position, Quaternion.identity);
AudioSource audioSource = gameObject.GetComponent<AudioSource>();
audioSource.PlayOneShot(audioSource.clip);
}
}
Este código coloca un monstruo al hacer clic o hacer clic con el mouse. Entonces, ¿cómo se logra esto?
OnMouseUp
Unity llama automáticamente a esto cuando el jugador hace clic en el colisionador de física del objeto del juego.CanPlaceMonster()
Cuando se llama, si se devuelve, este método colocará un nuevo monstruotrue
.- Creas un monstruo usando
Instantiate
este método, que crea una instancia de la casa prefabricada dada con una posición y rotación específicas. En este caso, copiamonsterPrefab
, le asigna la posición del objeto del juego actual y sin rotación, convierte el resultado aGameObject
y lo almacena en un archivomonster
. - Finalmente, llama a
PlayOneShot
Reproducir el efecto de sonido adjunto alAudioSource
componente del objeto.
Ahora tu PlaceMonster
script puede colocar un nuevo monstruo, pero aún tienes que especificar la casa prefabricada.
Utilice la casa prefabricada adecuada
Guarde el archivo y vuelva a Unity.
Para asignar la variable monsterPrefab , primero seleccione Openspot en la carpeta Prefabs en el Explorador de proyectos .
En el Inspector, haga clic en el círculo a la derecha del campo Monster_Prefab del componente PlaceMonster (Script) y seleccione Monster en el cuadro de diálogo que aparece .
Eso es todo. Ejecuta la escena y construye monstruos en varios puntos x con clics o toques.
¡éxito! Puedes construir monstruos. Sin embargo, parecen una papilla extraña porque todos los sprites de tu monstruo están dibujados. A continuación, resolverá este problema.
Mejora esos monstruos
En la imagen a continuación, verás que tu monstruo parece cada vez más aterrador en niveles más altos.
¡Tan esponjoso! Pero este monstruo puede convertirse en un asesino si intentas robar sus galletas.
El guión sirve como base para implementar un sistema de actualización para monstruos. Realiza un seguimiento de qué tan poderoso debe ser el monstruo en cada nivel y, por supuesto, el nivel actual del monstruo.
Ahora agregue este script.
Seleccione Prefab/Monsters en el Navegador de proyectos. Agregue un nuevo script C# denominado MonsterData . Abra el script en el IDE y agregue el siguiente código _arriba_ de la clase.MonsterData
[System.Serializable]
public class MonsterLevel
{
public int cost;
public GameObject visualization;
}
Esto creará MonsterLevel
Agrupa el costo (en oro, que se admitirá más adelante) y una representación visual del nivel de un monstruo específico.
[System.Serializable]
Puede agregar en la parte superior para que las instancias de la clase sean editables desde el inspector. Esto te permite cambiar rápidamente todos los valores en la clase Nivel, incluso mientras el juego se está ejecutando. Es muy útil para equilibrar tu juego.
Definir nivel de monstruo
怪物等级
En este ejemplo, almacena los predefinidos 列表<T>
en formato .
¿Por qué no simplemente utilizar MonsterLevel[]
? MonsterLevel
Bueno, necesitarás el índice de un objeto específico muchas veces. Si bien no es difícil codificar esto, utilizará IndexOf()
la funcionalidad que implementa Lists
. Esta vez no es necesario volver a escribir un método. :]
En la parte superior de MonsterData.cs , agregue las siguientes declaraciones:using
using System.Collections.Generic;
Esto le brinda acceso a estructuras de datos comunes para que pueda usar la clase en sus scripts.List<T>
Nota : Los genéricos son una parte importante de C#. Le permiten definir estructuras de datos con seguridad de tipos sin comprometer tipos. Esto es muy útil para clases contenedoras como listas y colecciones. Para obtener más información sobre los genéricos, consulte Introducción a los genéricos en C# .
Ahora agregue las siguientes variables para MonsterData
almacenar MonsterLevel
la lista:
public List<MonsterLevel> levels;
Al utilizar genéricos, se asegura de que solo pueda contener objetos.levels``List``MonsterLevel
Guarde el archivo y cambie a Unity para configurar cada etapa.
Seleccione Prefab/Monsters en el Navegador de proyectos. En __Inspector__ ahora puede ver el campo "Nivel " en el componente MonsterData (script) . Establezca su _tamaño_ en 3 .
A continuación, establezca el costo de cada nivel en los siguientes valores:
- Elemento 0 : 200
- Elemento 1 : 110
- Elemento 2 : 120
Ahora asigne los valores del campo de visualización.
Expanda Prefab/Monsters en el Explorador de proyectos para que pueda ver sus elementos secundarios. Arrastre y suelte el hijo Monster0 en el campo Visualización de Element0.
Repita esto, asignando el monstruo 1 al elemento 1 y el monstruo 2 al elemento 2. Vea el GIF a continuación que demuestra este proceso:
Al seleccionar prefab_/monster, prefab_ debería verse así:
Define el nivel del monstruo en el inspector.
Definir el nivel actual
En el IDE, vuelva a MonsterData.cs y agréguele otra variable MonsterData
.
private MonsterLevel currentLevel;
En la variable privada currentLevel
almacenarás...espéralo...el nivel actual del monstruo. ]
Ahora configúrelo currentLevel
y hágalo accesible para otros scripts. Agregue lo siguiente a MonsterData
, junto con la declaración de variable de instancia:
public MonsterLevel CurrentLevel
{
get
{
return currentLevel;
}
set
{
currentLevel = value;
int currentLevelIndex = levels.IndexOf(currentLevel);
GameObject levelVisualization = levels[currentLevelIndex].visualization;
for (int i = 0; i < levels.Count; i++)
{
if (levelVisualization != null)
{
if (i == currentLevelIndex)
{
levels[i].visualization.SetActive(true);
}
else
{
levels[i].visualization.SetActive(false);
}
}
}
}
}
Existen bastantes scripts de C#, ¿eh? Échales un vistazo a todos:
- Defina las propiedades de variables_privadas
currentLevel
. _Después de definir una propiedad, puedes llamarla como cualquier otra variable: comoCurrentLevel
(desde dentro de la clase) o comomonster.CurrentLevel
(desde fuera de la clase). Puede definir un comportamiento personalizado en el método getter o setter de una propiedad, y puede controlar si una propiedad es de solo lectura, solo escritura o lectura/escritura proporcionando solo un getter, un setter o ambos. - En un captador,
currentLevel
el valor devuelto. - En la biblioteca de recursos, asigne el nuevo valor a currentLevel. A continuación, obtendrá el índice del nivel actual. Finalmente, recorre todos los niveles y establece la visualización en activa o inactiva, dependiendo del currentLevelIndex. Esto es genial porque significa que cada vez que alguien establece el currentLevel, el sprite se actualiza automáticamente. ¡Las propiedades definitivamente te serán útiles!
Agregue la siguiente implementación OnEnable
:
void OnEnable()
{
CurrentLevel = levels[0];
}
Este CurrentLevel se establecerá en la ubicación, asegurando que solo muestre el sprite correcto.
NOTA : OnEnable
Es muy importante inicializar las propiedades en lugar del OnStart
método de orden, ya que puede llamar al método de orden al crear una instancia de la casa prefabricada.
Se llamará inmediatamente cuando se cree la casa prefabricada OnEnable
(si la casa prefabricada se guarda en un estado habilitado), pero no hasta que el objeto comience a ejecutarse como parte de la escena OnStart
.
Debes verificar estos datos antes de colocar el monstruo, para poder OnEnable
inicializarlo en formato .
Guarde el archivo y cambie a Unity. Ejecute el proyecto y coloque los monstruos; ahora muestran los sprites correctos y de nivel más bajo.
Mejora esos monstruos
Vuelva a su IDE y agregue el siguiente método a MonsterData
:
public MonsterLevel GetNextLevel()
{
int currentLevelIndex = levels.IndexOf (currentLevel);
int maxLevelIndex = levels.Count - 1;
if (currentLevelIndex < maxLevelIndex)
{
return levels[currentLevelIndex+1];
}
else
{
return null;
}
}
En GetNextLevel
puedes obtener el índice del nivel actual y el 级别的
índice más alto, siempre que el monstruo no haya alcanzado el nivel máximo para regresar al siguiente nivel. En caso contrario, regresa null
.
Puedes utilizar este método para determinar si un monstruo se puede actualizar.
Se agregaron los siguientes métodos para aumentar los niveles de monstruos:
public void IncreaseLevel()
{
int currentLevelIndex = levels.IndexOf(currentLevel);
if (currentLevelIndex < levels.Count - 1)
{
CurrentLevel = levels[currentLevelIndex + 1];
}
}
Aquí puede obtener el índice del nivel actual y luego asegurarse de que no sea el nivel máximo verificando si es menor que eso. Si es así, pase al siguiente nivel.levels.Count - 1``CurrentLevel
Capacidades de actualización de prueba
Guarde el archivo, luego cambie a PlaceMonster.cs en el IDE y agregue el siguiente método nuevo:
private bool CanUpgradeMonster()
{
if (monster != null)
{
MonsterData monsterData = monster.GetComponent<MonsterData>();
MonsterLevel nextLevel = monsterData.GetNextLevel();
if (nextLevel != null)
{
return true;
}
}
return false;
}
Primero verifique si hay un monstruo que pueda actualizarse verificando 怪物
si la variable 为 null
. Si este es el caso, puedes 数据
obtener el nivel actual del monstruo a través del monstruo.
Luego pruebe si hay un nivel superior disponible, es decir, cuando GetNextLevel()
no se devuelve null
. Devolver si es posible realizar una actualización; true
de lo contrario, devolverlo false
.
Habilitar actualización de oro
Para habilitar la opción de actualización, else if
agregue la rama a OnMouseUp
:
if (CanPlaceMonster())
{
}
else if (CanUpgradeMonster())
{
monster.GetComponent<MonsterData>().IncreaseLevel();
AudioSource audioSource = gameObject.GetComponent<AudioSource>();
audioSource.PlayOneShot(audioSource.clip);
}
Comprueba si puedes CanUpgradeMonster()
actualizar usando . Si es así, puedes usar GetComponent()
el MonsterData
componente de acceso y llamarlo, IncreaseLevel(),
lo que aumentará el nivel del monstruo. Finalmente, activas la fuente de audio del monstruo.
Guarde el archivo y vuelva a Unity. Ejecuta el juego, coloca y mejora cualquier cantidad de monstruos... por ahora.
Todos los monstruos mejorados
Pagar monedas - Administrador de juegos
Ahora, todos los monstruos se pueden construir y mejorar instantáneamente, pero ¿dónde está el desafío?
Profundicemos en la cuestión del oro. El problema con el seguimiento es que necesitas compartir información entre diferentes objetos del juego.
La siguiente imagen muestra todos los objetos que estarán involucrados.
Todos los objetos del juego resaltados necesitan saber cuántas monedas de oro tiene el jugador.
Utilizará un objeto compartido al que puedan acceder otros objetos para almacenar estos datos.
Haga clic derecho en Jerarquía y seleccione Crear vacío . Nombra el nuevo objeto del juego _GameManager_.
Agregue un script C# llamado GameManagerBehavior a GameManager y abra el nuevo script en el IDE. Mostrarás el oro total del jugador en la etiqueta, así que agrega la siguiente línea en la parte superior del archivo:
using UnityEngine.UI;
Esto le brinda acceso a clases específicas de la interfaz de usuario que, por ejemplo, el proyecto utiliza para las etiquetas. Ahora agregue las siguientes variables a la clase:Text
public Text goldLabel;
Text
Esto almacenará una referencia al componente utilizado para mostrar cuántas monedas tiene el jugador.
Ahora que GameManager
conoce la etiqueta, ¿cómo se asegura de que la cantidad de oro almacenada en la variable esté sincronizada con la cantidad que se muestra en la etiqueta? Crearás una propiedad.
Agregue el siguiente código a GameManagerBehavior
:
private int gold;
public int Gold {
get
{
return gold;
}
set
{
gold = value;
goldLabel.GetComponent<Text>().text = "GOLD: " + gold;
}
}
¿Te resulta familiar? Es similar a lo que define en CurrentLevel Monster
. Primero, cree una variable privada gold
para almacenar la cantidad total actual de oro. Luego defines una Gold
propiedad llamada – creativa, ¿verdad? -- – e implementar un captador y definidor.
El captador simplemente devuelve gold
el valor. El colocador es más interesante. Además de establecer el valor de la variable, también text
establece el campo en "activado" para goldLabel
mostrar la nueva cantidad de oro.
¿Qué tan generoso te sientes? Agrega la siguiente línea para Start()
darle al jugador 1000 de oro, o asigna menos si te sientes tacaño:
Gold = 1000;
Asignar objeto de etiqueta al script
Guarde el archivo y cambie a Unity.
En la Jerarquía , seleccione GameManager . En el Inspector , haga clic en el círculo a la derecha de la Etiqueta Dorada. En el cuadro de diálogo Seleccionar texto , seleccione la pestaña Escena y seleccione GoldLabel .
Al ejecutar el escenario, la etiqueta muestra _Oro : 1000_.
Verifique la "billetera" del jugador
Abra PlaceMonster_.cs en el IDE y agregue las siguientes variables de instancia:
private GameManagerBehavior gameManager;
El componente del GameManager que utilizarás gameManager
para acceder GameManagerBehavior
a la escena . Para asignarlo, agregue lo siguiente a :Start()
gameManager = GameObject.Find("GameManager").GetComponent<GameManagerBehavior>();
Puedes usar Obtener un objeto de juego llamado GameManager, que devuelve el primer objeto de juego que encuentra con un nombre determinado. Luego, recupere sus componentes y guárdelos para su uso posterior.GameObject.Find()``GameManagerBehavior
Nota
GameManager
: Puede hacer esto configurando un campo en el Editor de Unity o agregando un método estático que devuelva una instancia singleton de la que pueda obtener游戏管理器行为
.Sin embargo, hay un método oscuro en el bloque anterior: , que es más lento en tiempo de ejecución, pero conveniente y puede usarse con precaución.
Find
¡llevar dinero!
Aún no has deducido oro, así que OnMouseUp()
agrega esta línea dos veces, reemplazando cada comentario// TODO: 扣除金币:
gameManager.Gold -= monster.GetComponent<MonsterData>().CurrentLevel.cost;
Guarde el archivo y cambie a Unity, actualice algunos monstruos y observe cómo se actualizan las lecturas de oro. Ahora se deduce el oro, pero los jugadores pueden construir monstruos siempre que tengan espacio.
¿Capacidades ilimitadas? ¡Excelente! Pero no puedes permitir que esto suceda. Los monstruos sólo deben colocarse si el jugador tiene suficientes monedas de oro.
Los monstruos necesitan monedas de oro.
Cambie a PlaceMonster.cs en el IDE y CanPlaceMonster()
reemplace el contenido con lo siguiente:
int cost = monsterPrefab.GetComponent<MonsterData>().levels[0].cost;
return monster == null && gameManager.Gold >= cost;
levels
Recupera el costo de colocar el monstruo MonsterData
. Luego compruebas que monster
no lo es null
y es gameManager.Gold
mayor que el coste.
CanUpgradeMonster()
Desafío: añádete para comprobar si el jugador tiene suficientes monedas de oro.Reemplace esta línea:
return true;
Con este:
return gameManager.Gold >= nextLevel.cost;
Esto verificará si el _oro_ que tiene el jugador excede el costo de la actualización.
Guarde y ejecute la escena en Unity. ¡Ven e intenta colocar monstruos ilimitados!
Ahora sólo puedes construir un número limitado de monstruos.
Política de la torre: enemigos, oleadas y puntos de ruta
Es hora de "allanar el camino" para tus enemigos. Los enemigos aparecen en el primer punto de ruta, pasa al siguiente punto de ruta y repite hasta que lleguen a tu cookie.
Harás marchar al enemigo:
- Define un camino para el enemigo.
- Mueve a los enemigos por el camino.
- Gira al enemigo para que mire hacia adelante.
Crear una carretera con waypoints
Haga clic derecho en la Jerarquía y seleccione Crear nulo para crear un nuevo objeto de juego nulo. Nómbrelo Carretera y asegúrese de que esté en la posición (0, 0, 0).
Ahora, haga clic derecho en Road en la Jerarquía y cree otro objeto de juego vacío como hijo de Road. Nómbrelo Waypoint0 y establezca su posición en (-12, 2, 0); aquí es donde el enemigo comenzará su ataque.
Cree cinco puntos de ruta más de la misma manera usando los siguientes nombres y ubicaciones:
- Punto de navegación 1: (X: 7, Y: 2, Z: 0)
- Punto de navegación 2: (X: 7, Y: -1, Z: 0)
- Punto de navegación 3: (X: -7.3, Y: -1, Z: 0)
- Punto de navegación 4: (X: -7,3, Y: -4,5, Z: 0)
- Punto de navegación 5: (X: 7, Y: -4,5, Z: 0)
La siguiente captura de pantalla resalta las ubicaciones de los puntos de referencia y la ruta resultante.
generar enemigos
Ahora crea algunos enemigos a los que seguir. La carpeta _Prefabs_ contiene casas prefabricadas _enemigas_. Su posición es (-20, 0, 0), por lo que la nueva instancia se generará fuera de la pantalla.
De lo contrario, está configurado de manera muy similar a la casa prefabricada de Monster, con uno AudioSource
y un niño Sprite
, y es un objeto para que puedas rotarlo más tarde sin tener que rotar la barra de salud que necesitarás pronto.
### Mueve al monstruo a la carretera.
Agregue un nuevo script de C# denominado MoveEnemy a Prefabs_\Enemy Prefabs_. Abra el script en el IDE y agregue las siguientes variables:
[HideInInspector]
public GameObject[] waypoints;
private int currentWaypoint = 0;
private float lastWaypointSwitchTime;
public float speed = 1.0f;
waypoints
Almacenar una copia del punto de ruta en una matriz mientras lo anterior garantiza que no cambie accidentalmente el campo en el __inspector__, pero aún pueda acceder a él desde otros scripts.[HideIn_inspector_]``waypoints
currentWaypoint
Realiza un seguimiento del punto de ruta que el enemigo está abandonando actualmente y lastWaypointSwitchTime
almacena la hora a la que el enemigo lo pasó. Finalmente, almacena los del enemigo speed
.
Start()
Añade esta línea en :
lastWaypointSwitchTime = Time.time;
Esto se inicializará lastWaypointSwitchTime
a la hora actual.
Para hacer que los enemigos se muevan a lo largo de un camino, agregue el siguiente código a Update()
:
Vector3 startPosition = waypoints [currentWaypoint].transform.position;
Vector3 endPosition = waypoints [currentWaypoint + 1].transform.position;
float pathLength = Vector3.Distance (startPosition, endPosition);
float totalTimeForPath = pathLength / speed;
float currentTimeOnPath = Time.time - lastWaypointSwitchTime;
gameObject.transform.position = Vector2.Lerp (startPosition, endPosition, currentTimeOnPath / totalTimeForPath);
if (gameObject.transform.position.Equals(endPosition))
{
if (currentWaypoint < waypoints.Length - 2)
{
currentWaypoint++;
lastWaypointSwitchTime = Time.time;
}
else
{
Destroy(gameObject);
AudioSource audioSource = gameObject.GetComponent<AudioSource>();
AudioSource.PlayClipAtPoint(audioSource.clip, transform.position);
}
}
Paso a paso:
- Desde la matriz de puntos de ruta, puede recuperar las posiciones inicial y final del segmento de ruta actual.
- Calcule el tiempo requerido para todo el viaje usando la fórmula tiempo = distancia/velocidad y luego determine el tiempo actual en la ruta. Usando
Vector2.Lerp
, puedes insertar la posición actual del enemigo entre la posición inicial y final del segmento. - Comprueba si el enemigo ha llegado
endPosition
. En caso afirmativo, maneje estos dos escenarios posibles:- Los enemigos aún no están en el último punto de ruta, por lo que se agregaron
currentWaypoint
y actualizaronlastWaypointSwitchTime
. Más adelante, agregarás código para rotar al enemigo de modo que también apunte en la dirección en la que se mueve. - El enemigo llega al último punto de ruta, por lo que lo destruye y activa el efecto de sonido. Más adelante también agregarás código para reducir el tamaño del reproductor
health
.
- Los enemigos aún no están en el último punto de ruta, por lo que se agregaron
Guarde el archivo y cambie a Unity.
Dale al enemigo un sentido de dirección.
En su estado actual, el enemigo desconoce el orden de las señales de tráfico.
Seleccione Road en la Jerarquía y agregue un nuevo script C# llamado SpawnEnemy . Luego ábrelo en tu IDE y agrega las siguientes variables:
public GameObject[] waypoints;
Usarás esto waypoints
para almacenar puntos de referencia en tu escena en el orden correcto.
Guarde el archivo y cambie a Unity. Seleccione Carreteras en Jerarquía y establezca el Tamaño de la matriz de puntos de referencia en 6 .
Arrastre cada elemento secundario de Road al campo, colocando Waypoint0 en el Elemento 0 , Waypoint1 en el Elemento 1, y así sucesivamente.
Ahora tienes una serie con puntos de ruta cuidadosamente ordenados para que haya un camino; ten en cuenta que nunca se retirarán; morirán intentando llegar a los dulces.
Comprueba si todo está bien
Vaya a SpawnEnemy en el IDE y agregue las siguientes variables:
public GameObject testEnemyPrefab;
Esto mantendrá testEnemyPrefab
una referencia a la casa prefabricada Enemy en .
Para crear enemigos cuando se inicia el script, agregue el siguiente código aStart():
Instantiate(testEnemyPrefab).GetComponent<MoveEnemy>().waypoints = waypoints;
Esto creará testEnemy
una nueva copia de la casa prefabricada almacenada y le asignará un punto de ruta a seguir.
Guarde el archivo y cambie a Unity. Seleccione el Camino en la Jerarquía y establezca su Enemigo de prueba en el prefabricado Enemigo .
Ejecuta el proyecto y observa enemigos caminando por este camino.
Ejecuta el proyecto para ver a los enemigos viajando por el camino.
¿Alguna vez has notado que no siempre miran hacia dónde van? ¡interesante! Si desea llevar este proyecto un paso más allá, continúe con la Parte 2 y perfeccione el proyecto para aprender cómo hacer que funcionen mejor.
Hacer un seguimiento
Has trabajado mucho y estás en camino de tener tu propio juego de defensa de torres.
Los jugadores pueden construir monstruos, pero no en cantidades ilimitadas, y hacer que un enemigo corra hacia tu galleta. Los jugadores tienen monedas de oro y también pueden mejorar monstruos.
En la segunda parte, cubrirás cómo generar una gran cantidad de enemigos y eliminarlos. Nos vemos en la segunda parte
El blogger es un jugador autodidacta. Si también eres principiante de Unity, bienvenido a unirte a mi chat grupal para ayuda y comunicación mutua: 618012892