Как мы все знаем во многих играх разработчикам выбирают для проведения боя пошаговую систему. Такая система пользуется популярностью в пошаговых играх, например, серия игр герои. Я разумеется не буду рассматривать весь механизм работы пошаговой игры, такие моменты как переход от “обычного” режима в режим боя. Все это реализовать будете вы, так как в каждой игре это все выглядит по своему и написать один уникальный скрипт не получится. Хотя, если там будет куча странного кода, то получится, но производительности это не добавит.
Я буду рассматривать пошаговый бой как команда на команду. Одной командой управляет игрок, другой командой компьютер. Не забываем, что все приходит во время игры и игрок не должен понимать, что ему противостоит компьютер, поэтому обязательно добавляйте в код какие-нибудь паузы которые задержат решение компьютера о том как проводить атаку и все такое. На моей карте боя будут две команды по два бойца. Процесс боя будет заключаться в следующем: Атакует одна из команд, какая именно будет зависит от входных параметров. У меня их нет потому, что у меня одна сцена. В вашем случае должен будет быть входной параметр, который будет определять, кто первым атакует. Когда все члены атакующей команды завершат свои атаки, передаем управление второй команде.
В моем случае управляющий скрипт выглядит так:
public class BattleSystemScript : MonoBehaviour
{
/// <summary>
/// Сейчас ходит команда слева?
/// </summary>
public bool hodLeft = true;
/// <summary>
/// Массив мобов игрока
/// </summary>
public BSMobScript[] playerGroup;
/// <summary>
/// Массив мобов противника
/// </summary>
public BSMobScript[] enemyGroup;
/// <summary>
/// Указатель на скрипт управления игрока
/// </summary>
public BattleSystemPlayerControlScript playerScript;
/// <summary>
/// Указатель на спрайты выделения объектов
/// </summary>
public Transform selectObj, targetObj;
/// <summary>
/// Указатели на выделенные объекты
/// </summary>
public BSMobScript selectMob, targetMob;
/// <summary>
/// Указатель на скрипт управления компьютера
/// </summary>
public ComputerControlScript compScript;
/// <summary>
/// При старте сцены расчитываем границы камеры, потом устаналиваем поцизиции мобов, чтобы они не
/// выходили за пределы сцены.
/// </summary>
void Start()
{
playerScript.enabled = hodLeft;
compScript.enabled = !hodLeft;
float dist = Vector3.Distance(transform.position, Camera.main.transform.position);
float left = Camera.main.ViewportToWorldPoint(new Vector3(0, 0, dist)).x;
float right = Camera.main.ViewportToWorldPoint(new Vector3(1, 0, dist)).x;
float bottom = Camera.main.ViewportToWorldPoint(new Vector3(0, 0, dist)).y;
float top = Camera.main.ViewportToWorldPoint(new Vector3(0, 1, dist)).y;
Vector2[] position = new Vector2[8];
position[0] = new Vector2(left / 4, top / 4 + top / 2);
position[1] = new Vector2(left / 4, top / 4);
position[2] = new Vector2(left / 4, bottom / 4);
position[3] = new Vector2(left / 4, bottom / 4 + bottom / 2);
position[4] = new Vector2(left / 2 + left / 4, top / 4 + top / 2);
position[5] = new Vector2(left / 2 + left / 4, top / 4);
position[6] = new Vector2(left / 2 + left / 4, bottom / 4);
position[7] = new Vector2(left / 2 + left / 4, bottom / 4 + bottom / 2);
for (int i = 0; i < playerGroup.Length; i++)
{
playerGroup[i].transform.position = new Vector3(position[i].x, position[i].y, 1);
playerGroup[i].battleScript = this;
}
for (int i = 0; i < 4; i++)
position[i].x = right / 4;
for (int i = 4; i < 8; i++)
position[i].x = right / 2 + right / 4;
for (int i = 0; i < enemyGroup.Length; i++)
{
enemyGroup[i].transform.position = new Vector3(position[i].x, position[i].y, 1);
enemyGroup[i].battleScript = this;
}
foreach (var item in hodLeft ? playerGroup : enemyGroup)
item.hodFinish = false;
}
void Update()
{
/*Проверяем все ли мобы текущей команды завершили свои ходы, если да передаем ход
другой команде*/
if ((hodLeft ? playerGroup : enemyGroup).All(x => x.hodFinish || x.IsDead()))
{
hodLeft = !hodLeft;
Debug.Log("Ход передан " + (hodLeft ? "игроку" : "компьютеру"));
playerScript.enabled = hodLeft;
compScript.enabled = !hodLeft;
selectObj.position = new Vector3(0, 0, 1000);
targetObj.position = new Vector3(0, 0, 1000);
selectMob = null;
targetMob = null;
foreach (var item in playerGroup)
item.hodFinish = false;
foreach (var item in enemyGroup)
item.hodFinish = false;
}
/*Ниже идут две проверки, которые проверяет факт победы той или другой стороны. Проверяя все ли мобы
одной из команд мертвы*/
if (playerGroup.All(x => x.IsDead()))
{
Debug.Log("Компьютер победил");
this.enabled = false;
playerScript.enabled = false;
compScript.enabled = false;
}
if (enemyGroup.All(x => x.IsDead()))
{
Debug.Log("Игрок победил");
this.enabled = false;
playerScript.enabled = false;
compScript.enabled = false;
}
}
}
Скрипт который висит на мобе:
public class BSMobScript : MonoBehaviour
{
/// <summary>
/// Указатель на управляющий скрипт
/// </summary>
public BattleSystemScript battleScript;
/// <summary>
/// Завершен ли ход данным мобов
/// </summary>
public bool hodFinish = false;
/// <summary>
/// Уровень здоровья
/// </summary>
public float health = 100;
/// <summary>
/// Уровень дамага
/// </summary>
public float damage = 40;
/// <summary>
/// Моб мертв?
/// </summary>
public bool IsDead()
{
return health <= 0;
}
/// <summary>
/// Если моб мертв выключаем его и убираем выледение с данного моба.
/// </summary>
void Update()
{
if (health <= 0)
{
if (battleScript.targetObj.position.x == transform.position.x && battleScript.targetObj.position.y == transform.position.y)
battleScript.targetObj.position = new Vector3(0, 0, 1000);
gameObject.SetActive(false);
}
}
/// <summary>
/// Данный метод используется игроком. Проверяет какой команде принадлежит моб и выделяет его соответствующим
/// выделением.
/// </summary>
private void OnMouseDown()
{
foreach (var item in battleScript.hodLeft ? battleScript.playerGroup : battleScript.enemyGroup)
{
if (this == item)
{
if (hodFinish == false)
{
battleScript.selectObj.position = new Vector3(transform.position.x, transform.position.y, 2);
battleScript.selectMob = this;
}
return;
}
}
foreach (var item in battleScript.hodLeft ? battleScript.enemyGroup : battleScript.playerGroup)
{
if (this == item)
{
battleScript.targetObj.position = new Vector3(transform.position.x, transform.position.y, 2);
battleScript.targetMob = this;
return;
}
}
}
}
Скрипт игрока:
public class BattleSystemPlayerControlScript : MonoBehaviour {
public BattleSystemScript battleScript;
/// <summary>
/// Атаковать выделенного противника
/// </summary>
public void ClickAttack()
{
if (battleScript.selectMob != null && battleScript.targetMob != null && battleScript.hodLeft)
{
battleScript.targetMob.health -= battleScript.selectMob.damage;
battleScript.selectMob.hodFinish = true;
battleScript.selectMob = null;
battleScript.selectObj.position = new Vector3(0, 0, 1000);
}
}
}
Скрипт компьютера:
public class ComputerControlScript : MonoBehaviour {
/// <summary>
/// Указатель на управляющий скрипт
/// </summary>
public BattleSystemScript battleScript;
/// <summary>
/// Время последней атаки
/// </summary>
float time1 = float.PositiveInfinity;
/// <summary>
/// Устанавливаем текущее игровое время
/// </summary>
void Start()
{
time1 = UnityEngine.Time.time;
}
/// <summary>
/// Флаги проведения определенных операций
/// </summary>
public bool attack, select, target;
void Update()
{
//Если прошло более 3 секунд
if (Time.time - time1 > 3f)
{
//Если мы еще не выделили своего бойца и прошло более 4 секунд
if (select == false && Time.time - time1 > 4f)
{
//Находим бойца, который еще не производил атаку
var list = battleScript.enemyGroup.Where(x => x.health > 0 && !x.hodFinish);
if (list.Any())
{
var item = list.ElementAt(Random.Range(0, list.Count()));
battleScript.selectObj.position = new Vector3(item.transform.position.x, item.transform.position.y, 2);
battleScript.selectMob = item;
select = true;
}
}
//Если еще не выбрана цель
else if (target == false && select && Time.time - time1 > 5f)
{
//Находим живую цель и выбираем ее
var list = battleScript.playerGroup.Where(x => x.health > 0);
if (list.Any())
{
var item = list.ElementAt(Random.Range(0, list.Count()));
battleScript.targetObj.position = new Vector3(item.transform.position.x, item.transform.position.y, 2);
battleScript.targetMob = item;
target = true;
}
}
//Если еще не произведена атака, то производим
else if (attack == false && target && Time.time - time1 > 6f)
{
battleScript.targetMob.health -= battleScript.selectMob.damage;
battleScript.selectMob.hodFinish = true;
battleScript.selectMob = null;
battleScript.selectObj.position = new Vector3(0, 0, 1000);
attack = true;
}
//Сбрасываем флаги и время последней атаки
else if (select && target && attack)
{
select = false;
target = false;
attack = false;
time1 = UnityEngine.Time.time;
}
}
}
}
Чтобы наглядно увидеть принцип работы можете посмотреть видео.
|