212 lines
7.7 KiB
C#
212 lines
7.7 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using RPGCreationKit;
|
|
using RPGCreationKit.Player;
|
|
|
|
namespace RPGCreationKit
|
|
{
|
|
public class Projectile : MonoBehaviour
|
|
{
|
|
public Entity shooterEntity;
|
|
bool shotByPlayer = false;
|
|
bool shot;
|
|
bool hasCreatedItem = false;
|
|
|
|
|
|
AmmoItem thisAmmoItem; // What we've shot
|
|
WeaponItem thisWeaponItem; // With what weapon?
|
|
|
|
[SerializeField] Rigidbody rb;
|
|
[SerializeField] Collider physicalCollider;
|
|
[SerializeField] GameObject projectileInWorld; // Used to recover a projectile if it didn't hit anything
|
|
[SerializeField] TrailRenderer trail;
|
|
|
|
float damageAmount = 0f;
|
|
|
|
public void Shoot(WeaponItem _weaponItem, AmmoItem _ammoItem, Entity _shooterEntity, Vector3 _direction, bool _shotByPlayer = false)
|
|
{
|
|
shooterEntity = _shooterEntity;
|
|
shotByPlayer = _shotByPlayer;
|
|
|
|
if (rb == null)
|
|
{
|
|
rb = gameObject.AddComponent<Rigidbody>();
|
|
GetComponent<Collider>().enabled = true;
|
|
rb.isKinematic = true;
|
|
}
|
|
// Offset the arrow forward a little bit
|
|
transform.position = transform.position + transform.forward;
|
|
|
|
thisAmmoItem = _ammoItem;
|
|
thisWeaponItem = _weaponItem;
|
|
|
|
gameObject.transform.SetParent(null);
|
|
rb.isKinematic = false;
|
|
|
|
shot = true;
|
|
|
|
rb.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic;
|
|
|
|
|
|
|
|
rb.velocity = _direction * (thisWeaponItem.Reach * thisAmmoItem.Speed);
|
|
|
|
gameObject.layer = 10;
|
|
|
|
if (trail != null)
|
|
trail.enabled = true;
|
|
|
|
GetComponent<DestroyAfter>().enabled = true;
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
// Rotates the arrow towards its direction
|
|
if(shot && rb.velocity.magnitude > RCKSettings.MIN_VELOCITY_TO_CONTINUE_ROTATING_ARROW)
|
|
transform.rotation = Quaternion.LookRotation(rb.velocity);
|
|
}
|
|
|
|
bool projectileHit = false;
|
|
|
|
private void OnCollisionEnter(Collision collision)
|
|
{
|
|
if (projectileHit || !shot)
|
|
return;
|
|
|
|
if (trail != null)
|
|
trail.enabled = false;
|
|
|
|
IHittable hittable = collision.gameObject.GetComponent<IHittable>();
|
|
IDamageable damageable = collision.gameObject.GetComponentInParent<IDamageable>();
|
|
|
|
Entity entityHit = shooterEntity;
|
|
|
|
if (collision.transform.CompareTag("RPG Creation Kit/EntityShield"))
|
|
{
|
|
StickProjectile(false, collision);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
if (entityHit != null && entityHit == shooterEntity)
|
|
{
|
|
Debug.Log("Stopped!!!");
|
|
return;
|
|
}
|
|
*/
|
|
|
|
projectileHit = true;
|
|
|
|
if (hittable != null)
|
|
{
|
|
// Check for body
|
|
// Check for BodyParts, with a single swing we can hit multiple bodyparts but we don't want to be able to hit the same enemy more than once.
|
|
if (collision.transform.CompareTag("RPG Creation Kit/BodyPart"))
|
|
{
|
|
BodyPart bodyPart = collision.gameObject.GetComponent<BodyPart>();
|
|
|
|
// Check if player shot himself
|
|
if (shooterEntity == RckPlayer.GetPlayerEntity() && shotByPlayer && damageable == RckPlayer.instance.GetIDamageable())
|
|
return;
|
|
|
|
// Check for damageable, body part should always be damageable
|
|
|
|
if (damageable != null)
|
|
{
|
|
damageAmount = thisWeaponItem.Damage + thisAmmoItem.Damage;
|
|
|
|
LocationalDamage locDamage = bodyPart.GetComponentInParent<LocationalDamage>();
|
|
if(locDamage != null)
|
|
damageAmount = locDamage.CalculateLocationalDamage(bodyPart, damageAmount);
|
|
|
|
DamageContext context = new DamageContext(damageAmount, shooterEntity, thisWeaponItem, thisAmmoItem, false);
|
|
damageable.Damage(context);
|
|
|
|
if (damageable.Bleeds())
|
|
damageable.InstantiateBlood(transform.position);
|
|
}
|
|
|
|
hittable.Hit(RckPlayer.instance.mainCamera.transform.forward, RCKSettings.MELEE_ONBODY_RIGIDBODY_FORCE);
|
|
hittable.GenerateDecal();
|
|
StickProjectile(false, collision);
|
|
}
|
|
else // simple hit against an hittable
|
|
{
|
|
// Check for damageable
|
|
if (damageable != null)
|
|
{
|
|
// Check if player shot himself
|
|
if (shooterEntity == RckPlayer.GetPlayerEntity() && shotByPlayer && damageable == RckPlayer.instance.GetIDamageable())
|
|
return;
|
|
|
|
damageAmount = thisWeaponItem.Damage + thisAmmoItem.Damage;
|
|
|
|
DamageContext context = new DamageContext(damageAmount, shooterEntity, thisWeaponItem, thisAmmoItem, false);
|
|
damageable.Damage(context);
|
|
|
|
if (damageable.Bleeds())
|
|
damageable.InstantiateBlood(transform.position);
|
|
|
|
StickProjectile(false, collision);
|
|
}
|
|
else
|
|
{
|
|
StickProjectile(true, collision);
|
|
}
|
|
}
|
|
|
|
hittable.Hit(transform.forward, RCKSettings.ARROW_ONBODY_RIGIDBODY_FORCE);
|
|
hittable.GenerateDecal();
|
|
}
|
|
|
|
if (hittable == null && damageable == null && !collision.gameObject.CompareTag("Player")) // If it hit a random object
|
|
StickProjectile(true, collision);
|
|
}
|
|
|
|
public void StickProjectile(bool spawnInWorld, Collision coll)
|
|
{
|
|
// Stop the arrow
|
|
if(!spawnInWorld)
|
|
gameObject.transform.SetParent(coll.transform);
|
|
|
|
rb.collisionDetectionMode = CollisionDetectionMode.ContinuousSpeculative;
|
|
rb.isKinematic = true;
|
|
physicalCollider.enabled = false;
|
|
|
|
transform.position = coll.contacts[0].point;
|
|
|
|
//transform.rotation = Quaternion.FromToRotation(Vector3.up, coll.contacts[0].point);
|
|
|
|
// Push it trough objects
|
|
|
|
if (spawnInWorld)
|
|
{
|
|
// The arrow hit something and got sticked in it
|
|
Rigidbody pInW = projectileInWorld.GetComponent<Rigidbody>();
|
|
pInW.collisionDetectionMode = CollisionDetectionMode.ContinuousSpeculative;
|
|
pInW.isKinematic = true;
|
|
|
|
Collider[] colliders = projectileInWorld.GetComponents<Collider>();
|
|
foreach (Collider col in colliders)
|
|
if (!col.isTrigger)
|
|
col.enabled = false;
|
|
|
|
projectileInWorld.transform.SetParent(null);
|
|
projectileInWorld.layer = RCKLayers.Projectile;
|
|
|
|
pInW.transform.position = transform.position;
|
|
pInW.transform.rotation = transform.rotation;
|
|
pInW.transform.localScale = transform.localScale;
|
|
|
|
ItemInWorld projectileItem = pInW.GetComponent<ItemInWorld>();
|
|
projectileItem.isCreatedItem = true;
|
|
projectileItem.SaveOnFile(false);
|
|
hasCreatedItem = true;
|
|
|
|
projectileInWorld.SetActive(true);
|
|
Destroy(gameObject);
|
|
}
|
|
}
|
|
}
|
|
} |