В этом дружелюбном туториале по Unity 2D мы создадим простую космическую стрелялку. Ты будешь управлять кораблём, стрелять лазерами и побеждать врагов — шаг за шагом. Опыт не нужен. Просто установи Unity 6.0 LTS (или любую версию с поддержкой 2D) и следуй за нами.
Каждый шаг — короткий, понятный и спокойный. Никакой спешки. Учишься ли ты для себя или начинаешь первый проект — добро пожаловать!
Начнём с создания нового проекта Unity 2D, выбрав шаблон Universal 2D Core. Это даст нам чистую сцену — с готовой поддержкой спрайтов, физики и кода.
Подсказка: Назови проект SpaceShooter
или придумай
что-нибудь весёлое — имя на твой вкус.
Давай перенесём нашу графику в Unity.
Скачай изображение space-sprites.png
— в нём есть всё
нужное: враги, корабль игрока, снаряды и другое.
Открой проект Unity и импортируй файл:
После импорта выбери space-sprites.png в окне Assets. В панели Inspector проверь:
Sprite (2D and UI)
Multiple
Затем нажми Apply, чтобы применить настройки.
Подсказка: “Multiple” означает, что в изображении несколько спрайтов — например, персонажи, снаряды, объекты и т.д.
Unity должен автоматически нарезать изображение при импорте. Если этого не произошло, нажми Open Sprite Editor, затем Slice с выбранным Type: Automatic. Потом нажми Apply.
Подсказка: Если автоматическая нарезка не сработает, можно использовать режим по сетке или настроить вручную. Главное — не забудь нажать Apply перед выходом из редактора.
Построим корабль, которым будем управлять. В этой игре мы не будем использовать клавиатуру — только мышь. Корабль должен лететь туда, куда мы кликаем.
Начни с того, что перетащи синий спрайт корабля в сцену. Unity создаст
новый объект. Переименуй его в Player
и задай тег
Player.
Теперь добавим физику. С выделенным объектом Player
нажми
Add Component и добавь:
В настройках Rigidbody 2D:
0
Interpolate
Затем создай новый скрипт C# с именем PlayerMove
и
прикрепи его к объекту Player
.
using UnityEngine;
public class PlayerMove : MonoBehaviour
{
// Точка, куда кликнул игрок
Vector3 clickPos;
// Вектор движения к цели
Vector3 move;
// Скорость корабля
public float speed = 1f;
// Ссылка на Rigidbody2D
Rigidbody2D rb;
void Start()
{
rb = GetComponent<Rigidbody2D>();
clickPos = transform.position;
}
void Update()
{
if (Input.GetMouseButton(0))
{
clickPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
}
move = clickPos - transform.position;
}
void FixedUpdate()
{
rb.linearVelocity = new Vector2(move.x, move.y) * speed;
}
}
Сохрани скрипт и вернись в Unity. В Inspector задай
Speed
равным 1
. Нажми Play и проверь —
корабль должен двигаться к точке клика.
Подсказка: Положение мыши даётся в экранных координатах — в пикселях.
Чтобы использовать его в сцене, преобразуй с помощью
Camera.ScreenToWorldPoint
. Возвращается точка в мире, но
Z-координата будет совпадать с Z-камеры. В 2D это не критично — нас
интересуют только X и Y.
Теперь дадим нашему кораблю возможность стрелять. Добавим лазер.
Перетащи оранжевый спрайт лазера в сцену. Unity создаст новый объект.
Назови его Laser
. В Inspector задай
Order in Layer равным -10
, чтобы он был
позади корабля. При необходимости подгони размер — пусть выглядит
аккуратно.
Добавь к объекту Laser
следующие компоненты:
0
Теперь создай новый C#-скрипт с именем LaserShot
. Он
будет подталкивать лазер вверх при создании и удалять его, когда тот
выходит за экран.
using UnityEngine;
public class LaserShot : MonoBehaviour
{
Rigidbody2D rb;
public float force = 5f;
void Start()
{
rb = GetComponent<Rigidbody2D>();
Vector3 direction = new Vector3(0, force, 0);
rb.AddForce(direction, ForceMode2D.Impulse);
}
void OnBecameInvisible()
{
Destroy(gameObject);
}
}
Прикрепи скрипт к объекту Laser
и задай значение
Force
, например 5
.
Затем перетащи объект Laser
в окно
Assets, чтобы создать префаб. Unity сохранит его
автоматически. Теперь можно удалить лазер из сцены — позже мы будем
создавать его скриптом.
Лазер уже умеет летать — теперь сделаем так, чтобы корабль мог его запускать.
Мы создадим новый скрипт, который будет порождать лазер при нажатии правой кнопки мыши. Чтобы избежать слишком частой стрельбы, мы добавим короткую задержку между выстрелами с помощью корутины.
Создай новый скрипт C# и назови его PlayerShoot
. Он будет
выглядеть так:
using UnityEngine;
using System.Collections;
public class PlayerShoot : MonoBehaviour
{
// Префаб лазера
public GameObject laser;
// Задержка между выстрелами
public float delayTime = 0.5f;
// Можно ли стрелять сейчас
bool canShoot = true;
void Update()
{
// Проверяем: нажата ли правая кнопка мыши и можно ли стрелять
if (canShoot && Input.GetMouseButton(1))
{
canShoot = false;
// Создаём лазер в позиции игрока
Instantiate(laser, transform.position, transform.rotation);
// Запускаем таймер перезарядки
StartCoroutine(NoFire());
}
}
IEnumerator NoFire()
{
yield return new WaitForSeconds(delayTime);
canShoot = true;
}
}
Прикрепи скрипт PlayerShoot
к объекту игрока. Перетащи
префаб Laser
в поле Laser в инспекторе.
Установи Delay Time в 0.5
.
Нажми Play и проверь — теперь при правом клике корабль должен стрелять лазером!
Теперь немного опасности. Мы добавим маленькие вражеские мины, которые будут плавно двигаться вниз к игроку.
Перетащи спрайт мины в сцену. Unity создаст новый объект. Переименуй
его в Mine
. Установи Order in Layer на
-5
(между кораблём и лазером). При необходимости подгони
размер.
Добавь к мине следующие компоненты:
0
Создай новый тег Enemy
и присвой его мине.
Теперь создай скрипт C# с именем MineMove
. Он будет
двигать мину вниз, уничтожать её при выходе за экран и перезапускать
сцену, если она столкнётся с игроком.
using UnityEngine;
using System.Collections;
using UnityEngine.SceneManagement;
public class MineMove : MonoBehaviour
{
public float speed = 1f;
Rigidbody2D rb;
void Start()
{
rb = GetComponent<Rigidbody2D>();
Vector3 move = new Vector3(0, -1, 0);
rb.linearVelocity = move * speed;
}
void OnBecameInvisible()
{
Destroy(gameObject);
}
void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "Player")
{
Destroy(gameObject);
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
}
}
}
Прикрепи этот скрипт к объекту Mine
. Задай
Speed равной 1
. Затем перетащи мину в
окно Assets, чтобы создать префаб. После этого можешь
удалить её из сцены — позже мы будем создавать её скриптом.
Давайте автоматизируем волны врагов. Мы настроим спаунер, который будет создавать новые мины в случайных позициях.
Зайди в GameObject → Create Empty. Unity создаст
пустой объект. Назови его MineSpawner
. Можно задать ему
кастомную иконку, чтобы его было проще найти в окне сцены.
Перемести MineSpawner
в левый верхний угол видимой части
экрана. Убедись, что его Z-позиция равна
0
(так как это 2D-игра).
С выделенным MineSpawner
нажми
Ctrl + D (или правая кнопка → Duplicate). Назови
новый объект RightPosition
и сделай его
дочерним элементом MineSpawner. Перемести его в
правый верхний угол экрана. Z-позицию тоже поставь на 0
.
Создай новый скрипт C# с именем ObjectSpawner
. Он будет
выбирать случайную X-позицию между двумя точками и спаунить там мину с
задержкой.
using UnityEngine;
using System.Collections;
public class ObjectSpawner : MonoBehaviour
{
public Transform RightPosition;
public float spawnDelay = 5f;
public GameObject Item;
void Start()
{
InvokeRepeating("Spawn", spawnDelay, spawnDelay);
}
void Spawn()
{
Vector3 spawnPos = new Vector3(
Random.Range(transform.position.x, RightPosition.position.x),
transform.position.y,
0);
Instantiate(Item, spawnPos, transform.rotation);
}
}
Прикрепи скрипт к объекту MineSpawner
. Перетащи
RightPosition
в поле Right Position, а
префаб Mine
— в поле Item. Установи
Spawn Delay на 5
.
Нажми Play — теперь мины будут появляться сверху в случайных местах.
Сейчас лазеры просто пролетают сквозь мины — никакой реакции. Давай это исправим: добавим минам очки здоровья и сделаем так, чтобы лазеры наносили урон.
Создай новый C#-скрипт с именем HpController
. Он будет
хранить значение здоровья и удалять объект, когда оно станет нулевым.
using UnityEngine;
public class HpController : MonoBehaviour
{
// Очки здоровья
public int hp = 3;
// Метод для получения урона
void MakeDamage(int damage)
{
hp -= damage;
// Если здоровье закончилось — уничтожить объект
if (hp <= 0)
{
Destroy(gameObject);
}
}
}
Выбери префаб Mine
в окне Assets и добавь к нему скрипт
HpController
. Установи hp равным
3
.
Теперь открой скрипт LaserShot
. Мы добавим проверку
столкновений и передадим урон врагу.
using UnityEngine;
public class LaserShot : MonoBehaviour
{
// Ссылка на Rigidbody2D
Rigidbody2D rb;
// Сила, с которой движется лазер
public float force = 10f;
// Урон, наносимый врагам
public int damage = 1;
void Start()
{
rb = GetComponent<Rigidbody2D>();
Vector3 direction = new Vector3(0, force, 0);
rb.AddForce(direction, ForceMode2D.Impulse);
}
void OnBecameInvisible()
{
Destroy(gameObject);
}
void OnTriggerEnter2D(Collider2D other)
{
// Проверяем, попали ли во врага
if (other.gameObject.tag == "Enemy")
{
// Передаём урон, если объект умеет его принимать
other.gameObject.SendMessage("MakeDamage", damage, SendMessageOptions.DontRequireReceiver);
// Уничтожаем лазер
Destroy(gameObject);
}
}
}
Выбери префаб Laser
и в Inspector установи значение
Damage равным 1
.
Нажми Play и проверь — теперь минам потребуется три попадания, чтобы быть уничтоженными.
Добавим врага, который умеет стрелять в ответ. Мы повторно используем уже готовую заготовку и немного её изменим.
Перетащи префаб Mine
в сцену. Переименуй его в
Enemy-1
. Замени спрайт на изображение вражеского корабля.
Установи HP в 1
.
Кликни правой кнопкой по Circle Collider 2D и удали
его. Вместо него добавь Box Collider 2D. Затем
перетащи Enemy-1
в окно Assets, чтобы создать новый
префаб. После этого можешь удалить его из сцены.
Теперь добавим врагу ракету. Перетащи спрайт ракеты в сцену и назови
объект Rocket
. Установи
Order in Layer равным -10
. Добавь
Box Collider 2D и включи Is Trigger.
Добавь Rigidbody2D со значениями
Gravity Scale = 0 и
Interpolate = Interpolate.
Создай новый скрипт C# с именем EnemyBullet
. Он будет
выполнять следующее:
using UnityEngine;
public class EnemyBullet : MonoBehaviour
{
GameObject player;
Rigidbody2D rb;
public float force = 3f;
public int damage = 1;
void Start()
{
rb = GetComponent<Rigidbody2D>();
player = GameObject.FindWithTag("Player");
if (player != null)
{
Vector3 dir = player.transform.position - transform.position;
transform.up = dir;
rb.AddRelativeForce(transform.up * force, ForceMode2D.Impulse);
}
else
{
Destroy(gameObject);
}
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.tag == "Player")
{
other.gameObject.SendMessage("MakeDamage", damage, SendMessageOptions.DontRequireReceiver);
Destroy(gameObject);
}
}
void OnBecameInvisible()
{
Destroy(gameObject);
}
}
Прикрепи скрипт EnemyBullet
к объекту
Rocket
. Установи Force равным
3
, а Damage — 1
. Затем
создай префаб, перетащив ракету в окно Assets, и удали её из сцены.
Пора дать вражескому кораблю огневую мощь. Мы добавим скрипт стрельбы, который будет периодически создавать ракету, а остальное ракета сделает сама.
Создай новый скрипт C# и назови его EnemyShoot
.
using UnityEngine;
using System.Collections;
public class EnemyShoot : MonoBehaviour
{
// Префаб ракеты
public GameObject bullet;
// Задержка между выстрелами
public float fireDelay = 2f;
// Ссылка на игрока
GameObject player;
// Можно ли сейчас стрелять
bool canShoot = true;
void Start()
{
player = GameObject.FindWithTag("Player");
}
void Update()
{
if (canShoot && player != null)
{
canShoot = false;
// Создаём ракету в позиции врага
Instantiate(bullet, transform.position, Quaternion.identity);
// Запускаем задержку перед следующим выстрелом
StartCoroutine(firePause());
}
}
IEnumerator firePause()
{
yield return new WaitForSeconds(fireDelay);
canShoot = true;
}
}
Выбери префаб Enemy-1
в окне Assets. Добавь к нему скрипт
EnemyShoot
. В поле Bullet перетащи
префаб Rocket
. Установи
Fire Delay равным 2
.
Наш префаб Enemy-1
готов. Теперь сделаем так, чтобы он
появлялся в сцене, как и мины. Вместо создания второго спаунера мы
улучшим уже существующий, добавив возможность выбирать объект
случайным образом из нескольких.
Открой скрипт ObjectSpawner
и обнови его, чтобы он
использовал массив префабов:
using UnityEngine;
public class ObjectSpawner : MonoBehaviour
{
public Transform RightPosition;
public float spawnDelay;
public GameObject[] Item;
void Start()
{
InvokeRepeating("Spawn", spawnDelay, spawnDelay);
}
void Spawn()
{
Vector3 spawnPos = new Vector3(
Random.Range(transform.position.x, RightPosition.position.x),
transform.position.y,
0
);
int i = Random.Range(0, Item.Length);
Instantiate(Item[i], spawnPos, transform.rotation);
}
}
В объекте MineSpawner
(в сцене) посмотри на обновлённый
список Item. Добавь в него префабы
Mine
и Enemy-1
. Unity сам подберёт нужный
размер массива.
У игрока до сих пор нет видимого здоровья. Давай добавим простую панель UI, чтобы отображать текущий уровень жизни на экране. Мы сделаем горизонтальный индикатор здоровья с помощью встроенной системы UI в Unity.
Зайди в GameObject → UI → Image. Unity создаст
Canvas
с объектом Image
внутри. Переименуй
Image в HealthBar
.
Выдели Canvas
. В Inspector, в компоненте
Canvas Scaler, установи:
UI Scale Mode на Scale With Screen Size
.
Дважды кликни по Canvas
в Hierarchy — сцена отдалится, и
ты увидишь область UI. Выдели HealthBar
и с помощью
Rect Tool растяни его в форму полосы. Размести там,
где удобно по компоновке.
С выделенным HealthBar
:
Background
Filled
Horizontal
Left
Давайте теперь свяжем индикатор здоровья с игровым процессом. Мы напишем скрипт, который будет отслеживать HP игрока и обновлять панель здоровья.
Создай новый C#-скрипт с именем PlayerHp
:
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class PlayerHp : MonoBehaviour
{
public GameObject HealthBar;
Image img;
public int hp;
float maxHp;
void Start()
{
img = HealthBar.GetComponent<Image>();
maxHp = hp;
img.fillAmount = hp / maxHp;
}
void MakeDamage(int damage)
{
hp -= damage;
if (hp <= 0)
{
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
}
img.fillAmount = hp / maxHp;
}
}
Перейди в сцену и выбери объект Player. Добавь к нему
скрипт PlayerHp
. Перетащи HealthBar
(из
Canvas) в поле Health Bar. Установи значение
HP равным 10
.
Начнём с того, что превратим фон сцены в глубокий космос. Выдели
Main Camera в Hierarchy. В Inspector, в разделе
Environment, установи цвет
Background в black
.
Чтобы создать эффект космоса, мы используем встроенную систему частиц Unity — она будет имитировать движущиеся звёзды.
Stars
.10
и
X Rotation в 90
.
0.2
(или на свой
вкус).
Box
15
— чтобы звёзды покрывали
широкую область.
-100
— чтобы
звёзды были позади всех объектов.
Давайте дадим вражеской ракете полноценный звук выстрела. Когда ракета появляется, мы проиграем короткий звуковой эффект с помощью встроенной аудиосистемы Unity.
Ты можешь скачать звуки, используемые в этом туториале, здесь:
Открой скрипт EnemyBullet
и добавь такую переменную:
// переменная для звукового клипа
public AudioClip BulletSound;
Затем в методе Start()
добавь эту строку после запуска
ракеты:
AudioSource.PlayClipAtPoint(BulletSound, transform.position);
Это создаст временный звуковой объект в сцене, который проиграет звук и исчезнет.
Вот полный обновлённый скрипт EnemyBullet
с поддержкой
звука:
using UnityEngine;
public class EnemyBullet : MonoBehaviour
{
GameObject player;
Rigidbody2D rb;
public float force = 3f;
public int damage = 1;
public AudioClip BulletSound;
void Start()
{
rb = GetComponent<Rigidbody2D>();
player = GameObject.FindWithTag("Player");
if (player != null)
{
Vector3 dir = player.transform.position - transform.position;
transform.up = dir;
rb.AddRelativeForce(transform.up * force, ForceMode2D.Impulse);
// Проигрываем звук выстрела
AudioSource.PlayClipAtPoint(BulletSound, transform.position);
}
else
{
Destroy(gameObject);
}
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.tag == "Player")
{
other.gameObject.SendMessage("MakeDamage", damage, SendMessageOptions.DontRequireReceiver);
Destroy(gameObject);
}
}
void OnBecameInvisible()
{
Destroy(gameObject);
}
}
Теперь выбери префаб Rocket. Присвой звук
LaserSound
полю Bullet Sound в скрипте
EnemyBullet
.
💡 Ты можешь заменить этот звук на любой другой, импортировав свой
файл .wav
и назначив его в поле
AudioClip.
Как и у вражеских ракет, мы хотим добавить звук выстрела для лазера
игрока. Открой скрипт LaserShot
и обнови его следующим
образом:
using UnityEngine;
public class LaserShot : MonoBehaviour
{
Rigidbody2D rb;
public float force = 10f;
public int damage = 1;
public AudioClip LaserSound;
void Start()
{
rb = GetComponent<Rigidbody2D>();
Vector3 direction = new Vector3(0, force, 0);
rb.AddForce(direction, ForceMode2D.Impulse);
AudioSource.PlayClipAtPoint(LaserSound, transform.position);
}
void OnBecameInvisible()
{
Destroy(gameObject);
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.tag == "Enemy")
{
other.gameObject.SendMessage("MakeDamage", damage, SendMessageOptions.DontRequireReceiver);
Destroy(gameObject);
}
}
}
После обновления скрипта выбери префаб Laser в окне
Assets и назначь аудиофайл LaserSound.wav
в поле
Laser Sound.
💡 Если ты хочешь использовать свой звук вместо предложенного — просто
перетащи свой файл .wav
в папку
Assets/sound
и укажи его в инспекторе.
Когда враги и мины уничтожаются, пусть воспроизводится короткий звук
взрыва. Для этого немного расширим скрипт HpController
:
добавим звуковое поле и проиграем звук, когда здоровье обнуляется.
using UnityEngine;
public class HpController : MonoBehaviour
{
public int hp = 3;
public AudioClip ExplosionsSound;
void MakeDamage(int damage)
{
hp -= damage;
if (hp <= 0)
{
AudioSource.PlayClipAtPoint(ExplosionsSound, transform.position);
Destroy(gameObject);
}
}
}
Выдели префабы Mine и Enemy-1 в окне
Assets
. В компоненте
HpController назначь файл Boom.wav
в
поле Explosions Sound.
Готово! Теперь каждый раз при уничтожении врага или мины будет проигрываться приятный звуковой эффект.
💡 Можно использовать и собственный звук — просто перетащи свой
.wav
в папку Assets/sound
и назначь его.
Добавим визуальный эффект при уничтожении врагов (мин или Enemy-1).
Создай новый объект Particle System и назови его
KiavoBoom
. Установи Position и
Rotation в 0
. В Inspector задай
следующие параметры:
Перейди в модуль Emission, добавь Burst во
время 0.0
с количеством 30
.
В модуле Shape выбери Shape = Circle
и
Radius = 0.1
.
Включи Color over Lifetime. В редакторе цвета задай
финальный Alpha = 0
, а начальные и конечные
цвета выбери на свой вкус. В модуле Renderer установи
Order in Layer = 10
(находится в
настройках Renderer).
Добавь скрипт TimeDestroyer
к объекту KiavoBoom и задай
Time To Destroy = 2
. Затем сделай из
него префаб и удали из сцены.
Позже ты можешь поэкспериментировать с более яркими эффектами или цветами — а пока это простой и быстрый эффект взрыва.
Теперь у нас есть префаб взрыва. Давайте сделать так, чтобы он
появлялся при уничтожении врага (например, мины или Enemy-1). Открой
скрипт HpController
и измени его так:
using UnityEngine;
public class HpController : MonoBehaviour
{
public int hp = 3;
// Префаб взрыва
public GameObject Explosion;
// Звук взрыва
public AudioClip ExplosionsSound;
void MakeDamage(int damage)
{
hp -= damage;
if (hp <= 0)
{
AudioSource.PlayClipAtPoint(ExplosionsSound, transform.position);
Instantiate(Explosion, transform.position, Quaternion.identity);
Destroy(gameObject);
}
}
}
Теперь выбери префабы Mine и
Enemy-1. В компоненте
HpController
назначь префаб взрыва (например,
KiavoBoom
) в поле Explosion.
KiavoBoom
теперь подключён в
HpController
каждого врага. При уничтожении — звук и
частицы.
Наша игра завершена — в ней есть движение, враги, стрельба, звук и интерфейс. Этот туториал был посвящён созданию простой, но рабочей 2D-космической стрелялки с использованием базовых возможностей Unity.
Конечно, ты можешь продолжать развивать её: добавить анимации, визуальные эффекты, волны врагов, счёт, жизни, меню, босса, фоновую музыку… даже летающих куриц или космический чай ☕🛸
Но наша цель была — показать чистую и понятную основу. И теперь она у тебя есть.
💡 Продолжай экспериментировать, играй, и создавай свою собственную версию!