Characters
This commit is contained in:
123
Game/Scripts/WeaponSystem/Projectile.cs
Normal file
123
Game/Scripts/WeaponSystem/Projectile.cs
Normal file
@@ -0,0 +1,123 @@
|
||||
using MegaKoop.Game.Combat;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MegaKoop.Game.WeaponSystem
|
||||
{
|
||||
public class Projectile : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private float hitRadius = 0.05f;
|
||||
[SerializeField] private LayerMask hitMask = Physics.DefaultRaycastLayers;
|
||||
[SerializeField] private bool alignToVelocity = true;
|
||||
|
||||
private Vector3 direction;
|
||||
private float speed;
|
||||
private float damage;
|
||||
private float lifetime;
|
||||
private float timeAlive;
|
||||
private Team sourceTeam;
|
||||
private GameObject owner;
|
||||
private Collider[] projectileColliders;
|
||||
|
||||
public void Initialize(Vector3 shotDirection, float projectileSpeed, float damageAmount, float projectileLifetime, GameObject projectileOwner, Team ownerTeam, Collider[] ownerColliders, LayerMask mask)
|
||||
{
|
||||
direction = shotDirection.sqrMagnitude > 0f ? shotDirection.normalized : transform.forward;
|
||||
speed = Mathf.Max(0f, projectileSpeed);
|
||||
damage = Mathf.Max(0f, damageAmount);
|
||||
lifetime = Mathf.Max(0.01f, projectileLifetime);
|
||||
owner = projectileOwner;
|
||||
sourceTeam = ownerTeam;
|
||||
hitMask = mask;
|
||||
timeAlive = 0f;
|
||||
|
||||
projectileColliders ??= GetComponentsInChildren<Collider>();
|
||||
if (ownerColliders != null && projectileColliders != null)
|
||||
{
|
||||
foreach (Collider ownerCollider in ownerColliders)
|
||||
{
|
||||
if (ownerCollider == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (Collider projectileCollider in projectileColliders)
|
||||
{
|
||||
if (projectileCollider == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Physics.IgnoreCollision(projectileCollider, ownerCollider, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
float deltaTime = Time.deltaTime;
|
||||
Vector3 displacement = direction * speed * deltaTime;
|
||||
float distance = displacement.magnitude;
|
||||
|
||||
if (distance > 0f)
|
||||
{
|
||||
if (Physics.SphereCast(transform.position, hitRadius, direction, out RaycastHit hitInfo, distance, hitMask, QueryTriggerInteraction.Ignore))
|
||||
{
|
||||
TryHandleHit(hitInfo.collider, hitInfo.point, hitInfo.normal);
|
||||
return;
|
||||
}
|
||||
|
||||
transform.position += displacement;
|
||||
}
|
||||
|
||||
if (alignToVelocity && distance > 0f)
|
||||
{
|
||||
transform.forward = direction;
|
||||
}
|
||||
|
||||
timeAlive += deltaTime;
|
||||
if (timeAlive >= lifetime)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTriggerEnter(Collider other)
|
||||
{
|
||||
TryHandleHit(other, transform.position, -direction);
|
||||
}
|
||||
|
||||
private void TryHandleHit(Collider other, Vector3 hitPoint, Vector3 hitNormal)
|
||||
{
|
||||
if (other == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (owner != null)
|
||||
{
|
||||
if (other.transform.IsChildOf(owner.transform))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
IDamageable damageable = other.GetComponentInParent<IDamageable>();
|
||||
if (damageable != null && damageable.IsAlive)
|
||||
{
|
||||
bool isFriendly = damageable.Team == sourceTeam && damageable.Team != Team.Neutral;
|
||||
if (isFriendly)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (damage > 0f)
|
||||
{
|
||||
var payload = new DamagePayload(damage, hitPoint, hitNormal, owner, sourceTeam, other.gameObject);
|
||||
damageable.ApplyDamage(payload);
|
||||
}
|
||||
}
|
||||
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Game/Scripts/WeaponSystem/Projectile.cs.meta
Normal file
2
Game/Scripts/WeaponSystem/Projectile.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 038cb7cb48b0cb10da7ebba4ba473c63
|
||||
48
Game/Scripts/WeaponSystem/WeaponDefinition.cs
Normal file
48
Game/Scripts/WeaponSystem/WeaponDefinition.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace MegaKoop.Game.WeaponSystem
|
||||
{
|
||||
[CreateAssetMenu(fileName = "WeaponDefinition", menuName = "MegaKoop/Weapons/Weapon Definition", order = 0)]
|
||||
public class WeaponDefinition : ScriptableObject
|
||||
{
|
||||
[Header("Presentation")]
|
||||
[SerializeField] private string displayName = "Weapon";
|
||||
[SerializeField] private WeaponView viewPrefab;
|
||||
|
||||
[Header("Projectile")]
|
||||
[SerializeField] private Projectile projectilePrefab;
|
||||
[SerializeField] private float projectileSpeed = 25f;
|
||||
[SerializeField] private float projectileLifetime = 3f;
|
||||
|
||||
[Header("Firing")]
|
||||
[SerializeField] private float shotsPerSecond = 2f;
|
||||
[SerializeField] private float baseDamage = 10f;
|
||||
[SerializeField] private float range = 25f;
|
||||
[SerializeField] private int projectilesPerShot = 1;
|
||||
[SerializeField, Range(0f, 45f)] private float spreadAngle = 0f;
|
||||
[SerializeField] private LayerMask hitMask = Physics.DefaultRaycastLayers;
|
||||
|
||||
public string DisplayName => displayName;
|
||||
public WeaponView ViewPrefab => viewPrefab;
|
||||
public Projectile ProjectilePrefab => projectilePrefab;
|
||||
public float ProjectileSpeed => Mathf.Max(0f, projectileSpeed);
|
||||
public float ProjectileLifetime => Mathf.Max(0.05f, projectileLifetime);
|
||||
public float FireInterval => shotsPerSecond <= 0f ? float.MaxValue : 1f / shotsPerSecond;
|
||||
public float Damage => Mathf.Max(0f, baseDamage);
|
||||
public float Range => Mathf.Max(0f, range);
|
||||
public int ProjectilesPerShot => Mathf.Max(1, projectilesPerShot);
|
||||
public float SpreadAngle => Mathf.Abs(spreadAngle);
|
||||
public LayerMask HitMask => hitMask;
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
projectileSpeed = Mathf.Max(0f, projectileSpeed);
|
||||
projectileLifetime = Mathf.Max(0.05f, projectileLifetime);
|
||||
shotsPerSecond = Mathf.Max(0.01f, shotsPerSecond);
|
||||
baseDamage = Mathf.Max(0f, baseDamage);
|
||||
range = Mathf.Max(0f, range);
|
||||
projectilesPerShot = Mathf.Max(1, projectilesPerShot);
|
||||
spreadAngle = Mathf.Clamp(spreadAngle, 0f, 90f);
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Game/Scripts/WeaponSystem/WeaponDefinition.cs.meta
Normal file
2
Game/Scripts/WeaponSystem/WeaponDefinition.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2fd5ff95d6e2be5d09b6c054570cef0a
|
||||
43
Game/Scripts/WeaponSystem/WeaponView.cs
Normal file
43
Game/Scripts/WeaponSystem/WeaponView.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace MegaKoop.Game.WeaponSystem
|
||||
{
|
||||
public class WeaponView : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private Transform[] muzzles;
|
||||
|
||||
public Transform[] Muzzles => muzzles;
|
||||
|
||||
public Transform GetMuzzle(int index = 0)
|
||||
{
|
||||
if (muzzles == null || muzzles.Length == 0)
|
||||
{
|
||||
return transform;
|
||||
}
|
||||
|
||||
index = Mathf.Clamp(index, 0, muzzles.Length - 1);
|
||||
return muzzles[index] == null ? transform : muzzles[index];
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private void OnDrawGizmosSelected()
|
||||
{
|
||||
if (muzzles == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Gizmos.color = Color.cyan;
|
||||
foreach (Transform muzzle in muzzles)
|
||||
{
|
||||
if (muzzle == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Gizmos.DrawLine(muzzle.position, muzzle.position + muzzle.forward * 0.5f);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
2
Game/Scripts/WeaponSystem/WeaponView.cs.meta
Normal file
2
Game/Scripts/WeaponSystem/WeaponView.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5590d430717d95f878b7929af7bf28ff
|
||||
Reference in New Issue
Block a user