Wouldnt it be better to just use one of the events: onPassDamage, onCastCollider or onDestroyProjectile and check for the Hittable and pass damage there? You would then just need to attach that script to the projectile, instead of directly changing the src code.
A quick and dirty test works using the following. Just attach it to the projectile.
using Invector;
using Invector.vShooter;
using Knife.RealBlood;
using UnityEngine;
public class RealBloodProjectile : MonoBehaviour {
vProjectileControl projectile;
DamageData[] damage;
void Awake() {
projectile = GetComponent<vProjectileControl>();
projectile.onCastCollider.AddListener(OnHit);
projectile.onPassDamage.AddListener(OnPassDamage);
}
void OnHit(RaycastHit hitInfo) {
damage = new DamageData[] {
new DamageData {
direction = transform.forward,
normal = hitInfo.normal,
point = hitInfo.point
}
};
}
void OnPassDamage(vDamage d) {
if (damage != null) {
var hittable = d.receiver.GetComponent<IHittable>();
if (hittable != null) {
damage[0].amount = d.damageValue;
hittable.TakeDamage(damage);
damage = null;
}
}
}
}
Hi rasto61,
I got around to using your script but it doesn't seem to work with skinned meshes. The colliders on the joints/bones for skinned mesh objects have to be on the TransparentFX layer. Putting them on the Default layer makes blood splatters collide with them and hang in mid-air which looks very weird. I've tried modifying your code to account for this but have had no luck.
Anyway, Shooter Template got updated today so here's the modified vProjectileControl.cs if anyone is interested. It would be nice and neat to have a separate event script but I can't figure it out yet.
Also to get this to work:
1) Copy and paste the following code into
vProjectileControl.cs2) Select
vDefaultBullet in Assets->Invector-3rdPersonController->Shooter->Weapon->_bullets and select
Default and
TransparentFX layers for "
ShotMask" layermask.
3) Drag one of the Real Blood prefabs into you scene and shoot it with the assault rifle. They're located in Assets->Knife->Real Blood->Prefabs->Demo
using System.Collections.Generic;
using UnityEngine;
using Knife.RealBlood;
namespace Invector.vShooter
{
using Invector.vEventSystems;
[vClassHeader("Projectile Control", "The damage value is changed from minDamage, maxDamage, DropOffStart, DropOffEnd of the ShooterWeapon", openClose = false)]
public class vProjectileControl : vMonoBehaviour
{
public vBulletLifeSettings bulletLifeSettings;
public int bulletLife = 100;
public bool debugTrajetory;
public bool debugHittedObject;
public vDamage damage;
public float forceMultiplier = 1;
public bool destroyOnCast = true;
public ProjectilePassDamage onPassDamage;
public ProjectileCastColliderEvent onCastCollider;
public ProjectileCastColliderEvent onDestroyProjectile;
public vProjectileInstantiateData instantiateData;
internal bool damageByDistance;
internal float velocity = 580;
internal int minDamage;
internal int maxDamage;
internal float minDamageDistance = 8f;
internal float maxDamageDistance = 50f;
internal Vector3 startPosition;
internal LayerMask hitLayer = -1;
internal List<string> ignoreTags = new List<string>();
internal Transform shooterTransform;
protected Vector3 previousPosition;
protected Rigidbody _rigidBody;
protected Color debugColor = Color.green;
protected int debugLife;
protected float castDist;
// -----------ADDED VARIABLES----------------------
public LayerMask ShotMask;
public float Damage2 = 10f;
// -----------ADDED VARIABLES-----------------------
protected virtual void Start()
{
transform.SetParent(vObjectContainer.root, true);
debugLife = bulletLife;
_rigidBody = GetComponent<Rigidbody>();
startPosition = transform.position;
previousPosition = transform.position - transform.forward * 0.1f;
}
protected virtual void Update()
{
// ----------------MODIFIED CODE--------------
Ray r = new Ray(Camera.main.transform.position, Camera.main.transform.forward);
RaycastHit hitInfo;
RaycastHit hitInfo2;
// ----------------MODIFIED CODE----------------
if (_rigidBody.velocity.magnitude > 1)
transform.rotation = Quaternion.LookRotation(_rigidBody.velocity.normalized, transform.up);
if (Physics.Linecast(previousPosition, transform.position + transform.forward * 0.5f, out hitInfo, hitLayer))
{
if (!hitInfo.collider)
return;
var dist = Vector3.Distance(startPosition, transform.position) + castDist;
if (!(ignoreTags.Contains(hitInfo.collider.gameObject.tag) || (shooterTransform != null && hitInfo.collider.transform.IsChildOf(shooterTransform))))
{
if (debugHittedObject) Debug.Log(hitInfo.collider.gameObject.name, hitInfo.collider);
onCastCollider.Invoke(hitInfo);
damage.damageValue = maxDamage;
if (damageByDistance)
{
var result = 0f;
var damageDifence = maxDamage - minDamage;
//Calc damage per distance
if (dist - minDamageDistance >= 0)
{
int percentComplete = (int)System.Math.Round((double)(100 * (dist - minDamageDistance)) / (maxDamageDistance - minDamageDistance));
result = Mathf.Clamp(percentComplete * 0.01f, 0, 1f);
damage.damageValue = maxDamage - (int)(damageDifence * result);
}
else
damage.damageValue = maxDamage;
}
damage.hitPosition = hitInfo.point;
damage.receiver = hitInfo.collider.transform;
damage.force = transform.forward * damage.damageValue * forceMultiplier;
if (damage.damageValue > 0)
{
onPassDamage.Invoke(damage);
hitInfo.collider.gameObject.ApplyDamage(damage, damage.sender.GetComponent<vIMeleeFighter>());
}
var rigb = hitInfo.collider.gameObject.GetComponent<Rigidbody>();
if (rigb && !hitInfo.collider.gameObject.isStatic)
{
rigb.AddForce(transform.forward * damage.damageValue * forceMultiplier, ForceMode.Impulse);
}
transform.position = hitInfo.point + transform.forward * 0.02f;
startPosition = transform.position;
castDist = dist;
// ----------------- MODIFIED CODE HERE -------------------------------------
if (Physics.Raycast(r, out hitInfo2, 1000, ShotMask, QueryTriggerInteraction.Ignore))
{
var hittable = hitInfo2.collider.GetComponent<IHittable>();
if (hittable != null)
{
DamageData[] damage2 = new DamageData[1]
{
new DamageData()
{
amount = Damage2,
direction = r.direction,
normal = hitInfo2.normal,
point = hitInfo2.point
}
};
hittable.TakeDamage(damage2);
// ----------------- MODIFIED CODE HERE -------------------------------------
if (debugTrajetory) Debug.DrawLine(transform.position, previousPosition, debugColor, 10f);
if (destroyOnCast)
{
if (bulletLifeSettings)
{
var bulletLifeInfo = bulletLifeSettings.GetReduceLife(hitInfo.collider.gameObject.tag, hitInfo.collider.gameObject.layer);
bulletLife -= bulletLifeInfo.lostLife;
if (debugTrajetory) DrawHitPoint(hitInfo.point);
var crossed = false;
if (bulletLife > 0 && !bulletLifeInfo.ricochet)
{
for (float i = 0; i <= bulletLifeInfo.maxThicknessToCross; i += 0.01f)
{
var point = transform.position + transform.forward * (i);
if (!hitInfo.collider.bounds.Contains(point))
{
hitInfo.point = point;
hitInfo.normal = transform.forward;
onCastCollider.Invoke(hitInfo);
crossed = true;
break;
}
}
}
if (!crossed && !bulletLifeInfo.ricochet)
{
bulletLife = 0;
transform.position = hitInfo.point;
onDestroyProjectile.Invoke(hitInfo);
Destroy(gameObject);
}
maxDamage -= (maxDamage) - ((maxDamage * bulletLifeInfo.lostDamage) / 100);
minDamage -= (minDamage) - ((minDamage * bulletLifeInfo.lostDamage) / 100);
if (maxDamage < 0) maxDamage = 0;
if (minDamage < 0) minDamage = 0;
var x = Random.Range(bulletLifeInfo.minChangeTrajectory, bulletLifeInfo.maxChangeTrajectory) * (Random.Range(-1, 1) >= 0 ? 1 : -1);
var y = Random.Range(bulletLifeInfo.minChangeTrajectory, bulletLifeInfo.maxChangeTrajectory) * (Random.Range(-1, 1) >= 0 ? 1 : -1);
if (y > 60 || y < -60) x = Mathf.Clamp(x, -15, 15);
if (x != 0 || y != 0)
{
var dir = Quaternion.Euler(x, y, 0) * _rigidBody.velocity;
if (dir != Vector3.zero)
{
_rigidBody.velocity = dir * (bulletLifeInfo.ricochet ? -1 : 1);
transform.forward = dir * (bulletLifeInfo.ricochet ? -1 : 1);
}
}
if (debugTrajetory)
{
var lostedLifePercent = ((float)bulletLife / (float)debugLife) * 100f;
debugColor = lostedLifePercent > 76 ? Color.green : lostedLifePercent > 51 ? Color.yellow : lostedLifePercent > 26 ? new Color(1, .5f, 0) : Color.red;
debugColor.a = 0.5f;
}
}
if (bulletLife <= 0 || bulletLifeSettings == null)
{
transform.position = hitInfo.point;
onDestroyProjectile.Invoke(hitInfo);
Destroy(gameObject);
}
}
}
else
{
transform.position = hitInfo.point + transform.forward * 0.02f;
if (debugTrajetory) Debug.DrawLine(transform.position, previousPosition, debugColor, 10f);
}
}
else if (debugTrajetory)
{
Debug.DrawLine(transform.position, previousPosition, debugColor, 10f);
}
previousPosition = transform.position;
}}}
void DrawHitPoint(Vector3 point)
{
Debug.DrawRay(point, -transform.forward * 0.1f, Color.red, 10f);
Debug.DrawRay(point, transform.right * 0.1f, Color.red, 10f);
Debug.DrawRay(point, -transform.right * 0.1f, Color.red, 10f);
Debug.DrawRay(point, transform.up * 0.1f, Color.red, 10f);
Debug.DrawRay(point, -transform.up * 0.1f, Color.red, 10f);
}
public void RemoveParentOfOther(Transform other)
{
other.SetParent(vObjectContainer.root, true);
}
[System.Serializable]
public class ProjectileCastColliderEvent : UnityEngine.Events.UnityEvent<RaycastHit> { }
[System.Serializable]
public class ProjectilePassDamage : UnityEngine.Events.UnityEvent<vDamage> { }
}
}