Это заключительная часть урока по созданию Tower Defense на Unity 5 и в этой части мы реализуем все то, что будет связанно с деньгами или очками в нашей игре — добавление денег от уничтожения противников, покупка башен и отнимание денег при прохождении противника через конечную точку.
Первым делом создадим один общий скрипт, в котором будем хранить наши префабы башен и их цену, назовем его TurretBlueprint.
using UnityEngine;
using System.Collections;
[System.Serializable]
public class TurretBlueprint {
public GameObject prefab; // префаб башни
public int cost; // цена
}
Этот скрипт ни куда «вешать» не нужно он останется в таком виде у нас в проекте. Далее создадим еще один скрипт , где будем хранить начальное количество денег при старте сцены/ игры, назовем его PlayerStats.
using UnityEngine;
using System.Collections;
public class PlayerStats : MonoBehaviour {
public static int Money;
public int startMoney = 400;// стартовое количество денег
void Start () {
Money = startMoney;
}
}
Поместим этот скрипт на объект Start. Ну и на основании этих скриптов изменяем наши созданные ранее скрипты, для того чтобы реализовать возможность покупки башен. Откройте скрипт Shop, теперь он будет выглядеть так.
using UnityEngine;
public class Shop : MonoBehaviour {
BuildManager buildManager;
public TurretBlueprint standartTurret;
public TurretBlueprint missileLaumcher;
void Start() {
buildManager = BuildManager.instance;
}
public void SelectStandartTurret() {
buildManager.SelectedTurretToBuild(standartTurret);
}
public void SelectMissileTurret()
{
buildManager.SelectedTurretToBuild(missileLaumcher);
}
}Следующий скрипт Node:
using UnityEngine;
using UnityEngine.EventSystems;
using System.Collections;
public class Node : MonoBehaviour {
public Color hoverColor;
public Color notEnoughMoneyColor; //добавим цвет при недостатке денег
private Renderer rend;
private Color startColor;
public GameObject turret;
public Vector3 positionOffset;
BuildManager buildManager;
void Start() {
rend = GetComponent();
startColor = rend.material.color;
buildManager = BuildManager.instance;
}
public Vector3 GetBuildPosition() {
return transform.position + positionOffset;
}
void OnMouseEnter() {
if (EventSystem.current.IsPointerOverGameObject())
return;
if (!buildManager.CanBuild)
return;
if (buildManager.HasMoney)
{
rend.material.color = hoverColor;
}
else {
rend.material.color = notEnoughMoneyColor;
}
}
void OnMouseDown() {
if (EventSystem.current.IsPointerOverGameObject())
return;
if (!buildManager.CanBuild)
return;
if (turret != null) {
return;
}
buildManager.BuildTurretOn(this);
}
void OnMouseExit() {
rend.material.color = startColor;
}
}
И скрипт BuildManager:
using UnityEngine;
public class BuildManager : MonoBehaviour {
public static BuildManager instance;
private TurretBlueprint TurretToBuilt;
public bool CanBuild { get { return TurretToBuilt != null; } }
public bool HasMoney { get { return PlayerStats.Money >= TurretToBuilt.cost; } }
void Awake() {
if (instance != null) {
Debug.LogError("More than one BuiltManager in scene!");
return;
}
instance = this;
}
public GameObject standartTurretPrefab;
public GameObject anotherTurretPrefab;
public void BuildTurretOn(Node node) {
if (PlayerStats.Money < TurretToBuilt.cost) {
return;
}
PlayerStats.Money -= TurretToBuilt.cost; // отнимаем стоимость башни при покупке
GameObject turret = (GameObject) Instantiate(TurretToBuilt.prefab, node.GetBuildPosition(),Quaternion.identity);
node.turret = turret;
}
public void SelectedTurretToBuild(TurretBlueprint turret) {
TurretToBuilt = turret;
}
}
/*Будьте внимательны! В скриптах изменены названия некоторых функций, поэтому на кнопках в обработчике OnClick следует так же их изменить (иначе кнопки не сработают)*/

В объекте Shop добавим наши префабы башен и укажем их цену.

На префабе платформы укажем второй цвет, этот цвет будет принимать платформа в том случае, когда не будет хватать денег на покупку башни.

Сохраним сцену и проверим работоспособность игры.
Перейдем к оформлению сцены. Добавим новый элемент Canvas на сцену. В этом элементе будут отображаться наше количество денег. Я настрою его примерно так:

К Канвасу добавим элемент Text (назовем Money) и тоже его настроим.

Создадим новый скрипт MonyUI и переместим его на компонент Money.
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class MonyUI : MonoBehaviour {
public Text moneyText;
void Update() {
moneyText.text = PlayerStats.Money.ToString();// текст будет равен значению денег
}
}
Следующий наш шаг, добавление стоимости башни. Вернемся в компонент Canvas, где находится наш Shop, и к компоненту Button добавим Panel.

К Panel добавим Text.

И изменим скрипт Bullet, сделаем так чтобы добавлялись деньги при уничтожении противника.
using UnityEngine;
using System.Collections;
public class Bullet : MonoBehaviour {
private Transform target;
public float speed = 70f;
public GameObject bulletEffect;
public float explosionRadius = 0f;
public int plusMoney = 1; //количество денег при уничтожении противника
public void Seek (Transform _target) {
target = _target;
}
void Update () {
if (target == null) {
Destroy (gameObject);
return;
}
Vector3 dir = target.position - transform.position;
float distanceThisFrame = speed * Time.deltaTime;
if (dir.magnitude <= distanceThisFrame) { HitTarget (); return; } transform.Translate (dir.normalized * distanceThisFrame, Space.World); transform.LookAt(target); } void HitTarget (){ GameObject effectIns= (GameObject) Instantiate(bulletEffect, transform.position, transform. rotation); Destroy(effectIns, 5f); if (explosionRadius > 0f)
{
Explode();
}
else {
Damage(target);
}
Destroy(gameObject);
}
void Explode() {
Collider[] colliders = Physics.OverlapSphere(transform.position, explosionRadius);
foreach (Collider collider in colliders) {
if (collider.tag == "Enemy") {
Damage(collider.transform);
}
}
}
void Damage(Transform enemy) {
Destroy(enemy.gameObject);
PlayerStats.Money = PlayerStats.Money + plusMoney; // добавляем деньги при уничтожении
}
void OnDrawGizmosSelected() {
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(transform.position, explosionRadius);
}
}
Скрипт Enemy, здесь можно реализовать два варианта: первый при достижении противника конечной точки игра заканчивается и второй, при достижении противника конечной точки будут уменьшаться деньги, я сделаю именно так.
using UnityEngine;
using System.Collections;
public class Enemy : MonoBehaviour {
public float speed = 10f;
private Transform target;
private int wavepointIndex =0;
public int minusMoney = 10; // количество при достижении противника конечной точки
void Start (){
target = weapoints.points [0];
}
void Update(){
Vector3 dir = target.position - transform.position;
transform.Translate (dir.normalized * speed * Time.deltaTime, Space.World);
if (Vector3.Distance (transform.position, target.position) <= 0.3f) { GetNextWaypoint (); } } void GetNextWaypoint () { if (wavepointIndex >= weapoints.points.Length - 1)
{
Destroy (gameObject);
PlayerStats.Money = PlayerStats.Money - minusMoney; // отнимаем деньги при достижении конечной точки
return;
}
wavepointIndex++;
target = weapoints.points [wavepointIndex];
}
}
Проверяем игру.

Видим что теперь появилась цена башни, добавляются деньги при уничтожении противника и уменьшаются при достижении противника контрольной точки.
На этом серию уроком я думаю можно окончить, дальнейшая разработка игры и оформление будет зависеть только от ваших способностей и фантазии, можно добавить звуки выстрелов, уничтожения, оформить немного сцену визуально, добавить полноценное меню, первоначальную сцену и сцену завершения игры, вообщем все в ваших силах. Удачных проектов!
Данная серия уроков была переведена (канал Brackeys) и немного изменена.
Скачать проект с игрой можно здесь.
После небольших доработок получается примерно так:









Спасибо Вам за такие подробные уроки!