Стрельба, перезарядка, разброс пуль [2D]

Скрипт оружия для двухмерного платформера. В наличии два режима стрельбы, префабом или рейкастом, первый вариант подойдет для, например, плазменного оружия, а второй вариант для обычного пистолета или автомата. Есть учет количества патронов и перезарядка, как вручную, так и автоматически, если магазин пустой, а игрок нажимает клавишу выстрела. Кроме этого, мы добавили возможность настроить разброс пуль и добавили настройки скорострельности. Плюс, оружие может выстреливать сразу несколько пуль/рейкастов одновременно. Таким образом, данный скрипт можно настроить как: пистолет, автомат, дробовик и т.п.

Важное примечание! При создании модели персонажа с оружием, по умолчанию, и "лицо" персонажа и ствол пушки, должны быть "смотреть" вправо. Это необходимо для корректного переключения влево/вправо для модели. Саму модель можно ставить в любую часть экрана, главное чтобы на старте сцены, персонаж смотрел в правую сторону.

Для взаимодействия с объектом, куда попадает пуля:

using System.Collections;
using UnityEngine;

public class Weapon2DTarget : MonoBehaviour {

	public void DoAction(float damage)
	{
		// делаем что-нибудь...
	}
}

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

Теперь, сделаем префаб пули:

using System.Collections;
using UnityEngine;

public class Weapon2DBullet : MonoBehaviour {

	[SerializeField] private float damage = 15;

	void Start()
	{
		Destroy(gameObject, 10);
	}

	void OnTriggerEnter2D(Collider2D coll)
	{
		if(!coll.isTrigger)
		{
			Weapon2DTarget target = coll.GetComponent<Weapon2DTarget>();
			if(target != null) target.DoAction(damage);
			Destroy(gameObject);
		}
	}
}

Стрельба, перезарядка, разброс пуль [2D]

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

И сам скрипт оружия:

using System.Collections;
using UnityEngine;

public class Weapon2D : MonoBehaviour {

	[Header("Настройки префаба:")]
	[SerializeField] private Rigidbody2D bulletPrefab; // если префаба пули нет, то оружие будет стрелять рейкастом
	[SerializeField] private float bulletSpeed = 5; // скорость префаба пули
	[Header("Общие параметры:")]
	[SerializeField] private Transform shootPoint; // точка оружия, откуда должны вылетать пули
	[SerializeField] private float fireRate = 1; // скорострельность
	[SerializeField] [Range(1, 5)] private int shootCount = 1; // выстрелов одновременно, например, дробовик может выстреливать больше одной пули
	[SerializeField] [Range(0.9f, 1f)] private float accuracy = 1; // разброс пуль, 1 = 100% точности
	[SerializeField] private int bulletCount = 15; // объем магазина
	[SerializeField] private float reloadTime = 2.5f; // время перезарядки в секундах
	[Header("Объект вращения:")]
	[SerializeField] private Transform zRotate; // объект вращения, например, само оружие
	[SerializeField] private float minAngle = -40; // ограничение по углам
	[SerializeField] private float maxAngle = 40;
	[Header("Родитель персонажа:")]
	[SerializeField] private Transform flipParent; // родитель для этого оружия (персонаж)
	[Header("Настройки рейкаста:")]
	[SerializeField] private float rayDistance = 100; // длинна луча
	[SerializeField] private LayerMask rayLayerMask; // маска цели
	[SerializeField] private float rayDamage = 15; // урон, наносимый цели
	private int bulletCountInt;
	private float invert, timeout, reloadTimeout;
	private Vector3 mouse, direction;
	private bool reload;

	void Awake()
	{
		bulletCountInt = bulletCount;
	}

	IEnumerator WeaponReload()
	{
		// запуск процесса перезарядки
		reloadTimeout = 0;

		while(true)
		{
			yield return null;

			// процесс перезарядки
			reloadTimeout += Time.deltaTime;

			if(reloadTimeout > reloadTime)
			{
				// перезарядка завершена
				bulletCountInt = bulletCount;
				reload = false;
				break;
			}
		}
	}

	void Flip()
	{
		Vector3 theScale = flipParent.localScale;
		theScale.x *= -1;
		invert *= -1;
		flipParent.localScale = theScale;
	}

	void LookAtMouse()
	{
		Vector3 mousePosMain = Input.mousePosition;
		mousePosMain.z = Camera.main.transform.position.z; 
		mouse = Camera.main.ScreenToWorldPoint(mousePosMain);
		mouse.z = 0;
		Vector3 lookPos = zRotate.position;
		lookPos.z = 0;
		lookPos = mouse - lookPos;
		float angle  = Mathf.Atan2(lookPos.y, lookPos.x * invert) * Mathf.Rad2Deg;
		angle = Mathf.Clamp(angle, minAngle, maxAngle);
		zRotate.rotation = Quaternion.AngleAxis(angle * invert, Vector3.forward);
	}

	void GetReload()
	{
		bulletCountInt = 0;
		reload = true;
		StartCoroutine(WeaponReload());
	}

	void LateUpdate()
	{
		invert = Mathf.Sign(flipParent.localScale.x);

		if(zRotate != null) LookAtMouse();

		if(mouse.x < flipParent.position.x && invert == 1) Flip();
		else if(mouse.x > flipParent.position.x && invert == -1) Flip();

		if(reload) return;

		if(Input.GetMouseButton(1)) // выстрел ПКМ
		{
			if(bulletCountInt <= 0)
			{
				GetReload();
				return;
			}

			timeout += Time.deltaTime;
			if(timeout > fireRate)
			{
				timeout = 0;
				Shoot();
			}
		}
		else
		{
			timeout = Mathf.Infinity;
		}

		if(Input.GetKeyDown(KeyCode.R)) // перезарядка "R"
		{
			if(bulletCountInt != bulletCount) GetReload();
		}
	}

	void BulletShoot()
	{
		Rigidbody2D clone = Instantiate(bulletPrefab, shootPoint.position, Quaternion.identity) as Rigidbody2D;
		clone.velocity = direction * bulletSpeed;
		clone.transform.right = direction;
	}

	void RayShoot()
	{
		RaycastHit2D hit = Physics2D.Raycast(shootPoint.position, direction, rayDistance, rayLayerMask);

		if(hit.transform != null)
		{
			Weapon2DTarget target = hit.transform.GetComponent<Weapon2DTarget>();
			if(target != null)  target.DoAction(rayDamage);
		}
	}

	void Shoot()
	{
		for(int i = 0; i < shootCount; i++)
		{
			direction = (shootPoint.right + (Vector3)(Random.insideUnitCircle * (1f - accuracy))).normalized * invert;
			if(bulletPrefab == null) RayShoot(); else BulletShoot();
		}

		bulletCountInt--;
	}
}

Важно! Скрипт управляет вращением оружия по оси Z, можно указать торс персонажа или только модель оружия. И еще скрипт управляет разворотом персонажа, так как это напрямую зависит от положения курсора. Поэтому если в вашем скрипте персонажа есть функция разворота, ее необходимо отключить.

Скачать демо:

У вас нет доступа!
Тестировалось на: Unity 2017.1.1

Комментариев 7

Офлайн
и ни какого видео((((
Офлайн
SlavaXD 7 октября 2017
зато можно загрузить проект на движок и посмотреть
Офлайн
igor1906 10 октября 2017
А подскажите пожалуйста как сделать гильзы при стрельбе?
Офлайн
Light 10 октября 2017
igor1906, ну это обычные 2д ритжитбоди объекты, думаю лучше всего сделать пул из 10-15 элементов, и прогонять их циклом во время стрельбы.
Офлайн
TeDj 21 октября 2017
Добрый день!
Скажите, пожалуйста, в новой версии 2017.2.0 добавили Tileset. Можно ли его использовать для match3? Просто раньше сетку создавали с помощью скрипта и добавляли элементы префабами. А с новым Tileset'ом , если смотреть оптимистично, дело было бы проще. В инете пока нет такой информации
Офлайн
TEEAAA 2 ноября 2017
а как на андроид?
Офлайн
Light 13 ноября 2017
TeDj, это инструмент для редактора, чтобы быстро "рисовать" игровую карту.
Информация
Посетители, находящиеся в группе Гости, не могут оставлять комментарии к данной публикации.
  • Дешевый хостинг
  • Яндекс.Метрика