using UnityEngine; using System.Collections; using System.Collections.Generic; using GameKitController.Audio; public class decalManager : MonoBehaviour { public bool disableFullDecallSystem; public bool decalsPlacedOnSurfacesEnabled = true; public bool particlesPlacedOnSurfaceEnabled = true; public bool soundsPlacedOnSurfaceEnabled = true; public bool fadeDecals; public float fadeSpeed; public static bool fadeDecalsValue; public static float fadeSpeedValue; public List impactListInfo = new List (); public static List impactListInfoValue = new List (); public GameObject projectileImpactSoundPrefab; public static GameObject projectileImpactSoundPrefabObject; public static bool disableFullDecallSystemValue; public static bool decalsPlacedOnSurfacesEnabledValue; public static bool particlesPlacedOnSurfaceEnabledValue; public static bool soundsPlacedOnSurfaceEnabledValue; public static Transform decalParent; public static bool decalParentCreated; public const string mainManagerName = "Decal Manager"; public static string getMainManagerName () { return mainManagerName; } private static decalManager _decalManagerInstance; public static decalManager Instance { get { return _decalManagerInstance; } } bool instanceInitialized; public void getComponentInstance () { if (instanceInitialized) { return; } if (_decalManagerInstance != null && _decalManagerInstance != this) { Destroy (this.gameObject); return; } _decalManagerInstance = this; instanceInitialized = true; } void Awake () { getComponentInstance (); checkDecalParent (); } private void InitializeAudioElements () { foreach (var impactInfo in impactListInfo) { impactInfo.InitializeAudioElements (); } foreach (var impactInfo in impactListInfoValue) { impactInfo.InitializeAudioElements (); } } static void checkDecalParent () { if (!decalParentCreated) { if (decalParent == null) { GameObject decalParentGameObject = new GameObject (); decalParent = decalParentGameObject.transform; decalParent.name = "Decal Parent"; } decalParentCreated = true; } } void Start () { InitializeAudioElements (); fadeDecalsValue = fadeDecals; fadeSpeedValue = fadeSpeed; impactListInfoValue = impactListInfo; projectileImpactSoundPrefabObject = projectileImpactSoundPrefab; disableFullDecallSystemValue = disableFullDecallSystem; decalsPlacedOnSurfacesEnabledValue = decalsPlacedOnSurfacesEnabled; particlesPlacedOnSurfaceEnabledValue = particlesPlacedOnSurfaceEnabled; soundsPlacedOnSurfaceEnabledValue = soundsPlacedOnSurfaceEnabled; } public static void setScorch (Quaternion rotation, GameObject scorch, RaycastHit hit, GameObject collision, bool projectilesPoolEnabled) { //set the position of the scorch according to the hit point if (!collision.GetComponent ()) { GameObject newScorch = null; if (projectilesPoolEnabled) { newScorch = GKC_PoolingSystem.Spawn (scorch, Vector3.zero, Quaternion.identity, 30); } else { newScorch = Instantiate (scorch); } newScorch.transform.rotation = rotation; newScorch.transform.position = hit.point + 0.03f * hit.normal; //get the surface normal to rotate the scorch to that angle Vector3 myForward = Vector3.Cross (newScorch.transform.right, hit.normal); Quaternion dstRot = Quaternion.LookRotation (myForward, hit.normal); newScorch.transform.rotation = dstRot; setScorchParent (collision.transform, newScorch, hit.point); if (fadeDecalsValue) { fadeObject currentFadeObject = newScorch.GetComponent (); if (currentFadeObject != null) { currentFadeObject.activeVanish (fadeSpeedValue); } } } } public static bool placeProjectileInSurface (Quaternion rotation, Transform projectile, RaycastHit hit, GameObject objectToDamage, bool attachToLimbs, bool ignoreSetProjectilePositionOnImpact) { if (!ignoreSetProjectilePositionOnImpact) { projectile.rotation = rotation; projectile.position = hit.point + 0.03f * hit.normal; //get the surface normal to rotate the scorch to that angle Vector3 myForward = Vector3.Cross (projectile.forward, hit.normal); Quaternion dstRot = Quaternion.LookRotation (myForward, hit.normal); projectile.rotation = dstRot; } Rigidbody currentRigidbody = objectToDamage.GetComponent (); if (currentRigidbody != null) { ragdollActivator currentRagdollActivator = objectToDamage.GetComponent (); if (currentRagdollActivator != null) { if (attachToLimbs) { List bones = currentRagdollActivator.getBodyPartsList (); float distance = Mathf.Infinity; int index = -1; for (int i = 0; i < bones.Count; i++) { float currentDistance = GKC_Utils.distance (bones [i].transform.position, projectile.position); if (currentDistance < distance) { distance = currentDistance; index = i; } } if (index != -1) { projectile.SetParent (bones [index].transform); } return true; } } characterDamageReceiver currentCharacterDamageReceiver = objectToDamage.GetComponent (); if (currentCharacterDamageReceiver != null) { projectile.SetParent (currentCharacterDamageReceiver.character.transform); return true; } projectile.SetParent (objectToDamage.transform); return true; } vehicleDamageReceiver currentVehicleDamageReceiver = objectToDamage.GetComponent (); if (currentVehicleDamageReceiver != null) { projectile.SetParent (currentVehicleDamageReceiver.getPlaceToShootWithHealthManagement ()); return true; } parentAssignedSystem currentParentAssignedSystem = objectToDamage.GetComponent (); if (currentParentAssignedSystem != null) { projectile.SetParent (currentParentAssignedSystem.getAssignedParentTransform ()); return true; } projectile.SetParent (decalParent); return true; } public static bool setImpactDecal (int impactIndex, Transform projectile, GameObject objectToDamage, float projectileRayDistance, LayerMask projectilelayer, bool useSorch, bool projectilesPoolEnabled) { if (disableFullDecallSystemValue) { return false; } bool hasImpactDecal = false; Vector3 projectilePosition = projectile.position; Vector3 projectileForward = projectile.forward; if (impactIndex == -2) { bool terrainFound = false; //get the current texture index of the terrain under the player. int surfaceIndex = GetMainTexture (projectilePosition, objectToDamage.GetComponent ()); for (int i = 0; i < impactListInfoValue.Count; i++) { if (!terrainFound && impactListInfoValue [i].checkTerrain && impactListInfoValue [i].decalEnabled) { if (impactListInfoValue [i].terrainTextureIndex == surfaceIndex) { impactIndex = i; terrainFound = true; } } } } if (impactIndex >= 0 && impactIndex < impactListInfoValue.Count) { impactInfo newImpactInfo = impactListInfoValue [impactIndex]; if (newImpactInfo.decalEnabled) { hasImpactDecal = true; if (soundsPlacedOnSurfaceEnabledValue) { if (newImpactInfo.impactSound != null) { projectileSystem currentProjectileSystem = projectile.GetComponent (); if (currentProjectileSystem != null) { currentProjectileSystem.createImpactSound (newImpactInfo.impactAudioElement); } } } bool scorchAvailable = false; if (newImpactInfo.useRandomScorch) { scorchAvailable = useSorch && newImpactInfo.randomScorchList.Count > 0; } else { scorchAvailable = useSorch && newImpactInfo.scorch != null; } bool particlesAvailable = false; if (newImpactInfo.useRandomImpactParticles) { particlesAvailable = newImpactInfo.randomImpactParticlesList.Count > 0; } else { particlesAvailable = newImpactInfo.impactParticles != null; } if (scorchAvailable || particlesAvailable) { if (projectileRayDistance == 0) { projectileRayDistance = 1; } RaycastHit hit = new RaycastHit (); bool surfaceDetected = false; bool raycastLaunched = false; if (scorchAvailable) { surfaceDetected = Physics.Raycast (projectilePosition - 0.4f * projectileForward, projectileForward, out hit, projectileRayDistance, projectilelayer); raycastLaunched = true; //the bullet fired is a simple bullet or a greanade, check the hit point with a raycast to set in it a scorch if (surfaceDetected) { Debug.DrawLine (projectilePosition - 0.4f * projectileForward, hit.point, Color.red, 2); if (decalsPlacedOnSurfacesEnabledValue) { if (newImpactInfo.useRandomScorch) { int randomIndex = Random.Range (0, newImpactInfo.randomImpactParticlesList.Count); setScorchFromList (projectile.rotation, newImpactInfo.randomScorchList [randomIndex], hit, objectToDamage, newImpactInfo.scorchScale, newImpactInfo.fadeScorch, newImpactInfo.timeToFade, projectilesPoolEnabled); } else { setScorchFromList (projectile.rotation, newImpactInfo.scorch, hit, objectToDamage, newImpactInfo.scorchScale, newImpactInfo.fadeScorch, newImpactInfo.timeToFade, projectilesPoolEnabled); } } } } if (particlesPlacedOnSurfaceEnabledValue) { if (particlesAvailable) { if (!raycastLaunched) { surfaceDetected = Physics.Raycast (projectilePosition - 0.4f * projectileForward, projectileForward, out hit, projectileRayDistance, projectilelayer); } if (surfaceDetected) { Vector3 particlesPosition = hit.point + 0.03f * hit.normal; Vector3 myForward = Vector3.Cross (projectileForward, hit.normal); Quaternion particlesRotation = Quaternion.LookRotation (hit.normal, myForward); GameObject impactParticles = null; if (projectilesPoolEnabled) { if (newImpactInfo.useRandomImpactParticles) { int randomIndex = Random.Range (0, newImpactInfo.randomImpactParticlesList.Count); impactParticles = GKC_PoolingSystem.Spawn (newImpactInfo.randomImpactParticlesList [randomIndex], particlesPosition, particlesRotation, 30); } else { impactParticles = GKC_PoolingSystem.Spawn (newImpactInfo.impactParticles, particlesPosition, particlesRotation, 30); } } else { if (newImpactInfo.useRandomImpactParticles) { int randomIndex = Random.Range (0, newImpactInfo.randomImpactParticlesList.Count); impactParticles = Instantiate (newImpactInfo.randomImpactParticlesList [randomIndex], particlesPosition, particlesRotation); } else { impactParticles = Instantiate (newImpactInfo.impactParticles, particlesPosition, particlesRotation); } } healthManagement currentHealthManagement = objectToDamage.GetComponent (); if (currentHealthManagement != null) { impactParticles.transform.SetParent (currentHealthManagement.getPlaceToShootWithHealthManagement ()); return hasImpactDecal; } Rigidbody currentRigidbody = objectToDamage.GetComponent (); if (currentRigidbody != null) { impactParticles.transform.SetParent (objectToDamage.transform); return hasImpactDecal; } vehicleDamageReceiver currentVehicleDamageReceiver = objectToDamage.GetComponent (); if (currentVehicleDamageReceiver != null) { impactParticles.transform.SetParent (currentVehicleDamageReceiver.getPlaceToShootWithHealthManagement ()); return hasImpactDecal; } impactParticles.transform.SetParent (decalParent); } } } } } } return hasImpactDecal; } public static void setImpactSoundParent (Transform newImpactSound) { newImpactSound.SetParent (decalParent); } public static void setScorchFromList (Quaternion rotation, GameObject scorch, RaycastHit hit, GameObject collision, float scorchScale, bool fadeScorch, float timeToFade, bool projectilesPoolEnabled) { //set the position of the scorch according to the hit point GameObject newScorch = null; if (projectilesPoolEnabled) { newScorch = GKC_PoolingSystem.Spawn (scorch, Vector3.zero, Quaternion.identity, 30); } else { newScorch = Instantiate (scorch); } newScorch.transform.position = hit.point + 0.03f * hit.normal; newScorch.transform.rotation = rotation; //get the surface normal to rotate the scorch to that angle Vector3 myForward = Vector3.Cross (newScorch.transform.right, hit.normal); Quaternion dstRot = Quaternion.LookRotation (myForward, hit.normal); newScorch.transform.rotation = dstRot; setScorchParent (collision.transform, newScorch, hit.point); newScorch.transform.localScale *= scorchScale; if (fadeScorch) { fadeObject currentFadeObject = newScorch.GetComponent (); if (currentFadeObject != null) { currentFadeObject.activeVanish (timeToFade); } } } public static int checkIfHasDecalImpact (GameObject objectToCheck) { healthManagement currentHealthManagement = objectToCheck.GetComponent (); if (currentHealthManagement != null) { if (currentHealthManagement.isUseImpactSurfaceActiveWithHealthManagement ()) { int decalIndex = currentHealthManagement.getDecalImpactIndexWithHealthManagement (); if (decalIndex > -1) { return decalIndex; } } } decalTypeInformation currentDecalTypeInformation = objectToCheck.GetComponent (); if (currentDecalTypeInformation != null) { return currentDecalTypeInformation.getDecalImpactIndex (); } if (objectToCheck.GetComponent ()) { return -2; } return -1; } public static void setScorchParent (Transform objectDetected, GameObject newScorch, Vector3 impactPosition) { healthManagement currentHealthManagement = objectDetected.GetComponent (); if (currentHealthManagement != null) { newScorch.transform.SetParent (currentHealthManagement.getPlaceToShootWithHealthManagement ()); return; } Rigidbody currentRigidbody = objectDetected.GetComponent (); if (currentRigidbody != null) { newScorch.transform.SetParent (objectDetected); return; } decalTypeInformation currentdecalTypeInformation = objectDetected.GetComponent (); if (currentdecalTypeInformation != null) { if (currentdecalTypeInformation.isParentScorchOnThisObjectEnabled ()) { newScorch.transform.SetParent (objectDetected); return; } } vehicleDamageReceiver currentVehicleDamageReceiver = objectDetected.GetComponent (); if (currentVehicleDamageReceiver != null) { newScorch.transform.SetParent (currentVehicleDamageReceiver.getPlaceToShootWithHealthManagement ()); return; } parentAssignedSystem currentParentAssignedSystem = objectDetected.GetComponent (); if (currentParentAssignedSystem != null) { newScorch.transform.SetParent (currentParentAssignedSystem.getAssignedParentTransform ()); return; } newScorch.transform.SetParent (decalParent); } public static int GetMainTexture (Vector3 playerPos, Terrain terrain) { //get the index of the current texture of the terrain where the player is walking TerrainData terrainData = terrain.terrainData; Vector3 terrainPos = terrain.transform.position; //calculate which splat map cell the playerPos falls within int mapX = (int)(((playerPos.x - terrainPos.x) / terrainData.size.x) * terrainData.alphamapWidth); int mapZ = (int)(((playerPos.z - terrainPos.z) / terrainData.size.z) * terrainData.alphamapHeight); //get the splat data for this cell as a 1x1xN 3d array (where N = number of textures) float [,,] splatmapData = terrainData.GetAlphamaps (mapX, mapZ, 1, 1); //change the 3D array data to a 1D array: float [] cellMix = new float [splatmapData.GetUpperBound (2) + 1]; for (int n = 0; n < cellMix.Length; n++) { cellMix [n] = splatmapData [0, 0, n]; } float maxMix = 0; int maxIndex = 0; //loop through each mix value and find the maximum for (int n = 0; n < cellMix.Length; n++) { if (cellMix [n] > maxMix) { maxIndex = n; maxMix = cellMix [n]; } } return maxIndex; } public bool surfaceUseNoise (int surfaceIndex) { if (surfaceIndex >= 0 && surfaceIndex < impactListInfo.Count) { return impactListInfo [surfaceIndex].useNoise; } return false; } public static Transform getDecalParent () { return decalParent; } [System.Serializable] public class impactInfo { public string name; public bool decalEnabled = true; public string surfaceName; public AudioClip impactSound; public AudioElement impactAudioElement; public GameObject scorch; [Range (1, 5)] public float scorchScale; public bool fadeScorch; public float timeToFade; public GameObject impactParticles; public bool useRandomImpactParticles; public List randomImpactParticlesList = new List (); public bool useRandomScorch; public List randomScorchList = new List (); public bool checkTerrain; public int terrainTextureIndex; public bool useNoise = true; public void InitializeAudioElements () { if (impactSound != null) { impactAudioElement.clip = impactSound; } } } }