После выпуска первой статьи, однозначно было решено, что кнопочное управление, которое в ней описывалось — совершенно не удобно. Поэтому, Управление в игре было переделано на джойстик. Далее, к сожалению игра не прошла модерацию в плеймаркете. В прошедшую пятницу мне пришло уведомление о том, что проект отклонён по причине сбора метаданных. К слову сказать, мой первый платформер «Рыцарь Кадавар» так же в первый раз был отклонён, по причине якобы запроса на разрешение управления звонками и просмотра смс (что было полнейшей глупостью со стороны их бота. Игра не требовала никаких разрешений). Google тогда потребовал от меня письменное уведомление о том, зачем мне это нужно. Но, всё закончилось тем, что я исправил пару ошибок, которые заметил и отправил игру на повторную модерацию. Она была успешно добавлена в плеймаркет. Сейчас, я планирую сделать точно так же и с этой игрой.
Итак, как только была создана вторая по счёту сцена, автоматически был закрыт паттерн
Сцена
фрагмент уровня/мира, основанный на концепции, обычно является преодолеваемой трудностью.
Бонус
собираемый предмет, оказывающий на игроков положительное влияние
Реализуем 2 вида бонусов для Лукаса:
- Аптечка, которая будет выпадать при уничтожении монстров
- Сундуки с мечами, которые Лукас сможет метать во врагов
Чтобы реализовать бонус с аптечкой, необходимо модифицировать префабы с монстрами. Конкретнее, указать место, откуда будут выпадать бонусы.
Затем, модифицируем скрипт Enemy.cs:
/* Определяем, выпадет ли бонус для игрока при смерти монстра*/ [SerializeField] private GameObject bonusPref; // Префаб бонуса [SerializeField] private Transform instBonus; // Откуда будет вылетать бонус [SerializeField] private int isBonus; // Реализуем с помощью рандома, будет ли выдан бонус /* Конец определения бонусов*/ public void ifDie() { if (Damage(0) <= 0) { isBonus = Random.Range(0,3); if (isBonus == 0) { Instantiate(bonusPref, instBonus.position, instBonus.rotation); } Destroy(this.gameObject); } }
Вызываем функцию с возвращаемым типом Damage(0) и проверяем, возвращает ли Health 0. Если да, что вызываем генератор случайных чисел. Если генератор останавливается на выборе цифры 0, то выбрасываем игроку бонус и уничтожаем монстра.
Далее описываем, что можно сделать с этим бонусом. Для этого создадим его префаб с компонентами SpriteRenderer, BoxCollider2D и Rigidbody2D. Так же, создадим скрипт, который будет отвечать за то, что необходимо сделать, если яблоко столкнулось с игроком:
public void OnTriggerEnter2D(Collider2D collision) { switch (collision.gameObject.tag) { case "Player": { HeroScript.Health = 100; Destroy(this.gameObject); } break; } }
Посмотреть превью ролик
Далее, реализовываем бонус выпадения мечей. Его можно реализовать по тому же принципу, как в первой части реализовывалось выпадение брёвен. Интересная часть будет заключаться в том, что когда Лукас подберёт мечи, их необходимо будет бросать только в зоне видимости противников, а не то тогда, когда Лукас собирает брёвна. Ведь в том виде, в котором сейчас реализована кнопка Атаки\сбора предметов сделала бы именно так. Мечи выбрасывались в любой ситуации. Для этого модифицируем код скрипта атаки\сбора:
/* Определяем поля для метания меча */ [SerializeField] private GameObject swordPref; // Префаб хранения меча [SerializeField] private Transform instSword; // Откуда выпускать префаб меча [SerializeField] private float swordSpeed; // Скорость полёта мечей private float attackInBoxX, attackInBoxY; // Для отрисовки куба /* Конец определения полей для метания мечей */ // ED значит EnemyDamage Collider2D[] ED = Physics2D.OverlapBoxAll(Hero.position, new Vector2(attackInBoxX, attackInBoxY), 12, lEnemy); { if (ED.Length > 0) { if (InventoryOnHero.swordCount == 0) { Debug.Log("Нечем стрелять"); } if (InventoryOnHero.swordCount > 0) { instantiateSword(); InventoryOnHero.swordCount = InventoryOnHero.swordCount - 1; } else { for (int i = 0; i < ED.Length; i++) { ED[i].GetComponent<Enemy>().Damage(1); } } } }
Что означают данные строчки кода? Сперва, мы определяем массив коллайдеров и проверяем всё, что попало в наш куб
Collider2D[] ED = Physics2D.OverlapBoxAll(Hero.position, new Vector2(attackInBoxX, attackInBoxY), lEnemy);
Обратите внимание в передаваемые параметры, они сильно отличаются от тех, что используются для OvelapCircleAll. Ключевые параметры —
Vector2(attackInBoxX, attackInBoxY)
Затем выполняется условие, если массив коллайдеров больше 0, то мы проверяем инвентарь на наличие мечей. Если количество мечей равно 0, то ничего не делаем и выполняем метод
ED[i].GetComponent<Enemy>().Damage(1);
как если бы это был обычный удар. Если больше 0, то выпускаем меч и уменьшаем количество мечей на 1.
Далее, реализация метода instantiateSword();
private void instantiateSword() { GameObject newArrow = Instantiate(swordPref) as GameObject; newArrow.transform.position = instSword.transform.position; Rigidbody2D rb = newArrow.GetComponent<Rigidbody2D>(); if (GameObject.Find("Hero").GetComponent<HeroScript>().localScale.x > 0) { rb.velocity = new Vector3(swordSpeed, 0, 0); } else { rb.velocity = new Vector3(-swordSpeed, 0, 0); newArrow.transform.Rotate(0,0,-180); } }
Если вы хорошо читали предыдущую статью, то могли заметить, что данный код напоминает участок кода, который отвечает за стрельбу подсолнуха. В данный участок кода добавлены строки, которые отвечают за определение масштаба Лукаса. То есть, смотрит он налево или направо:
(GameObject.Find("Hero").GetComponent<HeroScript>().localScale.x > 0)
Если Лукас смотрит налево, то
rb.velocity = new Vector3(-swordSpeed, 0, 0); newArrow.transform.Rotate(0,0,-180);
меч летит налево и так же вращаем его на 180 градусов.
Посмотреть превью ролик
Выполнив данное действие, мы автоматически закрыли ещё 1 паттерн:
Объект
любая сущность, появляющаяся в игровой сцене и способная менять своё состояние. В число объектов входят опасности, враги, бонусы и т.д.
Хотя, вероятнее всего, данный паттерн был реализован раньше, когда был запрограммирован первый монстр.
В итоге, на данный момент осталось не реализовано 3 паттерна:
- Недостижимая область
- Механика
- Босс
Механика на данный момент вызывает у меня повышенный интерес. Потому что я не могу сказать себе, что я точно понимаю то, что разные люди вкладывают в это определение.
Далее, недостижимая область. В данном вопросе я займусь на некоторое время вопросами дизайна уровней. Во-первых, потому что я хочу сделать третий уровень тёмным. Вероятнее всего, пещеру или подземелье. С возможностью реализовать световые эффекты.
Босс! Так же останется вишенкой на торте. Я хочу сделать его максимально самостоятельным и с возможностью менять своё обличье.
Ссылка на мою витрину приложений в Google Play
Ссылка на Лукаса Джонса на sourceforge.net
Чувствуйте себя свободным и пишите комментарии на хабре или мне на почту worldofonehero@gmail.com.
Благодарю за прочтение, удачи.
ссылка на оригинал статьи https://habr.com/ru/post/460561/