This commit is contained in:
2025-09-17 18:56:28 +08:00
commit 54c72710a5
5244 changed files with 5717609 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 39b985d343618d84e8fe3c794db15869
folderAsset: yes
timeCreated: 1477871306
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,34 @@
using UnityEngine;
using System.Collections;
namespace DestroyIt
{
/// <summary>
/// This script provides extra features to the BulbFlash particle effect.
/// It removes the "Powered" tag from its parent, and removes the PoweredTag
/// script which manages the parent's powered state.
/// </summary>
public class BulbFlash : MonoBehaviour
{
void OnEnable()
{
// start a coroutine because we want to wait until the particle effect has had a
// chance to be a child under something.
StartCoroutine(RemovePower());
}
IEnumerator RemovePower()
{
// wait one frame
yield return 0;
Transform parent = this.transform.parent;
if (parent != null)
{
parent.gameObject.RemoveTag(Tag.Powered);
parent.gameObject.RemoveComponent<PoweredTag>();
}
StopCoroutine("RemovePower");
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 30d4ab45655a90647910eb3f46ce8013
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,43 @@
using UnityEngine;
using UnityEngine.SceneManagement;
#if UNITY_EDITOR
using UnityEditor.SceneManagement;
#endif
namespace DestroyIt
{
public class DemoNavigation : MonoBehaviour
{
private readonly LoadSceneParameters lsp = new LoadSceneParameters { loadSceneMode = LoadSceneMode.Single, localPhysicsMode = LocalPhysicsMode.None };
public void Start()
{
Cursor.lockState = CursorLockMode.None;
Cursor.visible = true;
}
public void LoadMainScenariosDemoScene()
{
Cursor.visible = false;
Cursor.lockState = CursorLockMode.Locked;
#if UNITY_EDITOR
EditorSceneManager.LoadSceneAsyncInPlayMode("Assets/DestroyIt/Demos (safe to delete)/Main Scenarios Scene.unity", lsp);
#else
SceneManager.LoadSceneAsync("Assets/DestroyIt/Demos (safe to delete)/Main Scenarios Scene.unity", lsp);
#endif
}
public void LoadSUVShowcaseDemoScene()
{
Cursor.visible = false;
Cursor.lockState = CursorLockMode.Locked;
#if UNITY_EDITOR
EditorSceneManager.LoadSceneAsyncInPlayMode("Assets/DestroyIt/Demos (safe to delete)/SUV Showcase Scene/SUV Showcase Scene.unity", lsp);
#else
SceneManager.LoadSceneAsync("Assets/DestroyIt/Demos (safe to delete)/SUV Showcase Scene/SUV Showcase Scene.unity", lsp);
#endif
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: d2026aafc48b78744acae1d6a3a0ed23
timeCreated: 1495512015
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,37 @@
using UnityEngine;
namespace DestroyIt
{
public class DisableAfter : MonoBehaviour
{
public float seconds; // seconds to wait before disabling this game object.
public bool removeScript; // remove this script after disabled?
private float timeLeft;
private bool isInitialized;
void Start()
{
timeLeft = seconds;
isInitialized = true;
}
void OnEnable()
{
timeLeft = seconds;
}
void Update()
{
if (!isInitialized) return;
timeLeft -= Time.deltaTime;
if (timeLeft <= 0)
{
this.gameObject.SetActive(false);
if (removeScript)
Destroy(this);
}
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4415e549706669c419f43ca86a7843e5
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,28 @@
using System.Collections.Generic;
using UnityEngine;
namespace DestroyIt
{
public class DynamicDestructible : MonoBehaviour
{
public GameObject objectToSpawn;
public GameObject destroyedPrefab;
public List<MaterialMapping> materialsToReplace;
public void Start()
{
if (objectToSpawn != null)
{
GameObject go = Instantiate(objectToSpawn, transform, false);
Destructible dest = go.AddComponent<Destructible>();
if (destroyedPrefab != null)
{
dest.destroyedPrefab = destroyedPrefab;
if (materialsToReplace != null && materialsToReplace.Count > 0)
dest.replaceMaterials = materialsToReplace;
}
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: c9d79d9038467ae45ab07e2d09ded8d0
timeCreated: 1491084134
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,174 @@
using System.Collections.Generic;
using UnityEngine;
namespace DestroyIt
{
/// <summary>
/// Attach this script to any object that has a transparent shader on its mesh renderer.
///
/// Also, you can attach this script to a destroyed prefab that has child "debris" objects. Example: a broken wall object that
/// is composed of multiple child rubble pieces. This script will fade-out and clean up all the child rubble pieces for you.
/// </summary>
public class FadeOut : MonoBehaviour
{
[Range(0f, 30f)]
public float afterSeconds = 6f; // seconds to wait before starting the fade.
[Range(0f, 10f)]
public float fadeLength = 2f; // how long (in seconds) to fade-out objects before destroying them.
private List<ObjectToFade> objectsToFade;
private float timeLeft;
private bool isInitialized;
private bool isBeingDestroyed;
void Start()
{
timeLeft = afterSeconds;
isInitialized = true;
MeshRenderer[] meshRenderers = transform.GetComponentsInChildren<MeshRenderer>();
if (meshRenderers.Length == 0)
{
Debug.LogWarning("FadeOut: No MeshRenderers found under \"" + transform.name + "\". Cannot fade out.");
Destroy(this);
}
else
{
// Collect all the objects to fade into a list.
objectsToFade = new List<ObjectToFade>();
for (int i = 0; i < meshRenderers.Length; i++)
{
objectsToFade.Add(new ObjectToFade()
{
MeshRenderer = meshRenderers[i],
Colliders = meshRenderers[i].GetComponentsInChildren<Collider>(),
Rigidbody = meshRenderers[i].GetComponent<Rigidbody>(),
CanBeFaded = true
});
}
}
}
void OnEnable()
{
timeLeft = afterSeconds;
}
void Update()
{
if (!isInitialized || isBeingDestroyed) return;
timeLeft -= Time.deltaTime;
if (timeLeft <= 0)
{
if (timeLeft <= -1*fadeLength)
{
isBeingDestroyed = true;
Destroy(transform.gameObject);
}
else
Fade();
}
}
private void StripColliders(ObjectToFade obj)
{
// Try to strip Colliders
if (obj.Colliders.Length == 0)
obj.IsStripped = true;
else
{
for (int i=0; i<obj.Colliders.Length; i++)
Destroy(obj.Colliders[i]);
obj.IsStripped = true;
}
}
/// <summary>Fade this object and its children one step towards invisible.</summary>
private void Fade()
{
foreach (ObjectToFade obj in objectsToFade)
{
if (obj.MeshRenderer == null) continue;
// Try to strip Rigidbody and Colliders
if (!obj.IsStripped)
{
if (obj.Rigidbody == null)
{
// No Rigidbody, so try to strip Colliders
StripColliders(obj);
}
else if (obj.Rigidbody.IsSleeping())
{
// Rigidbody is sleeping, so destroy it and then strip Colliders
Destroy(obj.Rigidbody);
StripColliders(obj);
}
// Else Rigidbody isn't sleeping, so leave it alone for now.
}
if (!obj.IsTransparencyChecked)
{
Material[] mats = obj.MeshRenderer.materials;
for (int i = 0; i < mats.Length; i++)
{
// If the material on the object doesn't have a transparency property...
if (!mats[i].HasProperty("_Transparency"))
{
// Try to find the appropriate "Transparent" version of its shader.
mats[i].shader = mats[i].shader.GetTransparentVersion();
mats[i].SetFloat("_Transparency", 0f);
}
}
obj.MeshRenderer.materials = mats;
obj.IsTransparencyChecked = true;
}
for (int i = 0; i < obj.MeshRenderer.materials.Length; i++)
{
float currTransparency = obj.MeshRenderer.materials[i].GetFloat("_Transparency");
if (currTransparency >= 1f)
continue;
currTransparency += Mathf.Clamp01(Time.deltaTime / fadeLength);
obj.MeshRenderer.materials[i].SetFloat("_Transparency", currTransparency);
}
}
}
}
public class ObjectToFade
{
public MeshRenderer MeshRenderer { get; set; }
/// <summary>Are the rigidbody and colliders stripped from this object?</summary>
public bool IsStripped { get; set; }
public bool CanBeFaded { get; set; }
public Rigidbody Rigidbody { get; set; }
public Collider[] Colliders { get; set; }
public bool IsTransparencyChecked { get; set; }
}
public static class ShaderExtensions
{
public static Shader GetTransparentVersion(this Shader currentShader)
{
Shader transShader;
// Try to find the appropriate "Transparent" version of the shader.
if (currentShader.name.Contains("DestroyIt/"))
transShader = Shader.Find(currentShader.name.Replace("DestroyIt/", "DestroyIt/Transparent"));
else
transShader = Shader.Find("DestroyIt/Transparent" + currentShader.name.Replace(" ", ""));
if (transShader != null)
return transShader;
// Transparent version of shader not found. Try to fallback on DestroyIt/TransparentDiffuse.
transShader = Shader.Find("DestroyIt/TransparentDiffuse");
if (transShader != null)
return transShader;
// if no transparency shader could be found, log an error and destroy this script
Debug.LogError("DestroyIt: No progressive damage transparency shader could be found. Cannot fade out material with shader \"" + currentShader.name + "\" object.");
return currentShader;
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7eb932bf1c55c054a9a0c925e5040a2f
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,58 @@
using UnityEngine;
namespace DestroyIt
{
public class Follow : MonoBehaviour
{
public Transform objectToFollow;
public FacingDirection facingDirection = FacingDirection.FollowedObject;
[HideInInspector]
public bool isPositionFixed;
[HideInInspector]
public Vector3 fixedFromPosition = Vector3.zero;
[HideInInspector]
public float fixedDistance;
void Start()
{
if (objectToFollow == null)
{
Debug.Log("[DestroyIt-Follow]: No transform was provided. Nothing to follow. Removing script...");
Destroy(this);
}
}
void LateUpdate()
{
if (objectToFollow != null)
{
if (isPositionFixed)
{
// get point along line from player to shockwave start
Vector3 followPoint = objectToFollow.position.LerpByDistance(fixedFromPosition, fixedDistance);
transform.position = followPoint;
}
else
transform.position = objectToFollow.position;
switch (facingDirection)
{
case FacingDirection.FollowedObject:
transform.LookAt(objectToFollow);
break;
case FacingDirection.FixedPosition:
transform.LookAt(fixedFromPosition);
break;
}
}
}
void OnDrawGizmos()
{
if (isPositionFixed && objectToFollow != null)
Gizmos.DrawLine(fixedFromPosition, objectToFollow.position);
Gizmos.DrawWireSphere(transform.position, .5f);
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d4f42c95654649941acc8d8566df4024
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,116 @@
using UnityEngine;
using UnityEngine.UI;
namespace DestroyIt
{
/// <summary>This script provides performance and basic control info for the demo scene.</summary>
public class HeadsUpDisplay : MonoBehaviour
{
public RectTransform hud;
[Tooltip("The number of times per second the UI updates.")]
public float updateRate = 15f;
public Text destroyedPrefabsText;
public Text destroyedParticlesText;
public Text debrisCountText;
public Image reticleImage;
public Image selectedWeapon;
public Sprite unknownWeapon;
public Sprite assaultRifle;
public Sprite rocketLauncher;
public Sprite fireAxe;
public Sprite cannon;
public Sprite nuke;
public Sprite wrench;
private float nextUpdate;
private void Start()
{
if (DestructionManager.Instance != null)
{
DestructionManager.Instance.DestroyedPrefabCounterChangedEvent += OnDestroyedPrefabCounterChanged;
DestructionManager.Instance.ActiveDebrisCounterChangedEvent += OnActiveDebrisCounterChanged;
}
if (ParticleManager.Instance != null)
ParticleManager.Instance.ActiveParticlesCounterChangedEvent += OnActiveParticlesCounterChanged;
OnDestroyedPrefabCounterChanged();
OnActiveDebrisCounterChanged();
OnActiveParticlesCounterChanged();
}
private void OnDisable()
{
// Unregister the event listeners when disabled/destroyed. Very important to prevent memory leaks due to orphaned event listeners!
if (DestructionManager.Instance != null)
{
DestructionManager.Instance.DestroyedPrefabCounterChangedEvent -= OnDestroyedPrefabCounterChanged;
DestructionManager.Instance.ActiveDebrisCounterChangedEvent -= OnActiveDebrisCounterChanged;
}
if (ParticleManager.Instance != null)
ParticleManager.Instance.ActiveParticlesCounterChangedEvent -= OnActiveParticlesCounterChanged;
}
private void OnDestroyedPrefabCounterChanged()
{
// Destroyed Prefab Updates
destroyedPrefabsText.text = "Destroyed Prefabs (last " + DestructionManager.Instance.withinSeconds + "s): " + DestructionManager.Instance.DestroyedPrefabCounter.Count;
}
private void OnActiveParticlesCounterChanged()
{
// Destroyed Particles Updates
destroyedParticlesText.text = "Destroyed Particles (last " + ParticleManager.Instance.withinSeconds + "s): " + ParticleManager.Instance.ActiveParticles.Length;
}
private void OnActiveDebrisCounterChanged()
{
// Debris Count Updates
debrisCountText.text = "Debris Count: " + DestructionManager.Instance.ActiveDebrisCount;
}
private void Update()
{
if (!(Time.time > nextUpdate)) return;
nextUpdate = Time.time + (1.0f / updateRate);
// HUD Visibility Updates
int showHud = PlayerPrefs.GetInt("ShowHud", -1);
hud.gameObject.SetActive(showHud == -1);
// Reticle HUD Updates
int showReticle = PlayerPrefs.GetInt("ShowReticle", -1);
reticleImage.gameObject.SetActive(showReticle == -1);
if (InputManager.Instance != null)
{
// Selected Weapon Silhouette Update
switch (InputManager.Instance.SelectedWeapon)
{
case WeaponType.Gun:
selectedWeapon.sprite = assaultRifle;
break;
case WeaponType.Rocket:
selectedWeapon.sprite = rocketLauncher;
break;
case WeaponType.Melee:
selectedWeapon.sprite = fireAxe;
break;
case WeaponType.Cannonball:
selectedWeapon.sprite = cannon;
break;
case WeaponType.Nuke:
selectedWeapon.sprite = nuke;
break;
case WeaponType.RepairWrench:
selectedWeapon.sprite = wrench;
break;
default: // This should never happen.
selectedWeapon.sprite = unknownWeapon;
break;
}
}
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 19f260da355be4e49b2b66749b83875d
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,104 @@
using System.Collections.Generic;
using UnityEngine;
namespace DestroyIt
{
public class MeleeArea : MonoBehaviour
{
public int damageAmount = 30;
public int repairAmount = 20;
public float meleeRadius = 1.3f;
public float additionalForceAmount = 150f;
public float additionalForceRadius = 2f;
public ParticleSystem repairEffect;
public void OnMeleeDamage()
{
Collider[] objectsInRange = Physics.OverlapSphere(transform.position, meleeRadius);
List<Destructible> damagedObjects = new List<Destructible>(); // Keep track of what objects have been damaged so we don't do damage multiple times per collider.
bool hasPlayedHitEffect = false;
foreach (Collider col in objectsInRange)
{
// Ignore terrain colliders
if (col is TerrainCollider) continue;
// Ignore trigger colliders
if (col.isTrigger) continue;
// Ignore the player's character controller (ie, don't allow hitting yourself)
if (col is CharacterController && col.tag == "Player") continue;
if (!hasPlayedHitEffect) // Only play the hit effect once per melee attack.
{
// Play hit effects
HitEffects hitEffects = col.gameObject.GetComponentInParent<HitEffects>();
if (hitEffects != null && hitEffects.effects.Count > 0)
hitEffects.PlayEffect(HitBy.Axe, transform.position, transform.forward * -1);
hasPlayedHitEffect = true;
}
// Apply impact force to rigidbody hit
Rigidbody rbody = col.attachedRigidbody;
if (rbody != null)
rbody.AddForceAtPosition(transform.forward * 3f, transform.position, ForceMode.Impulse);
// Apply damage if object hit was Destructible
// Only do this for active and enabled Destructible scripts found in parent objects
// Special Note: Destructible scripts are turned off on terrain trees by default (to save resources), so we will make an exception for them and process the hit anyway
Destructible[] destObjs = col.gameObject.GetComponentsInParent<Destructible>(false);
foreach (Destructible destObj in destObjs)
{
if (damagedObjects.Contains(destObj)) continue;
if (!destObj.isActiveAndEnabled && !destObj.isTerrainTree) continue;
damagedObjects.Add(destObj);
ImpactDamage meleeImpact = new ImpactDamage() { DamageAmount = damageAmount, AdditionalForce = additionalForceAmount,
AdditionalForcePosition = transform.position, AdditionalForceRadius = additionalForceRadius };
destObj.ApplyDamage(meleeImpact);
}
}
}
private void OnMeleeRepair()
{
Collider[] objectsInRange = Physics.OverlapSphere(transform.position, meleeRadius);
List<Destructible> repairedObjects = new List<Destructible>(); // Keep track of what objects have been repaired so we don't repair multiple times per collider.
bool hasPlayedRepairEffect = false;
// Repair items within range
foreach (Collider col in objectsInRange)
{
// Ignore terrain colliders
if (col is TerrainCollider) continue;
// Ignore trigger colliders
if (col.isTrigger) continue;
// Ignore the player's character controller (ie, don't allow hitting yourself)
if (col is CharacterController && col.tag == "Player") continue;
// Repair object if it is a Destructible
Destructible destObj = col.gameObject.GetComponentInParent<Destructible>();
if (destObj != null && !repairedObjects.Contains(destObj) && destObj.CurrentHitPoints < destObj.TotalHitPoints && destObj.canBeRepaired)
{
repairedObjects.Add(destObj);
destObj.RepairDamage(repairAmount);
// Play repair particle effect
if (repairEffect != null && !hasPlayedRepairEffect)
{
repairEffect.GetComponent<ParticleSystem>().Clear(true);
repairEffect.Play(true);
hasPlayedRepairEffect = true;
}
}
}
}
private void OnDrawGizmos()
{
Gizmos.DrawWireSphere(transform.position, meleeRadius);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: d65e0b9e2f047aa408e2fe38b55123e2
timeCreated: 1482099782
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,31 @@
using UnityEngine;
namespace DestroyIt
{
public class OpenCloseChest : MonoBehaviour
{
void Start()
{
InvokeRepeating("SwapOpenClose", 3.5f, 3.5f);
}
public void SwapOpenClose()
{
HingeJoint joint = this.GetComponent<HingeJoint>();
if (joint != null)
{
joint.motor = new JointMotor()
{
targetVelocity = -1 * joint.motor.targetVelocity,
force = 10
};
joint.useMotor = true;
GetComponent<Rigidbody>().WakeUp();
}
else
Destroy(this);
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1a708abe01b83cd4b97a5da08881fbcd
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,18 @@
using UnityEngine;
namespace DestroyIt
{
public class PowerSource : MonoBehaviour
{
public bool hasPower = true;
public bool cutPowerOnRapidTilt = true;
public float tiltThreshold = 1.5f;
void Update()
{
// Cut power when object is tilted suddenly (angular velocity goes up)
if (cutPowerOnRapidTilt && hasPower && GetComponent<Rigidbody>() != null && GetComponent<Rigidbody>().angularVelocity.magnitude > tiltThreshold)
Destroy(this);
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f6d069f57f5e5e644a174e37962e8e7c
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,64 @@
using UnityEngine;
using System.Linq;
using System.Collections.Generic;
namespace DestroyIt
{
/// <summary>
/// This script checks if an object that contains lights is getting power from its
/// parent, determined by whether the parent is tagged as "Powered".
/// </summary>
public class PoweredLight : MonoBehaviour
{
public PowerSource powerSource; // The source of power for this light.
public MeshRenderer emissiveMesh; // Any additional mesh for which to turn off the emissive property of its shader when this light is unpowered. (For example, the lampshade of a light bulb.)
public Material emissiveOffMaterial;
private List<Light> lights;
private Transform parent;
private bool isPowered;
void Start()
{
isPowered = false;
lights = gameObject.GetComponentsInChildren<Light>().ToList();
if (lights.Count == 0)
{
Debug.Log("PoweredLight: No Light components found on [" + gameObject.name + "]. Removing script.");
Destroy(this);
}
parent = this.gameObject.transform.parent;
if (parent == null)
{
Debug.Log("PoweredLight: No parent found for [" + gameObject.name + "]. Removing script.");
Destroy(this);
}
}
void Update()
{
// remove any light from the list that is null or missing.
lights.RemoveAll(x => x == null);
// find out if we have power from the parent.
if (parent.gameObject.HasTag(Tag.Powered))
isPowered = true;
else
isPowered = false;
if (isPowered)
{
for (int i = 0; i < lights.Count; i++)
lights[i].enabled = true;
}
else
{
for (int i = 0; i < lights.Count; i++)
lights[i].enabled = false;
// Turn off emissive material
emissiveMesh.material = emissiveOffMaterial;
}
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: cd8d816adf0b1274d8219452269ed1e1
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,17 @@
using UnityEngine;
namespace DestroyIt
{
public class PoweredTag : MonoBehaviour
{
public PowerSource powerSource;
void Update()
{
if (powerSource == null || !powerSource.hasPower)
gameObject.RemoveTag(Tag.Powered);
else
gameObject.AddTag(Tag.Powered);
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a33bf757133652244a37eec56402e1a1
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,56 @@
using UnityEngine;
namespace DestroyIt
{
/// <summary>
/// Place this script on your destroyed prefab, at the highest parent level.
/// When your destroyed prefab spawns in, it will wait for a while and then reset itself to whatever game object you have assigned to resetToPrefab.
/// </summary>
public class ResetDestructible : MonoBehaviour
{
[Tooltip("The game object prefab you want to reset this destructible object to after it has been destroyed. (Usually a Pristine version of this destroyed object.)")]
public GameObject resetToPrefab;
[Tooltip("The minimum amount of time to wait (in seconds) before resetting the destructible object. (3600 seconds = 1 hour)")]
public float minWaitSeconds = 30.0f;
[Tooltip("The maximum amount of time to wait (in seconds) before resetting the destructible object. (3600 seconds = 1 hour)")]
public float maxWaitSeconds = 45.0f;
private float _timeLeft;
private bool _isInitialized;
void Start()
{
if (resetToPrefab == null)
{
Debug.LogError("ResetDestructible Script: You need to assign a prefab to the [resetToPrefab] field.");
Destroy(this);
return;
}
// Randomly determine when to reset the destroyed object, based on the min/max wait seconds.
_timeLeft = maxWaitSeconds <= minWaitSeconds ? 0f : Random.Range(minWaitSeconds, maxWaitSeconds);
Debug.Log($"[{gameObject.name}] will be reset in approximately {Mathf.RoundToInt(_timeLeft)} seconds.");
_isInitialized = true;
}
void Update()
{
if (!_isInitialized) return;
_timeLeft -= Time.deltaTime;
if (_timeLeft <= 0)
{
// Spawn the resetToPrefab object after the required wait time.
GameObject go = Instantiate(resetToPrefab, transform.position, transform.rotation, transform.parent);
go.transform.localScale = transform.localScale; // in case the destroyed object was scaled in the scene
Debug.Log($"[{gameObject.name}] has been reset to [{resetToPrefab.name}].");
Destroy(gameObject); // remove this gameObject to cleanup the scene
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f20d9c5d4088ba74f9a6c389f11f5384
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,22 @@
using UnityEngine;
namespace DestroyIt
{
public class RocketLoading : MonoBehaviour
{
public bool isLoaded = true; // start off with the rocket loaded into the launcher
private void OnEnable()
{
if (isLoaded) // if the rocket is already loaded, position the game object so it is in the launcher.
transform.localPosition = new Vector3(transform.localPosition.x, transform.localPosition.y, 0.74f);
else // if rocket is not currently loaded, play the rocket loading animation
{
Animation anim = gameObject.GetComponent<Animation>();
if (anim != null)
anim.Play("Rocket Loading");
isLoaded = true;
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: afd04edbf4cf42949a3c5e4d46ff5e98
timeCreated: 1477871320
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 6534977353ffd124d969b676964f7063
folderAsset: yes
timeCreated: 1480900827
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,123 @@
using UnityEditor;
using UnityEngine;
namespace DestroyIt
{
[CustomEditor (typeof(ColorCorrectionCurves))]
class ColorCorrectionCurvesEditor : Editor {
SerializedObject serObj;
SerializedProperty mode;
SerializedProperty redChannel;
SerializedProperty greenChannel;
SerializedProperty blueChannel;
SerializedProperty useDepthCorrection;
SerializedProperty depthRedChannel;
SerializedProperty depthGreenChannel;
SerializedProperty depthBlueChannel;
SerializedProperty zCurveChannel;
SerializedProperty saturation;
SerializedProperty selectiveCc;
SerializedProperty selectiveFromColor;
SerializedProperty selectiveToColor;
private bool applyCurveChanges = false;
void OnEnable () {
serObj = new SerializedObject (target);
mode = serObj.FindProperty ("mode");
saturation = serObj.FindProperty ("saturation");
redChannel = serObj.FindProperty ("redChannel");
greenChannel = serObj.FindProperty ("greenChannel");
blueChannel = serObj.FindProperty ("blueChannel");
useDepthCorrection = serObj.FindProperty ("useDepthCorrection");
zCurveChannel = serObj.FindProperty ("zCurve");
depthRedChannel = serObj.FindProperty ("depthRedChannel");
depthGreenChannel = serObj.FindProperty ("depthGreenChannel");
depthBlueChannel = serObj.FindProperty ("depthBlueChannel");
serObj.ApplyModifiedProperties ();
selectiveCc = serObj.FindProperty ("selectiveCc");
selectiveFromColor = serObj.FindProperty ("selectiveFromColor");
selectiveToColor = serObj.FindProperty ("selectiveToColor");
}
void CurveGui ( string name, SerializedProperty animationCurve, Color color) {
// @NOTE: EditorGUILayout.CurveField is buggy and flickers, using PropertyField for now
//animationCurve.animationCurveValue = EditorGUILayout.CurveField (GUIContent (name), animationCurve.animationCurveValue, color, Rect (0.0f,0.0f,1.0f,1.0f));
EditorGUILayout.PropertyField (animationCurve, new GUIContent (name));
if (GUI.changed)
applyCurveChanges = true;
}
void BeginCurves () {
applyCurveChanges = false;
}
void ApplyCurves () {
if (applyCurveChanges) {
serObj.ApplyModifiedProperties ();
(serObj.targetObject as ColorCorrectionCurves).gameObject.SendMessage ("UpdateTextures");
}
}
public override void OnInspectorGUI () {
serObj.Update ();
GUILayout.Label ("Use curves to tweak RGB channel colors", EditorStyles.miniBoldLabel);
saturation.floatValue = EditorGUILayout.Slider( "Saturation", saturation.floatValue, 0.0f, 5.0f);
EditorGUILayout.PropertyField (mode, new GUIContent ("Mode"));
EditorGUILayout.Separator ();
BeginCurves ();
CurveGui (" Red", redChannel, Color.red);
CurveGui (" Green", greenChannel, Color.green);
CurveGui (" Blue", blueChannel, Color.blue);
EditorGUILayout.Separator ();
if (mode.intValue > 0)
useDepthCorrection.boolValue = true;
else
useDepthCorrection.boolValue = false;
if (useDepthCorrection.boolValue) {
CurveGui (" Red (depth)", depthRedChannel, Color.red);
CurveGui (" Green (depth)", depthGreenChannel, Color.green);
CurveGui (" Blue (depth)", depthBlueChannel, Color.blue);
EditorGUILayout.Separator ();
CurveGui (" Blend Curve", zCurveChannel, Color.grey);
}
EditorGUILayout.Separator ();
EditorGUILayout.PropertyField (selectiveCc, new GUIContent ("Selective"));
if (selectiveCc.boolValue) {
EditorGUILayout.PropertyField (selectiveFromColor, new GUIContent (" Key"));
EditorGUILayout.PropertyField (selectiveToColor, new GUIContent (" Target"));
}
ApplyCurves ();
if (!applyCurveChanges)
serObj.ApplyModifiedProperties ();
}
}
}

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 4db7e5f0702b8664a9dcc0d4dfba5691
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:

View File

@@ -0,0 +1,23 @@
using UnityEditor;
namespace DestroyIt
{
[CustomEditor(typeof(Follow))]
public class FollowEditor : Editor
{
public override void OnInspectorGUI()
{
DrawDefaultInspector();
Follow script = target as Follow;
// FixedFromPosition and FixedDistance should only be available when FixedPosition is true.
script.isPositionFixed = EditorGUILayout.Toggle("Is Fixed From Position", script.isPositionFixed);
if (script.isPositionFixed)
{
script.fixedFromPosition = EditorGUILayout.Vector3Field("Position", script.fixedFromPosition);
script.fixedDistance = EditorGUILayout.FloatField("Distance", script.fixedDistance);
}
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 997b49b1f5939cf4dbe4fcee14094752
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,46 @@
using UnityEditor;
using UnityEngine;
namespace DestroyIt
{
public class SetupDestroyItDemo
{
[MenuItem("Window/DestroyIt/Setup - First Person Controller")]
public static void SetupFirstPersonControllerMenuOption()
{
DestructionManager destructionManager = Object.FindObjectOfType<DestructionManager>();
if (destructionManager == null)
SetupDestroyIt.SetupMinimalMenuOption();
destructionManager = Object.FindObjectOfType<DestructionManager>();
string fpControllerPath = "Assets/DestroyIt/Demos (safe to delete)/Prefabs/Character Controllers/First Person Controller.prefab";
GameObject fpController = AssetDatabase.LoadAssetAtPath<GameObject>(fpControllerPath);
if (fpController == null)
{
Debug.LogWarning("Could not find asset " + fpControllerPath);
return;
}
// if there is already a Main camera in the scene, disable it.
Camera cam = Camera.main;
if (cam != null)
cam.gameObject.SetActive(false);
GameObject fpControllerObj = PrefabUtility.InstantiatePrefab(fpController) as GameObject;
InputManager inputManager = fpControllerObj.GetComponent<InputManager>();
ObjectPool pool = destructionManager.gameObject.GetComponent<ObjectPool>();
pool.prefabsToPool.Add(new PoolEntry() {Count = 20, Prefab = inputManager.bulletPrefab});
pool.prefabsToPool.Add(new PoolEntry() {Count = 5, Prefab = inputManager.rocketPrefab});
pool.prefabsToPool.Add(new PoolEntry() {Count = 20, Prefab = inputManager.cannonballPrefab});
pool.prefabsToPool.Add(new PoolEntry() {Count = 1, Prefab = inputManager.nukePrefab});
pool.prefabsToPool.Add(new PoolEntry() {Count = 1, Prefab = inputManager.dustWallPrefab});
string effectsPrefabPath = "Assets/DestroyIt/Demos (safe to delete)/Prefabs/Effects/";
GameObject rocketSmokeTrailPrefab = AssetDatabase.LoadAssetAtPath<GameObject>(effectsPrefabPath + "Rocket Smoke Trail.prefab");
pool.prefabsToPool.Add(new PoolEntry() {Count = 10, Prefab = rocketSmokeTrailPrefab});
GameObject burstFlamePrefabPath = AssetDatabase.LoadAssetAtPath<GameObject>(effectsPrefabPath + "BurstFlame.prefab");
pool.prefabsToPool.Add(new PoolEntry() {Count = 10, Prefab = burstFlamePrefabPath});
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6b5d95ba491b4bc298e4e51460a6ad97
timeCreated: 1546043554

View File

@@ -0,0 +1,80 @@
using UnityEditor;
using UnityEngine;
namespace DestroyIt
{
[CustomEditor (typeof(Tonemapping))]
class TonemappingEditor : Editor
{
SerializedObject serObj;
SerializedProperty type;
// CURVE specific parameter
SerializedProperty remapCurve;
SerializedProperty exposureAdjustment;
// REINHARD specific parameter
SerializedProperty middleGrey;
SerializedProperty white;
SerializedProperty adaptionSpeed;
SerializedProperty adaptiveTextureSize;
void OnEnable () {
serObj = new SerializedObject (target);
type = serObj.FindProperty ("type");
remapCurve = serObj.FindProperty ("remapCurve");
exposureAdjustment = serObj.FindProperty ("exposureAdjustment");
middleGrey = serObj.FindProperty ("middleGrey");
white = serObj.FindProperty ("white");
adaptionSpeed = serObj.FindProperty ("adaptionSpeed");
adaptiveTextureSize = serObj.FindProperty("adaptiveTextureSize");
}
public override void OnInspectorGUI () {
serObj.Update ();
GUILayout.Label("Mapping HDR to LDR ranges since 1982", EditorStyles.miniLabel);
Camera cam = (target as Tonemapping).GetComponent<Camera>();
if (cam != null) {
if (!cam.allowHDR) {
EditorGUILayout.HelpBox("The camera is not HDR enabled. This will likely break the Tonemapper.", MessageType.Warning);
}
else if (!(target as Tonemapping).validRenderTextureFormat) {
EditorGUILayout.HelpBox("The input to Tonemapper is not in HDR. Make sure that all effects prior to this are executed in HDR.", MessageType.Warning);
}
}
EditorGUILayout.PropertyField (type, new GUIContent ("Technique"));
if (type.enumValueIndex == (int) Tonemapping.TonemapperType.UserCurve) {
EditorGUILayout.PropertyField (remapCurve, new GUIContent ("Remap curve", "Specify the mapping of luminances yourself"));
} else if (type.enumValueIndex == (int) Tonemapping.TonemapperType.SimpleReinhard) {
EditorGUILayout.PropertyField (exposureAdjustment, new GUIContent ("Exposure", "Exposure adjustment"));
} else if (type.enumValueIndex == (int) Tonemapping.TonemapperType.Hable) {
EditorGUILayout.PropertyField (exposureAdjustment, new GUIContent ("Exposure", "Exposure adjustment"));
} else if (type.enumValueIndex == (int) Tonemapping.TonemapperType.Photographic) {
EditorGUILayout.PropertyField (exposureAdjustment, new GUIContent ("Exposure", "Exposure adjustment"));
} else if (type.enumValueIndex == (int) Tonemapping.TonemapperType.OptimizedHejiDawson) {
EditorGUILayout.PropertyField (exposureAdjustment, new GUIContent ("Exposure", "Exposure adjustment"));
} else if (type.enumValueIndex == (int) Tonemapping.TonemapperType.AdaptiveReinhard) {
EditorGUILayout.PropertyField (middleGrey, new GUIContent ("Middle grey", "Middle grey defines the average luminance thus brightening or darkening the entire image."));
EditorGUILayout.PropertyField (white, new GUIContent ("White", "Smallest luminance value that will be mapped to white"));
EditorGUILayout.PropertyField (adaptionSpeed, new GUIContent ("Adaption Speed", "Speed modifier for the automatic adaption"));
EditorGUILayout.PropertyField (adaptiveTextureSize, new GUIContent ("Texture size", "Defines the amount of downsamples needed."));
} else if (type.enumValueIndex == (int) Tonemapping.TonemapperType.AdaptiveReinhardAutoWhite) {
EditorGUILayout.PropertyField (middleGrey, new GUIContent ("Middle grey", "Middle grey defines the average luminance thus brightening or darkening the entire image."));
EditorGUILayout.PropertyField (adaptionSpeed, new GUIContent ("Adaption Speed", "Speed modifier for the automatic adaption"));
EditorGUILayout.PropertyField (adaptiveTextureSize, new GUIContent ("Texture size", "Defines the amount of downsamples needed."));
}
GUILayout.Label("All following effects will use LDR color buffers", EditorStyles.miniBoldLabel);
serObj.ApplyModifiedProperties();
}
}
}

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 2ddd43d5ae63f0242b491e0cc5236a0c
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:

View File

@@ -0,0 +1,17 @@
fileFormatVersion: 2
guid: c782f904b3bb055428862531571ab698
labels:
- Destruction
- Destroy
- Physics
- DestroyIt
- Damage
- Fracturing
- Demolition
folderAsset: yes
timeCreated: 1427397479
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,180 @@
using UnityEngine;
namespace DestroyIt
{
[ExecuteInEditMode]
[AddComponentMenu ("Image Effects/Color Adjustments/Color Correction (Curves, Saturation)")]
public class ColorCorrectionCurves : PostEffectsBase
{
public enum ColorCorrectionMode
{
Simple = 0,
Advanced = 1
}
public AnimationCurve redChannel = new AnimationCurve(new Keyframe(0f,0f), new Keyframe(1f,1f));
public AnimationCurve greenChannel = new AnimationCurve(new Keyframe(0f,0f), new Keyframe(1f,1f));
public AnimationCurve blueChannel = new AnimationCurve(new Keyframe(0f,0f), new Keyframe(1f,1f));
public bool useDepthCorrection = false;
public AnimationCurve zCurve = new AnimationCurve(new Keyframe(0f,0f), new Keyframe(1f,1f));
public AnimationCurve depthRedChannel = new AnimationCurve(new Keyframe(0f,0f), new Keyframe(1f,1f));
public AnimationCurve depthGreenChannel = new AnimationCurve(new Keyframe(0f,0f), new Keyframe(1f,1f));
public AnimationCurve depthBlueChannel = new AnimationCurve(new Keyframe(0f,0f), new Keyframe(1f,1f));
private Material ccMaterial;
private Material ccDepthMaterial;
private Material selectiveCcMaterial;
private Texture2D rgbChannelTex;
private Texture2D rgbDepthChannelTex;
private Texture2D zCurveTex;
public float saturation = 1.0f;
public bool selectiveCc = false;
public Color selectiveFromColor = Color.white;
public Color selectiveToColor = Color.white;
public ColorCorrectionMode mode;
public bool updateTextures = true;
public Shader colorCorrectionCurvesShader = null;
public Shader simpleColorCorrectionCurvesShader = null;
public Shader colorCorrectionSelectiveShader = null;
private bool updateTexturesOnStartup = true;
new void Start ()
{
base.Start ();
updateTexturesOnStartup = true;
}
void Awake () { }
public override bool CheckResources ()
{
CheckSupport (mode == ColorCorrectionMode.Advanced);
ccMaterial = CheckShaderAndCreateMaterial (simpleColorCorrectionCurvesShader, ccMaterial);
ccDepthMaterial = CheckShaderAndCreateMaterial (colorCorrectionCurvesShader, ccDepthMaterial);
selectiveCcMaterial = CheckShaderAndCreateMaterial (colorCorrectionSelectiveShader, selectiveCcMaterial);
if (!rgbChannelTex)
rgbChannelTex = new Texture2D (256, 4, TextureFormat.ARGB32, false, true);
if (!rgbDepthChannelTex)
rgbDepthChannelTex = new Texture2D (256, 4, TextureFormat.ARGB32, false, true);
if (!zCurveTex)
zCurveTex = new Texture2D (256, 1, TextureFormat.ARGB32, false, true);
rgbChannelTex.hideFlags = HideFlags.DontSave;
rgbDepthChannelTex.hideFlags = HideFlags.DontSave;
zCurveTex.hideFlags = HideFlags.DontSave;
rgbChannelTex.wrapMode = TextureWrapMode.Clamp;
rgbDepthChannelTex.wrapMode = TextureWrapMode.Clamp;
zCurveTex.wrapMode = TextureWrapMode.Clamp;
if (!isSupported)
ReportAutoDisable ();
return isSupported;
}
public void UpdateParameters ()
{
CheckResources(); // textures might not be created if we're tweaking UI while disabled
if (redChannel != null && greenChannel != null && blueChannel != null)
{
for (float i = 0.0f; i <= 1.0f; i += 1.0f / 255.0f)
{
float rCh = Mathf.Clamp (redChannel.Evaluate(i), 0.0f, 1.0f);
float gCh = Mathf.Clamp (greenChannel.Evaluate(i), 0.0f, 1.0f);
float bCh = Mathf.Clamp (blueChannel.Evaluate(i), 0.0f, 1.0f);
rgbChannelTex.SetPixel ((int) Mathf.Floor(i*255.0f), 0, new Color(rCh,rCh,rCh) );
rgbChannelTex.SetPixel ((int) Mathf.Floor(i*255.0f), 1, new Color(gCh,gCh,gCh) );
rgbChannelTex.SetPixel ((int) Mathf.Floor(i*255.0f), 2, new Color(bCh,bCh,bCh) );
float zC = Mathf.Clamp (zCurve.Evaluate(i), 0.0f,1.0f);
zCurveTex.SetPixel ((int) Mathf.Floor(i*255.0f), 0, new Color(zC,zC,zC) );
rCh = Mathf.Clamp (depthRedChannel.Evaluate(i), 0.0f,1.0f);
gCh = Mathf.Clamp (depthGreenChannel.Evaluate(i), 0.0f,1.0f);
bCh = Mathf.Clamp (depthBlueChannel.Evaluate(i), 0.0f,1.0f);
rgbDepthChannelTex.SetPixel ((int) Mathf.Floor(i*255.0f), 0, new Color(rCh,rCh,rCh) );
rgbDepthChannelTex.SetPixel ((int) Mathf.Floor(i*255.0f), 1, new Color(gCh,gCh,gCh) );
rgbDepthChannelTex.SetPixel ((int) Mathf.Floor(i*255.0f), 2, new Color(bCh,bCh,bCh) );
}
rgbChannelTex.Apply ();
rgbDepthChannelTex.Apply ();
zCurveTex.Apply ();
}
}
public void UpdateTextures ()
{
UpdateParameters ();
}
void OnRenderImage (RenderTexture source, RenderTexture destination)
{
if (CheckResources()==false)
{
Graphics.Blit (source, destination);
return;
}
if (updateTexturesOnStartup)
{
UpdateParameters ();
updateTexturesOnStartup = false;
}
if (useDepthCorrection)
GetComponent<Camera>().depthTextureMode |= DepthTextureMode.Depth;
RenderTexture renderTarget2Use = destination;
if (selectiveCc)
{
renderTarget2Use = RenderTexture.GetTemporary (source.width, source.height);
}
if (useDepthCorrection)
{
ccDepthMaterial.SetTexture ("_RgbTex", rgbChannelTex);
ccDepthMaterial.SetTexture ("_ZCurve", zCurveTex);
ccDepthMaterial.SetTexture ("_RgbDepthTex", rgbDepthChannelTex);
ccDepthMaterial.SetFloat ("_Saturation", saturation);
Graphics.Blit (source, renderTarget2Use, ccDepthMaterial);
}
else
{
ccMaterial.SetTexture ("_RgbTex", rgbChannelTex);
ccMaterial.SetFloat ("_Saturation", saturation);
Graphics.Blit (source, renderTarget2Use, ccMaterial);
}
if (selectiveCc)
{
selectiveCcMaterial.SetColor ("selColor", selectiveFromColor);
selectiveCcMaterial.SetColor ("targetColor", selectiveToColor);
Graphics.Blit (renderTarget2Use, destination, selectiveCcMaterial);
RenderTexture.ReleaseTemporary (renderTarget2Use);
}
}
}
}

View File

@@ -0,0 +1,15 @@
fileFormatVersion: 2
guid: 2adfe5e4cdca8d740b1ae4b9ea08c040
MonoImporter:
serializedVersion: 2
defaultReferences:
- colorCorrectionCurvesShader: {fileID: 4800000, guid: 62bcade1028c24ca1a39760ed84b9487,
type: 3}
- simpleColorCorrectionCurvesShader: {fileID: 4800000, guid: 438ddd58d82c84d9eb1fdc56111702e1,
type: 3}
- colorCorrectionSelectiveShader: {fileID: 4800000, guid: e515e0f94cefc4c0db54b45cba621544,
type: 3}
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:

View File

@@ -0,0 +1,32 @@
using UnityEngine;
namespace DestroyIt
{
public class DustWall : MonoBehaviour
{
public GameObject playerDustPrefab; // A dust cloud particle effect that surrounds the player when the shockwave hits.
public float dustDurationSeconds = 10f; // How long (in seconds) to play the dust effect around a player after being hit by the shockwave.
public float dustStartDistance = 50f; // How far away from the player the dust effect starts.
public Vector3 fixedFromPosition;
void OnTriggerEnter(Collider collider)
{
if (collider.tag == "Player")
{
if (playerDustPrefab != null)
{
Transform player = collider.gameObject.transform;
GameObject dustCloud = Instantiate(playerDustPrefab, player.position, Quaternion.identity) as GameObject;
Follow followScript = dustCloud.AddComponent<Follow>();
followScript.isPositionFixed = true;
followScript.objectToFollow = player;
followScript.facingDirection = FacingDirection.FollowedObject;
followScript.fixedFromPosition = fixedFromPosition;
followScript.fixedDistance = dustStartDistance;
FadeParticleEffect fadeParticleEff = dustCloud.AddComponent<FadeParticleEffect>();
fadeParticleEff.delaySeconds = dustDurationSeconds - 2f; // allow for a two-second fadeout time.
}
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 9b13f8a31b5777a45a2ed5eef02d5e7d
timeCreated: 1426122767
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,139 @@
using System.Collections.Generic;
using UnityEngine;
namespace DestroyIt
{
public class Explode : MonoBehaviour
{
[Tooltip("The maximum amount of damage the blast can do. This is separate from, and does not affect, the force of the blast on rigidbodies.")]
public float blastDamage = 250f;
[Tooltip("The strength (or force) of the blast. Higher numbers push rigidbodies around more.")]
public float blastForce = 250f;
[Tooltip("The distance from point of impact where objects are considered to be hit at point blank range. Point Blank radius is checked first, then Near, then Far.")]
public float pointBlankBlastRadius = 2f;
[Tooltip("The percentage of blast damage applied to objects hit at point blank distance from the rocket's impact point.")]
[Range(0f, 1f)]
public float pointBlankDamagePercent = 1f;
[Tooltip("The distance from the point of impact where objects are nearby, but not considered point blank. Point Blank radius is checked first, then Near, then Far.")]
public float nearBlastRadius = 5f;
[Tooltip("The percentage of blast damage applied to objects hit at a distance near to the rocket's impact point.")]
[Range(0f, 1f)]
public float nearDamagePercent = .5f;
[Tooltip("The distance from the point of impact where objects are far away, but still considered to be in the blast zone. Point Blank radius is checked first, then Near, then Far.")]
public float farBlastRadius = 10f;
[Tooltip("The percentage of blast damage applied to objects hit within maximum effective distance from the rocket's impact point.")]
[Range(0f, 1f)]
public float farDamagePercent = .25f;
[Tooltip("The amount of upward \"push\" explosions have. Higher numbers make debris fly up in the air, but can get unrealistic.")]
[Range(0f, 3f)]
public float explosionUpwardPush = 1f;
private List<Rigidbody> affectedRigidbodies;
private Dictionary<ChipAwayDebris, float> affectedChipAwayDebris;
private Dictionary<Destructible, ExplosiveDamage> affectedDestructibles;
public void Start()
{
Vector3 currPos = transform.position;
affectedRigidbodies = new List<Rigidbody>();
affectedChipAwayDebris = new Dictionary<ChipAwayDebris, float>();
affectedDestructibles = new Dictionary<Destructible, ExplosiveDamage>();
// POINT BLANK RANGE - Apply force and damage to colliders and rigidbodies
int pointBlankCounter = Physics.OverlapSphereNonAlloc(currPos, pointBlankBlastRadius, DestructionManager.Instance.overlapColliders);
ExplosiveDamage pointBlankExplosiveDamage = new ExplosiveDamage()
{
Position = currPos,
DamageAmount = blastDamage * pointBlankDamagePercent,
BlastForce = blastForce,
Radius = farBlastRadius,
UpwardModifier = explosionUpwardPush
};
AddAffectedObjects(pointBlankCounter, pointBlankExplosiveDamage, .75f);
// NEAR RANGE - Apply force and damage to colliders and rigidbodies
int nearCounter = Physics.OverlapSphereNonAlloc(currPos, nearBlastRadius, DestructionManager.Instance.overlapColliders);
ExplosiveDamage nearExplosiveDamage = new ExplosiveDamage()
{
Position = currPos,
DamageAmount = blastDamage * nearDamagePercent,
BlastForce = blastForce,
Radius = farBlastRadius,
UpwardModifier = explosionUpwardPush
};
AddAffectedObjects(nearCounter, nearExplosiveDamage, .50f);
// FAR RANGE - Apply force and damage to colliders and rigidbodies
int farCounter = Physics.OverlapSphereNonAlloc(currPos, farBlastRadius, DestructionManager.Instance.overlapColliders);
ExplosiveDamage farExplosiveDamage = new ExplosiveDamage()
{
Position = currPos,
DamageAmount = blastDamage * farDamagePercent,
BlastForce = blastForce,
Radius = farBlastRadius,
UpwardModifier = explosionUpwardPush
};
AddAffectedObjects(farCounter, farExplosiveDamage, .25f);
// Apply blast force to all affected rigidbodies
foreach (Rigidbody rbody in affectedRigidbodies)
rbody.AddExplosionForce(blastForce, transform.position, farBlastRadius, explosionUpwardPush); // NOTE: farBlastRadius is used because we need the max radius for rigidbody force.
// Apply blast to ChipAwayDebris
foreach (KeyValuePair<ChipAwayDebris, float> chipAwayDebris in affectedChipAwayDebris)
{
if (Random.Range(1, 100) <= 100 * chipAwayDebris.Value) // Chip off debris pieces a fraction of the time, depending on how close they were to the blast point.
chipAwayDebris.Key.BreakOff(blastForce, farBlastRadius, explosionUpwardPush);
}
// Apply blast to Destructibles
foreach (KeyValuePair<Destructible, ExplosiveDamage> destructible in affectedDestructibles)
{
if (destructible.Value.DamageAmount > 0f)
destructible.Key.ApplyDamage(destructible.Value);
}
}
private void AddAffectedObjects(int colliderCount, ExplosiveDamage explosiveDamage, float chipAwayPercentage)
{
for (int i=0; i<colliderCount; i++)
{
Collider col = DestructionManager.Instance.overlapColliders[i];
// Ignore terrain colliders
if (col is TerrainCollider)
continue;
// Ignore self (the rocket)
if (col == GetComponent<Collider>())
continue;
// Check for Rigidbodies
Rigidbody rbody = col.attachedRigidbody;
if (rbody != null && !rbody.isKinematic && !affectedRigidbodies.Contains(rbody))
affectedRigidbodies.Add(rbody);
// Check for Chip-Away Debris
ChipAwayDebris chipAwayDebris = col.gameObject.GetComponent<ChipAwayDebris>();
if (chipAwayDebris != null && !affectedChipAwayDebris.ContainsKey(chipAwayDebris))
{
affectedChipAwayDebris.Add(chipAwayDebris, chipAwayPercentage);
continue; // Don't process destructible components on chip-away debris.
}
// Check for Destructible objects
Destructible destructible = col.gameObject.GetComponentInParent<Destructible>();
if (destructible != null && !affectedDestructibles.ContainsKey(destructible))
affectedDestructibles.Add(destructible, explosiveDamage);
}
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4ca94c4cbadf1ec46bb54a9f30ae10aa
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,38 @@
using UnityEngine;
namespace DestroyIt
{
/// <summary>
/// This script produces a screen-wide fade-in effect. It starts from one color and fades that color out over the specified number of seconds.
/// </summary>
public class FadeIn : MonoBehaviour
{
public Color startColor = Color.black;
[Range(0f, 10f)]
public float fadeLength = 2f; // how long (in seconds) the fade effect lasts
private Texture2D blackTexture;
private float alphaFadeValue = 1f;
void Start()
{
blackTexture = new Texture2D(1, 1, TextureFormat.ARGB32, false);
blackTexture.SetPixel(0, 0, startColor);
blackTexture.Apply();
}
void Update()
{
alphaFadeValue -= Mathf.Clamp01(Time.deltaTime / fadeLength);
if (alphaFadeValue <= 0f)
Destroy(this);
}
void OnGUI()
{
GUI.color = new Color(alphaFadeValue, alphaFadeValue, alphaFadeValue, alphaFadeValue);
GUI.DrawTexture(new Rect(0, 0, Screen.width, Screen.height), blackTexture);
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f9f2b43d9f0c502408b07cee6e222d2b
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,67 @@
using System.Collections.Generic;
using UnityEngine;
namespace DestroyIt
{
/// <summary>This script fades out all the child particle effects for the game object it is attached to.</summary>
public class FadeParticleEffect : MonoBehaviour
{
[Range(0f, 60f)]
public float delaySeconds = 10f; // How long to delay before starting the fade.
[Range(0f, 60f)]
public float fadeSeconds = 2f; // How long to spend fading out the particle effect.
[Range(1, 30)]
public int updatesPerSecond = 15; // How often to update the fade effect. Higher values have smoother fade-out, but higher performance cost.
private float fadeTiming;
private int stepCounter;
private float totalFadeSteps;
private List<ParticleEffectPropertyBag> particleEffectProperties;
void Start()
{
particleEffectProperties = new List<ParticleEffectPropertyBag>();
fadeTiming = 1 / (float)updatesPerSecond;
totalFadeSteps = fadeSeconds / fadeTiming;
Destroy(transform.gameObject, delaySeconds + fadeSeconds);
if (fadeSeconds > 0f)
InvokeRepeating("Fade", delaySeconds, fadeTiming);
}
void Fade()
{
stepCounter += 1;
if (particleEffectProperties.Count == 0)
{
ParticleSystem[] particleSystems = this.GetComponentsInChildren<ParticleSystem>();
foreach (ParticleSystem particleSystem in particleSystems)
{
Material mat = particleSystem.GetComponent<Renderer>().material;
if (!mat.HasProperty("_TintColor")) continue;
Color tintColorStart = mat.GetColor("_TintColor");
particleEffectProperties.Add(new ParticleEffectPropertyBag() { ParticleSystem = particleSystem, TintColorStart = tintColorStart });
}
}
foreach (ParticleEffectPropertyBag particleSystemPropBag in particleEffectProperties)
{
Material mat = particleSystemPropBag.ParticleSystem.GetComponent<Renderer>().material;
if (!mat.HasProperty("_TintColor")) continue;
Color tintColor = particleSystemPropBag.TintColorStart;
float fadeAmountPerStep = ((1.0f - particleSystemPropBag.TintColorStart.a) / 1.0f) / totalFadeSteps;
float newAlphaValue = Mathf.Clamp01(particleSystemPropBag.TintColorStart.a - (fadeAmountPerStep * stepCounter));
Color newTintColor = new Color(tintColor.r, tintColor.g, tintColor.b, newAlphaValue);
mat.SetColor("_TintColor", newTintColor);
}
}
}
public class ParticleEffectPropertyBag
{
public ParticleSystem ParticleSystem { get; set; }
public Color TintColorStart { get; set; }
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 05d89a5f64f3434468210dcef454a3f2
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,33 @@
using UnityEngine;
namespace DestroyIt
{
public class FlareFadeOut : MonoBehaviour
{
[Range(0f, 10f)]
public float flareFadeSeconds = 5f;
private float startBrightness;
private LensFlare flare;
// Use this for initialization
void Start()
{
flare = GetComponent<LensFlare>();
startBrightness = flare.brightness;
}
// Update is called once per frame
void Update()
{
flare.brightness -= Mathf.Clamp01(Time.deltaTime / (flareFadeSeconds / startBrightness));
if (flare.brightness <= 0f)
{
Destroy(flare);
Destroy(this);
}
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7376e4ac713bc3b40b71287dc2417142
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,32 @@
using UnityEngine;
namespace DestroyIt
{
public class FloatUp : MonoBehaviour
{
[Range(0f, 10f)]
public float floatSpeed = 5f;
private float checkFrequency = 0.05f; // The time (in seconds) this script checks for updates.
private float nextUpdateCheck;
// Use this for initialization
void Start()
{
nextUpdateCheck = Time.time + checkFrequency;
}
// Update is called once per frame
void Update()
{
if (Time.time > nextUpdateCheck)
{
// float up
this.gameObject.transform.position = this.gameObject.transform.position + (Vector3.up * floatSpeed);
// reset the counter
nextUpdateCheck = Time.time + checkFrequency;
}
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ec141900e15553f4d8ef3cc6b55aed82
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,69 @@
using UnityEngine;
namespace DestroyIt
{
/// <summary>
/// Put this script on your main camera if you want camera effects when the nuke explodes.
/// </summary>
[RequireComponent(typeof(Camera))]
public class NukeCameraEffect : MonoBehaviour
{
[Tooltip("Stores the initial, regular tonemapping settings of the main camera for later use.")]
public Tonemapping regularTonemapping;
[Tooltip("Alternate tonemapping settings to make the scene look over-exposed and strange while the nuke is active.")]
public Tonemapping nukeTonemapping;
[Tooltip("Optional additional color correction curves to use on the main camera to make the scene look strange while the nuke is active.")]
public ColorCorrectionCurves nukeColorCorrection;
public void Start()
{
// Use whichever tonemapper is enabled on the scene by default as the "regular" tonemapping.
// The other one will be used for "nuke effect" tonemapping.
Tonemapping[] toneMappers = GetComponents<Tonemapping>();
if (toneMappers != null && toneMappers.Length == 2)
{
if (toneMappers[0].enabled)
{
regularTonemapping = toneMappers[0];
nukeTonemapping = toneMappers[1];
}
else
{
nukeTonemapping = toneMappers[0];
regularTonemapping = toneMappers[1];
}
nukeTonemapping.enabled = false;
}
ColorCorrectionCurves colorCorrection = GetComponent<ColorCorrectionCurves>();
if (colorCorrection != null && !colorCorrection.enabled)
nukeColorCorrection = colorCorrection;
}
public void OnNukeStart()
{
// If the main camera has a ToneMapping component, switch it to the nuke tonemapping settings.
if (regularTonemapping != null && regularTonemapping.enabled)
{
regularTonemapping.enabled = false;
nukeTonemapping.enabled = true;
}
if (nukeColorCorrection != null && !nukeColorCorrection.enabled)
nukeColorCorrection.enabled = true;
}
public void OnNukeEnd()
{
// If the main camera has a ToneMapping component, deactivate it.
if (regularTonemapping != null && !regularTonemapping.enabled && nukeTonemapping != null && nukeTonemapping.enabled)
{
nukeTonemapping.enabled = false;
regularTonemapping.enabled = true;
}
if (nukeColorCorrection != null && nukeColorCorrection.enabled)
nukeColorCorrection.enabled = false;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 057f6fcdec714c445be9269b2346cce9
timeCreated: 1482263838
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,236 @@
using UnityEngine;
namespace DestroyIt
{
[ExecuteInEditMode]
[RequireComponent (typeof(Camera))]
public class PostEffectsBase : MonoBehaviour
{
protected bool supportHDRTextures = true;
protected bool supportDX11 = false;
protected bool isSupported = true;
protected Material CheckShaderAndCreateMaterial ( Shader s, Material m2Create)
{
if (!s)
{
Debug.Log("Missing shader in " + ToString ());
enabled = false;
return null;
}
if (s.isSupported && m2Create && m2Create.shader == s)
return m2Create;
if (!s.isSupported)
{
NotSupported ();
Debug.Log("The shader " + s.ToString() + " on effect "+ToString()+" is not supported on this platform!");
return null;
}
else
{
m2Create = new Material (s);
m2Create.hideFlags = HideFlags.DontSave;
if (m2Create)
return m2Create;
else return null;
}
}
protected Material CreateMaterial (Shader s, Material m2Create)
{
if (!s)
{
Debug.Log ("Missing shader in " + ToString ());
return null;
}
if (m2Create && (m2Create.shader == s) && (s.isSupported))
return m2Create;
if (!s.isSupported)
{
return null;
}
else
{
m2Create = new Material (s);
m2Create.hideFlags = HideFlags.DontSave;
if (m2Create)
return m2Create;
else return null;
}
}
void OnEnable ()
{
isSupported = true;
}
protected bool CheckSupport ()
{
return CheckSupport (false);
}
public virtual bool CheckResources ()
{
Debug.LogWarning ("CheckResources () for " + ToString() + " should be overwritten.");
return isSupported;
}
protected void Start ()
{
CheckResources ();
}
protected bool CheckSupport (bool needDepth)
{
isSupported = true;
supportHDRTextures = SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.ARGBHalf);
supportDX11 = SystemInfo.graphicsShaderLevel >= 50 && SystemInfo.supportsComputeShaders;
if (needDepth && !SystemInfo.SupportsRenderTextureFormat (RenderTextureFormat.Depth))
{
NotSupported ();
return false;
}
if (needDepth)
GetComponent<Camera>().depthTextureMode |= DepthTextureMode.Depth;
return true;
}
protected bool CheckSupport (bool needDepth, bool needHdr)
{
if (!CheckSupport(needDepth))
return false;
if (needHdr && !supportHDRTextures)
{
NotSupported ();
return false;
}
return true;
}
public bool Dx11Support ()
{
return supportDX11;
}
protected void ReportAutoDisable ()
{
Debug.LogWarning ("The image effect " + ToString() + " has been disabled as it's not supported on the current platform.");
}
// deprecated but needed for old effects to survive upgrading
bool CheckShader (Shader s)
{
Debug.Log("The shader " + s.ToString () + " on effect "+ ToString () + " is not part of the Unity 3.2+ effects suite anymore. For best performance and quality, please ensure you are using the latest Standard Assets Image Effects (Pro only) package.");
if (!s.isSupported)
{
NotSupported ();
return false;
}
else
{
return false;
}
}
protected void NotSupported ()
{
enabled = false;
isSupported = false;
return;
}
protected void DrawBorder (RenderTexture dest, Material material)
{
float x1;
float x2;
float y1;
float y2;
RenderTexture.active = dest;
bool invertY = true; // source.texelSize.y < 0.0ff;
// Set up the simple Matrix
GL.PushMatrix();
GL.LoadOrtho();
for (int i = 0; i < material.passCount; i++)
{
material.SetPass(i);
float y1_; float y2_;
if (invertY)
{
y1_ = 1.0f; y2_ = 0.0f;
}
else
{
y1_ = 0.0f; y2_ = 1.0f;
}
// left
x1 = 0.0f;
x2 = 0.0f + 1.0f/(dest.width*1.0f);
y1 = 0.0f;
y2 = 1.0f;
GL.Begin(GL.QUADS);
GL.TexCoord2(0.0f, y1_); GL.Vertex3(x1, y1, 0.1f);
GL.TexCoord2(1.0f, y1_); GL.Vertex3(x2, y1, 0.1f);
GL.TexCoord2(1.0f, y2_); GL.Vertex3(x2, y2, 0.1f);
GL.TexCoord2(0.0f, y2_); GL.Vertex3(x1, y2, 0.1f);
// right
x1 = 1.0f - 1.0f/(dest.width*1.0f);
x2 = 1.0f;
y1 = 0.0f;
y2 = 1.0f;
GL.TexCoord2(0.0f, y1_); GL.Vertex3(x1, y1, 0.1f);
GL.TexCoord2(1.0f, y1_); GL.Vertex3(x2, y1, 0.1f);
GL.TexCoord2(1.0f, y2_); GL.Vertex3(x2, y2, 0.1f);
GL.TexCoord2(0.0f, y2_); GL.Vertex3(x1, y2, 0.1f);
// top
x1 = 0.0f;
x2 = 1.0f;
y1 = 0.0f;
y2 = 0.0f + 1.0f/(dest.height*1.0f);
GL.TexCoord2(0.0f, y1_); GL.Vertex3(x1, y1, 0.1f);
GL.TexCoord2(1.0f, y1_); GL.Vertex3(x2, y1, 0.1f);
GL.TexCoord2(1.0f, y2_); GL.Vertex3(x2, y2, 0.1f);
GL.TexCoord2(0.0f, y2_); GL.Vertex3(x1, y2, 0.1f);
// bottom
x1 = 0.0f;
x2 = 1.0f;
y1 = 1.0f - 1.0f/(dest.height*1.0f);
y2 = 1.0f;
GL.TexCoord2(0.0f, y1_); GL.Vertex3(x1, y1, 0.1f);
GL.TexCoord2(1.0f, y1_); GL.Vertex3(x2, y1, 0.1f);
GL.TexCoord2(1.0f, y2_); GL.Vertex3(x2, y2, 0.1f);
GL.TexCoord2(0.0f, y2_); GL.Vertex3(x1, y2, 0.1f);
GL.End();
}
GL.PopMatrix();
}
}
}

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 89db801485ee4814a930357b9bbacc17
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:

View File

@@ -0,0 +1,16 @@
using UnityEngine;
namespace DestroyIt
{
public class ResetSkybox : MonoBehaviour
{
void Start()
{
// Reset the skybox blend amount to zero. This is only used for the demo scene.
if (RenderSettings.skybox.HasProperty("_Blend"))
RenderSettings.skybox.SetFloat("_Blend", 0f);
Destroy(this);
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 117a70a4471544147b194fe2d4fcc39a
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,198 @@
using UnityEngine;
namespace DestroyIt
{
[ExecuteInEditMode]
[RequireComponent (typeof(Camera))]
[AddComponentMenu("Image Effects/Rendering/Screen Space Ambient Occlusion")]
public class ScreenSpaceAmbientOcclusion : MonoBehaviour
{
public enum SSAOSamples
{
Low = 0,
Medium = 1,
High = 2,
}
public float m_Radius = 0.4f;
public SSAOSamples m_SampleCount = SSAOSamples.Medium;
public float m_OcclusionIntensity = 1.5f;
public int m_Blur = 2;
public int m_Downsampling = 2;
public float m_OcclusionAttenuation = 1.0f;
public float m_MinZ = 0.01f;
public Shader m_SSAOShader;
private Material m_SSAOMaterial;
public Texture2D m_RandomTexture;
private bool m_Supported;
private static Material CreateMaterial (Shader shader)
{
if (!shader)
return null;
Material m = new Material (shader);
m.hideFlags = HideFlags.HideAndDontSave;
return m;
}
private static void DestroyMaterial (Material mat)
{
if (mat)
{
DestroyImmediate (mat);
mat = null;
}
}
void OnDisable()
{
DestroyMaterial (m_SSAOMaterial);
}
void Start()
{
if (!SystemInfo.SupportsRenderTextureFormat (RenderTextureFormat.Depth))
{
m_Supported = false;
enabled = false;
return;
}
CreateMaterials ();
if (!m_SSAOMaterial || m_SSAOMaterial.passCount != 5)
{
m_Supported = false;
enabled = false;
return;
}
//CreateRandomTable (26, 0.2f);
m_Supported = true;
}
void OnEnable () {
GetComponent<Camera>().depthTextureMode |= DepthTextureMode.DepthNormals;
}
private void CreateMaterials ()
{
if (!m_SSAOMaterial && m_SSAOShader.isSupported)
{
m_SSAOMaterial = CreateMaterial (m_SSAOShader);
m_SSAOMaterial.SetTexture ("_RandomTexture", m_RandomTexture);
}
}
[ImageEffectOpaque]
void OnRenderImage (RenderTexture source, RenderTexture destination)
{
if (!m_Supported || !m_SSAOShader.isSupported) {
enabled = false;
return;
}
CreateMaterials ();
m_Downsampling = Mathf.Clamp (m_Downsampling, 1, 6);
m_Radius = Mathf.Clamp (m_Radius, 0.05f, 1.0f);
m_MinZ = Mathf.Clamp (m_MinZ, 0.00001f, 0.5f);
m_OcclusionIntensity = Mathf.Clamp (m_OcclusionIntensity, 0.5f, 4.0f);
m_OcclusionAttenuation = Mathf.Clamp (m_OcclusionAttenuation, 0.2f, 2.0f);
m_Blur = Mathf.Clamp (m_Blur, 0, 4);
// Render SSAO term into a smaller texture
RenderTexture rtAO = RenderTexture.GetTemporary (source.width / m_Downsampling, source.height / m_Downsampling, 0);
float fovY = GetComponent<Camera>().fieldOfView;
float far = GetComponent<Camera>().farClipPlane;
float y = Mathf.Tan (fovY * Mathf.Deg2Rad * 0.5f) * far;
float x = y * GetComponent<Camera>().aspect;
m_SSAOMaterial.SetVector ("_FarCorner", new Vector3(x,y,far));
int noiseWidth, noiseHeight;
if (m_RandomTexture) {
noiseWidth = m_RandomTexture.width;
noiseHeight = m_RandomTexture.height;
} else {
noiseWidth = 1; noiseHeight = 1;
}
m_SSAOMaterial.SetVector ("_NoiseScale", new Vector3 ((float)rtAO.width / noiseWidth, (float)rtAO.height / noiseHeight, 0.0f));
m_SSAOMaterial.SetVector ("_Params", new Vector4(
m_Radius,
m_MinZ,
1.0f / m_OcclusionAttenuation,
m_OcclusionIntensity));
bool doBlur = m_Blur > 0;
Graphics.Blit (doBlur ? null : source, rtAO, m_SSAOMaterial, (int)m_SampleCount);
if (doBlur)
{
// Blur SSAO horizontally
RenderTexture rtBlurX = RenderTexture.GetTemporary (source.width, source.height, 0);
m_SSAOMaterial.SetVector ("_TexelOffsetScale",
new Vector4 ((float)m_Blur / source.width, 0,0,0));
m_SSAOMaterial.SetTexture ("_SSAO", rtAO);
Graphics.Blit (null, rtBlurX, m_SSAOMaterial, 3);
RenderTexture.ReleaseTemporary (rtAO); // original rtAO not needed anymore
// Blur SSAO vertically
RenderTexture rtBlurY = RenderTexture.GetTemporary (source.width, source.height, 0);
m_SSAOMaterial.SetVector ("_TexelOffsetScale",
new Vector4 (0, (float)m_Blur/source.height, 0,0));
m_SSAOMaterial.SetTexture ("_SSAO", rtBlurX);
Graphics.Blit (source, rtBlurY, m_SSAOMaterial, 3);
RenderTexture.ReleaseTemporary (rtBlurX); // blurX RT not needed anymore
rtAO = rtBlurY; // AO is the blurred one now
}
// Modulate scene rendering with SSAO
m_SSAOMaterial.SetTexture ("_SSAO", rtAO);
Graphics.Blit (source, destination, m_SSAOMaterial, 4);
RenderTexture.ReleaseTemporary (rtAO);
}
/*
private void CreateRandomTable (int count, float minLength)
{
Random.seed = 1337;
Vector3[] samples = new Vector3[count];
// initial samples
for (int i = 0; i < count; ++i)
samples[i] = Random.onUnitSphere;
// energy minimization: push samples away from others
int iterations = 100;
while (iterations-- > 0) {
for (int i = 0; i < count; ++i) {
Vector3 vec = samples[i];
Vector3 res = Vector3.zero;
// minimize with other samples
for (int j = 0; j < count; ++j) {
Vector3 force = vec - samples[j];
float fac = Vector3.Dot (force, force);
if (fac > 0.00001f)
res += force * (1.0f / fac);
}
samples[i] = (samples[i] + res * 0.5f).normalized;
}
}
// now scale samples between minLength and 1.0
for (int i = 0; i < count; ++i) {
samples[i] = samples[i] * Random.Range (minLength, 1.0f);
}
string table = string.Format ("#define SAMPLE_COUNT {0}\n", count);
table += "const float3 RAND_SAMPLES[SAMPLE_COUNT] = {\n";
for (int i = 0; i < count; ++i) {
Vector3 v = samples[i];
table += string.Format("\tfloat3({0},{1},{2}),\n", v.x, v.y, v.z);
}
table += "};\n";
Debug.Log (table);
}
*/
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 9f372122fe30c144b93cadbedbf22d8d
MonoImporter:
serializedVersion: 2
defaultReferences:
- m_SSAOShader: {fileID: 4800000, guid: 43ca18288c424f645aaa1e9e07f04c50, type: 3}
- m_RandomTexture: {fileID: 2800000, guid: a181ca8e3c62f3e4b8f183f6c586b032, type: 3}
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,44 @@
using UnityEngine;
namespace DestroyIt
{
public class ShockWall : MonoBehaviour
{
public float blastForce = 200f;
public float damageAmount = 200f;
public Vector3 origin;
private void OnTriggerEnter(Collider col)
{
// If it has a rigidbody, apply force
Rigidbody rbody = col.attachedRigidbody;
if (rbody != null && !rbody.isKinematic)
rbody.AddExplosionForce(blastForce, origin, 0f, 0.5f);
// Check for Chip-Away Debris
ChipAwayDebris chipAwayDebris = col.gameObject.GetComponent<ChipAwayDebris>();
if (chipAwayDebris != null)
{
if (Random.Range(1, 100) > 50) // Do this about half the time...
{
chipAwayDebris.BreakOff(blastForce, 0f, 0.5f);
return; //Skip the destructible check if the debris hasn't chipped away yet.
}
return;
}
// If it's a destructible object, apply damage
// Only do this for the first active and enabled Destructible script found in parent objects
// Special Note: Destructible scripts are turned off on terrain trees by default (to save resources), so we will make an exception for them and process the damage anyway
Destructible[] destObjs = col.gameObject.GetComponentsInParent<Destructible>(false);
foreach (Destructible destObj in destObjs)
{
if (!destObj.isActiveAndEnabled && !destObj.isTerrainTree) continue;
ExplosiveDamage explosiveDamage = new ExplosiveDamage { DamageAmount = damageAmount, BlastForce = blastForce, Position = origin, Radius = 0f, UpwardModifier = 0.5f };
destObj.ApplyDamage(explosiveDamage);
break;
}
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: aca012ace7354df46ac42baa938124fe
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,124 @@
using UnityEngine;
namespace DestroyIt
{
[RequireComponent(typeof(SphereCollider))]
[RequireComponent(typeof(Rigidbody))]
public class ShockWaveSphere : MonoBehaviour
{
[Tooltip("How many seconds to wait before the shockwave starts.")]
public float timer = 10f;
[Tooltip("The particle effect to use for the shockwave.")]
public ParticleSystem visualEffect;
[Tooltip("How much force to apply to rigidbodies hit by the shockwave.")]
public float blastForce = 500f;
[Tooltip("How much damage to apply to Destructible objects that are hit by the shockwave.")]
public float damageAmount = 200f;
[Tooltip("How fast the shockwave spreads out.")]
public float shockwaveSpeed = 30f;
[Tooltip("The maximum radius of the shockwave. Once it reaches this size, it is disabled and removed from the scene.")]
public float maxRadius = 300f;
private Vector3 _originPos; // the world position where the shockwave originates
private float _timeLeft;
private bool _isInitialized;
private bool _hasStarted;
private SphereCollider _sphereCollider;
private Rigidbody _rigidbody;
public void Start()
{
Initialize();
}
public void OnEnable()
{
Initialize();
}
private void Initialize()
{
if (_isInitialized) return;
_originPos = transform.position;
_timeLeft = timer;
_sphereCollider = gameObject.GetComponent<SphereCollider>();
_sphereCollider.isTrigger = true;
_sphereCollider.radius = 0f;
_rigidbody = gameObject.GetComponent<Rigidbody>();
_rigidbody.useGravity = false;
_isInitialized = true;
}
public void Update()
{
if (!_isInitialized) return;
if (_hasStarted)
{
// Check if the shockwave has reached its max size. If so, destroy it.
if (_sphereCollider.radius >= maxRadius)
{
gameObject.SetActive(false);
Destroy(gameObject);
return;
}
// Grow the shockwave based on the shockwave speed
_sphereCollider.radius += Time.deltaTime * shockwaveSpeed;
return;
}
_timeLeft -= Time.deltaTime;
if (_timeLeft <= 0)
{
// Start the shockwave
if (visualEffect != null)
Instantiate(visualEffect, _originPos, Quaternion.identity);
_hasStarted = true;
}
}
public void OnTriggerEnter(Collider col)
{
// If it has a rigidbody, apply force
Rigidbody rbody = col.attachedRigidbody;
if (rbody != null && !rbody.isKinematic)
rbody.AddExplosionForce(blastForce, _originPos, 0f, 0.5f);
// Check for Chip-Away Debris
ChipAwayDebris chipAwayDebris = col.gameObject.GetComponent<ChipAwayDebris>();
if (chipAwayDebris != null)
{
if (Random.Range(1, 100) > 50) // Do this about half the time...
{
chipAwayDebris.BreakOff(blastForce, 0f, 0.5f);
return; //Skip the destructible check if the debris hasn't chipped away yet.
}
return;
}
// If it's a destructible object, apply damage
// Only do this for the first active and enabled Destructible script found in parent objects
// Special Note: Destructible scripts are turned off on terrain trees by default (to save resources), so we will make an exception for them and process the damage anyway
Destructible[] destObjs = col.gameObject.GetComponentsInParent<Destructible>(false);
foreach (Destructible destObj in destObjs)
{
if (!destObj.isActiveAndEnabled && !destObj.isTerrainTree) continue;
ExplosiveDamage explosiveDamage = new ExplosiveDamage { DamageAmount = damageAmount, BlastForce = blastForce, Position = _originPos, Radius = 0f, UpwardModifier = 0.5f };
destObj.ApplyDamage(explosiveDamage);
break;
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3631767c8c3d4029aea8d849d9c5bbc0
timeCreated: 1648252882

View File

@@ -0,0 +1,85 @@
using UnityEngine;
using System.Collections.Generic;
namespace DestroyIt
{
public class SmoothMouseLook : MonoBehaviour
{
// Public variables
public float sensitivityX = 2.0f;
public float sensitivityY = 2.0f;
public float minimumY = -60f;
public float maximumY = 60f;
public int frameCounterX = 20;
public int frameCounterY = 20;
// Private variables
private float rotationX;
private float rotationY;
private Quaternion xQuaternion;
private Quaternion yQuaternion;
private Quaternion origRotation;
private List<float> rotationsX = new List<float>();
private List<float> rotationsY = new List<float>();
void Start()
{
Cursor.lockState = CursorLockMode.Locked;
if (GetComponent<Rigidbody>())
GetComponent<Rigidbody>().freezeRotation = true;
origRotation = transform.localRotation;
}
void Update()
{
if (Cursor.lockState == CursorLockMode.Locked)
{
// Add X rotation
rotationX += Input.GetAxis("Mouse X") * sensitivityX;
rotationsX.Add(rotationX);
// Add Y rotation
rotationY += Input.GetAxis("Mouse Y") * sensitivityY;
rotationY = ClampAngle(rotationY, minimumY, maximumY);
rotationsY.Add(rotationY);
// Average rotations
float rotAverageX = AverageRotations(rotationsX, frameCounterX);
float rotAverageY = AverageRotations(rotationsY, frameCounterY);
// Perform rotation based on averages
xQuaternion = Quaternion.AngleAxis(rotAverageX, Vector3.up);
yQuaternion = Quaternion.AngleAxis(rotAverageY, Vector3.left);
transform.localRotation = origRotation * xQuaternion * yQuaternion;
}
else
Cursor.visible = true;
}
private static float AverageRotations(List<float> rotations, int frameCounter)
{
float rotAverage = 0f;
if (rotations.Count >= frameCounter)
rotations.RemoveAt(0);
for (int i = 0; i < rotations.Count; i++)
rotAverage += rotations[i];
rotAverage /= rotations.Count;
return rotAverage;
}
private float ClampAngle(float angle, float min, float max)
{
if (angle < -360f)
angle += 360f;
if (angle > 360f)
angle -= 360f;
return Mathf.Clamp(angle, min, max);
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f4b44c5f660801648ac6d666e3d0dbef
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,271 @@
using UnityEngine;
namespace DestroyIt
{
[ExecuteInEditMode]
[RequireComponent(typeof (Camera))]
[AddComponentMenu("Image Effects/Color Adjustments/Tonemapping")]
public class Tonemapping : PostEffectsBase
{
public enum TonemapperType
{
SimpleReinhard,
UserCurve,
Hable,
Photographic,
OptimizedHejiDawson,
AdaptiveReinhard,
AdaptiveReinhardAutoWhite,
};
public enum AdaptiveTexSize
{
Square16 = 16,
Square32 = 32,
Square64 = 64,
Square128 = 128,
Square256 = 256,
Square512 = 512,
Square1024 = 1024,
};
public TonemapperType type = TonemapperType.Photographic;
public AdaptiveTexSize adaptiveTextureSize = AdaptiveTexSize.Square256;
// CURVE parameter
public AnimationCurve remapCurve;
private Texture2D curveTex = null;
// UNCHARTED parameter
public float exposureAdjustment = 1.5f;
// REINHARD parameter
public float middleGrey = 0.4f;
public float white = 2.0f;
public float adaptionSpeed = 1.5f;
// usual & internal stuff
public Shader tonemapper = null;
public bool validRenderTextureFormat = true;
private Material tonemapMaterial = null;
private RenderTexture rt = null;
private RenderTextureFormat rtFormat = RenderTextureFormat.ARGBHalf;
public override bool CheckResources()
{
CheckSupport(false, true);
tonemapMaterial = CheckShaderAndCreateMaterial(tonemapper, tonemapMaterial);
if (!curveTex && type == TonemapperType.UserCurve)
{
curveTex = new Texture2D(256, 1, TextureFormat.ARGB32, false, true);
curveTex.filterMode = FilterMode.Bilinear;
curveTex.wrapMode = TextureWrapMode.Clamp;
curveTex.hideFlags = HideFlags.DontSave;
}
if (!isSupported)
ReportAutoDisable();
return isSupported;
}
public float UpdateCurve()
{
float range = 1.0f;
if (remapCurve.keys.Length < 1)
remapCurve = new AnimationCurve(new Keyframe(0, 0), new Keyframe(2, 1));
if (remapCurve != null)
{
if (remapCurve.length > 0)
range = remapCurve[remapCurve.length - 1].time;
for (float i = 0.0f; i <= 1.0f; i += 1.0f/255.0f)
{
float c = remapCurve.Evaluate(i*1.0f*range);
curveTex.SetPixel((int) Mathf.Floor(i*255.0f), 0, new Color(c, c, c));
}
curveTex.Apply();
}
return 1.0f/range;
}
private void OnDisable()
{
if (rt)
{
DestroyImmediate(rt);
rt = null;
}
if (tonemapMaterial)
{
DestroyImmediate(tonemapMaterial);
tonemapMaterial = null;
}
if (curveTex)
{
DestroyImmediate(curveTex);
curveTex = null;
}
}
private bool CreateInternalRenderTexture()
{
if (rt)
{
return false;
}
rtFormat = SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.RGHalf) ? RenderTextureFormat.RGHalf : RenderTextureFormat.ARGBHalf;
rt = new RenderTexture(1, 1, 0, rtFormat);
rt.hideFlags = HideFlags.DontSave;
return true;
}
// attribute indicates that the image filter chain will continue in LDR
[ImageEffectTransformsToLDR]
private void OnRenderImage(RenderTexture source, RenderTexture destination)
{
if (CheckResources() == false)
{
Graphics.Blit(source, destination);
return;
}
#if UNITY_EDITOR
validRenderTextureFormat = true;
if (source.format != RenderTextureFormat.ARGBHalf)
{
validRenderTextureFormat = false;
}
#endif
// clamp some values to not go out of a valid range
exposureAdjustment = exposureAdjustment < 0.001f ? 0.001f : exposureAdjustment;
// SimpleReinhard tonemappers (local, non adaptive)
if (type == TonemapperType.UserCurve)
{
float rangeScale = UpdateCurve();
tonemapMaterial.SetFloat("_RangeScale", rangeScale);
tonemapMaterial.SetTexture("_Curve", curveTex);
Graphics.Blit(source, destination, tonemapMaterial, 4);
return;
}
if (type == TonemapperType.SimpleReinhard)
{
tonemapMaterial.SetFloat("_ExposureAdjustment", exposureAdjustment);
Graphics.Blit(source, destination, tonemapMaterial, 6);
return;
}
if (type == TonemapperType.Hable)
{
tonemapMaterial.SetFloat("_ExposureAdjustment", exposureAdjustment);
Graphics.Blit(source, destination, tonemapMaterial, 5);
return;
}
if (type == TonemapperType.Photographic)
{
tonemapMaterial.SetFloat("_ExposureAdjustment", exposureAdjustment);
Graphics.Blit(source, destination, tonemapMaterial, 8);
return;
}
if (type == TonemapperType.OptimizedHejiDawson)
{
tonemapMaterial.SetFloat("_ExposureAdjustment", 0.5f*exposureAdjustment);
Graphics.Blit(source, destination, tonemapMaterial, 7);
return;
}
// still here?
// => adaptive tone mapping:
// builds an average log luminance, tonemaps according to
// middle grey and white values (user controlled)
// AdaptiveReinhardAutoWhite will calculate white value automagically
bool freshlyBrewedInternalRt = CreateInternalRenderTexture(); // this retrieves rtFormat, so should happen before rt allocations
RenderTexture rtSquared = RenderTexture.GetTemporary((int) adaptiveTextureSize, (int) adaptiveTextureSize, 0, rtFormat);
Graphics.Blit(source, rtSquared);
int downsample = (int) Mathf.Log(rtSquared.width*1.0f, 2);
int div = 2;
var rts = new RenderTexture[downsample];
for (int i = 0; i < downsample; i++)
{
rts[i] = RenderTexture.GetTemporary(rtSquared.width/div, rtSquared.width/div, 0, rtFormat);
div *= 2;
}
// downsample pyramid
var lumRt = rts[downsample - 1];
Graphics.Blit(rtSquared, rts[0], tonemapMaterial, 1);
if (type == TonemapperType.AdaptiveReinhardAutoWhite)
{
for (int i = 0; i < downsample - 1; i++)
{
Graphics.Blit(rts[i], rts[i + 1], tonemapMaterial, 9);
lumRt = rts[i + 1];
}
}
else if (type == TonemapperType.AdaptiveReinhard)
{
for (int i = 0; i < downsample - 1; i++)
{
Graphics.Blit(rts[i], rts[i + 1]);
lumRt = rts[i + 1];
}
}
// we have the needed values, let's apply adaptive tonemapping
adaptionSpeed = adaptionSpeed < 0.001f ? 0.001f : adaptionSpeed;
tonemapMaterial.SetFloat("_AdaptionSpeed", adaptionSpeed);
#if UNITY_EDITOR
if (Application.isPlaying && !freshlyBrewedInternalRt)
Graphics.Blit(lumRt, rt, tonemapMaterial, 2);
else
Graphics.Blit(lumRt, rt, tonemapMaterial, 3);
#else
Graphics.Blit (lumRt, rt, tonemapMaterial, freshlyBrewedInternalRt ? 3 : 2);
#endif
middleGrey = middleGrey < 0.001f ? 0.001f : middleGrey;
tonemapMaterial.SetVector("_HdrParams", new Vector4(middleGrey, middleGrey, middleGrey, white*white));
tonemapMaterial.SetTexture("_SmallTex", rt);
if (type == TonemapperType.AdaptiveReinhard)
{
Graphics.Blit(source, destination, tonemapMaterial, 0);
}
else if (type == TonemapperType.AdaptiveReinhardAutoWhite)
{
Graphics.Blit(source, destination, tonemapMaterial, 10);
}
else
{
Debug.LogError("No valid adaptive tonemapper type found!");
Graphics.Blit(source, destination); // at least we get the TransformToLDR effect
}
// cleanup for adaptive
for (int i = 0; i < downsample; i++)
{
RenderTexture.ReleaseTemporary(rts[i]);
}
RenderTexture.ReleaseTemporary(rtSquared);
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 984c820fad35bd149ab5d581d2296070
MonoImporter:
serializedVersion: 2
defaultReferences:
- tonemapper: {fileID: 4800000, guid: 003377fc2620a44939dadde6fe3f8190, type: 3}
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: cbcaca60e877cf347841a0f9c4d71029
folderAsset: yes
timeCreated: 1517186452
licenseType: Store
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,299 @@
using System;
using UnityEngine;
namespace DestroyIt
{
public static class CrossPlatformInputManager
{
public enum ActiveInputMethod
{
Hardware,
Touch
}
private static VirtualInput activeInput;
private static VirtualInput s_TouchInput;
private static VirtualInput s_HardwareInput;
static CrossPlatformInputManager()
{
s_TouchInput = new MobileInput();
s_HardwareInput = new StandaloneInput();
#if MOBILE_INPUT
activeInput = s_TouchInput;
#else
activeInput = s_HardwareInput;
#endif
}
public static void SwitchActiveInputMethod(ActiveInputMethod activeInputMethod)
{
switch (activeInputMethod)
{
case ActiveInputMethod.Hardware:
activeInput = s_HardwareInput;
break;
case ActiveInputMethod.Touch:
activeInput = s_TouchInput;
break;
}
}
public static bool AxisExists(string name)
{
return activeInput.AxisExists(name);
}
public static bool ButtonExists(string name)
{
return activeInput.ButtonExists(name);
}
public static void RegisterVirtualAxis(VirtualAxis axis)
{
activeInput.RegisterVirtualAxis(axis);
}
public static void RegisterVirtualButton(VirtualButton button)
{
activeInput.RegisterVirtualButton(button);
}
public static void UnRegisterVirtualAxis(string name)
{
if (name == null)
{
throw new ArgumentNullException("name");
}
activeInput.UnRegisterVirtualAxis(name);
}
public static void UnRegisterVirtualButton(string name)
{
activeInput.UnRegisterVirtualButton(name);
}
// returns a reference to a named virtual axis if it exists otherwise null
public static VirtualAxis VirtualAxisReference(string name)
{
return activeInput.VirtualAxisReference(name);
}
// returns the platform appropriate axis for the given name
public static float GetAxis(string name)
{
return GetAxis(name, false);
}
public static float GetAxisRaw(string name)
{
return GetAxis(name, true);
}
// private function handles both types of axis (raw and not raw)
private static float GetAxis(string name, bool raw)
{
return activeInput.GetAxis(name, raw);
}
// -- Button handling --
public static bool GetButton(string name)
{
return activeInput.GetButton(name);
}
public static bool GetButtonDown(string name)
{
return activeInput.GetButtonDown(name);
}
public static bool GetButtonUp(string name)
{
return activeInput.GetButtonUp(name);
}
public static void SetButtonDown(string name)
{
activeInput.SetButtonDown(name);
}
public static void SetButtonUp(string name)
{
activeInput.SetButtonUp(name);
}
public static void SetAxisPositive(string name)
{
activeInput.SetAxisPositive(name);
}
public static void SetAxisNegative(string name)
{
activeInput.SetAxisNegative(name);
}
public static void SetAxisZero(string name)
{
activeInput.SetAxisZero(name);
}
public static void SetAxis(string name, float value)
{
activeInput.SetAxis(name, value);
}
public static Vector3 mousePosition
{
get { return activeInput.MousePosition(); }
}
public static void SetVirtualMousePositionX(float f)
{
activeInput.SetVirtualMousePositionX(f);
}
public static void SetVirtualMousePositionY(float f)
{
activeInput.SetVirtualMousePositionY(f);
}
public static void SetVirtualMousePositionZ(float f)
{
activeInput.SetVirtualMousePositionZ(f);
}
// virtual axis and button classes - applies to mobile input
// Can be mapped to touch joysticks, tilt, gyro, etc, depending on desired implementation.
// Could also be implemented by other input devices - kinect, electronic sensors, etc
public class VirtualAxis
{
public string name { get; private set; }
private float m_Value;
public bool matchWithInputManager { get; private set; }
public VirtualAxis(string name)
: this(name, true)
{
}
public VirtualAxis(string name, bool matchToInputSettings)
{
this.name = name;
matchWithInputManager = matchToInputSettings;
}
// removes an axes from the cross platform input system
public void Remove()
{
UnRegisterVirtualAxis(name);
}
// a controller gameobject (eg. a virtual thumbstick) should update this class
public void Update(float value)
{
m_Value = value;
}
public float GetValue
{
get { return m_Value; }
}
public float GetValueRaw
{
get { return m_Value; }
}
}
// a controller gameobject (eg. a virtual GUI button) should call the
// 'pressed' function of this class. Other objects can then read the
// Get/Down/Up state of this button.
public class VirtualButton
{
public string name { get; private set; }
public bool matchWithInputManager { get; private set; }
private int m_LastPressedFrame = -5;
private int m_ReleasedFrame = -5;
private bool m_Pressed;
public VirtualButton(string name)
: this(name, true)
{
}
public VirtualButton(string name, bool matchToInputSettings)
{
this.name = name;
matchWithInputManager = matchToInputSettings;
}
// A controller gameobject should call this function when the button is pressed down
public void Pressed()
{
if (m_Pressed)
{
return;
}
m_Pressed = true;
m_LastPressedFrame = Time.frameCount;
}
// A controller gameobject should call this function when the button is released
public void Released()
{
m_Pressed = false;
m_ReleasedFrame = Time.frameCount;
}
// the controller gameobject should call Remove when the button is destroyed or disabled
public void Remove()
{
UnRegisterVirtualButton(name);
}
// these are the states of the button which can be read via the cross platform input system
public bool GetButton
{
get { return m_Pressed; }
}
public bool GetButtonDown
{
get
{
return m_LastPressedFrame - Time.frameCount == -1;
}
}
public bool GetButtonUp
{
get
{
return (m_ReleasedFrame == Time.frameCount - 1);
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f49091ed45769774391e7704a20c863a
labels:
- Done
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: -1010
icon: {instanceID: 0}
userData:
assetBundleName:

View File

@@ -0,0 +1,152 @@
using UnityEngine;
namespace DestroyIt
{
[RequireComponent(typeof (CharacterController))]
[RequireComponent(typeof (AudioSource))]
public class FirstPersonController : MonoBehaviour
{
[SerializeField] private bool m_IsWalking = false;
[SerializeField] private float m_WalkSpeed = 0f;
[SerializeField] private float m_RunSpeed = 0f;
[SerializeField] [Range(0f, 1f)] private float m_RunstepLenghten = 0f;
[SerializeField] private float m_JumpSpeed = 0f;
[SerializeField] private float m_StickToGroundForce = 0f;
[SerializeField] private float m_GravityMultiplier = 0f;
[SerializeField] private MouseLook m_MouseLook = new MouseLook();
[SerializeField] private float m_StepInterval = 0f;
private Camera m_Camera;
private bool m_Jump;
private float m_YRotation;
private Vector2 m_Input;
private Vector3 m_MoveDir = Vector3.zero;
private CharacterController m_CharacterController;
private CollisionFlags m_CollisionFlags;
private bool m_PreviouslyGrounded;
private float m_StepCycle;
private float m_NextStep;
private bool m_Jumping;
// Use this for initialization
private void Start()
{
m_CharacterController = GetComponent<CharacterController>();
m_Camera = Camera.main;
m_StepCycle = 0f;
m_NextStep = m_StepCycle/2f;
m_Jumping = false;
m_MouseLook.Init(transform , m_Camera.transform);
}
// Update is called once per frame
private void Update()
{
RotateView();
// the jump state needs to read here to make sure it is not missed
if (!m_Jump)
m_Jump = CrossPlatformInputManager.GetButtonDown("Jump");
if (!m_PreviouslyGrounded && m_CharacterController.isGrounded)
{
m_MoveDir.y = 0f;
m_Jumping = false;
}
if (!m_CharacterController.isGrounded && !m_Jumping && m_PreviouslyGrounded)
m_MoveDir.y = 0f;
m_PreviouslyGrounded = m_CharacterController.isGrounded;
}
private void FixedUpdate()
{
float speed;
GetInput(out speed);
// always move along the camera forward as it is the direction that it being aimed at
Vector3 desiredMove = transform.forward*m_Input.y + transform.right*m_Input.x;
// get a normal for the surface that is being touched to move along it
RaycastHit hitInfo;
Physics.SphereCast(transform.position, m_CharacterController.radius, Vector3.down, out hitInfo,
m_CharacterController.height/2f, Physics.AllLayers, QueryTriggerInteraction.Ignore);
desiredMove = Vector3.ProjectOnPlane(desiredMove, hitInfo.normal).normalized;
m_MoveDir.x = desiredMove.x*speed;
m_MoveDir.z = desiredMove.z*speed;
if (m_CharacterController.isGrounded)
{
m_MoveDir.y = -m_StickToGroundForce;
if (m_Jump)
{
m_MoveDir.y = m_JumpSpeed;
m_Jump = false;
m_Jumping = true;
}
}
else
{
m_MoveDir += Physics.gravity*m_GravityMultiplier*Time.fixedDeltaTime;
}
m_CollisionFlags = m_CharacterController.Move(m_MoveDir*Time.fixedDeltaTime);
ProgressStepCycle(speed);
m_MouseLook.UpdateCursorLock();
}
private void ProgressStepCycle(float speed)
{
if (m_CharacterController.velocity.sqrMagnitude > 0 && (m_Input.x != 0 || m_Input.y != 0))
{
m_StepCycle += (m_CharacterController.velocity.magnitude + (speed*(m_IsWalking ? 1f : m_RunstepLenghten)))*
Time.fixedDeltaTime;
}
if (!(m_StepCycle > m_NextStep)) return;
m_NextStep = m_StepCycle + m_StepInterval;
}
private void GetInput(out float speed)
{
// Read input
float horizontal = CrossPlatformInputManager.GetAxis("Horizontal");
float vertical = CrossPlatformInputManager.GetAxis("Vertical");
#if !MOBILE_INPUT
// On standalone builds, walk/run speed is modified by a key press.
// keep track of whether or not the character is walking or running
m_IsWalking = !Input.GetKey(KeyCode.LeftShift);
#endif
// set the desired speed to be walking or running
speed = m_IsWalking ? m_WalkSpeed : m_RunSpeed;
m_Input = new Vector2(horizontal, vertical);
// normalize input if it exceeds 1 in combined length:
if (m_Input.sqrMagnitude > 1)
m_Input.Normalize();
}
private void RotateView()
{
m_MouseLook.LookRotation (transform, m_Camera.transform);
}
private void OnControllerColliderHit(ControllerColliderHit hit)
{
Rigidbody body = hit.collider.attachedRigidbody;
//dont move the rigidbody if the character is on top of it
if (m_CollisionFlags == CollisionFlags.Below) return;
if (body == null || body.isKinematic) return;
body.AddForceAtPosition(m_CharacterController.velocity*0.1f, hit.point, ForceMode.Impulse);
}
}
}

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: a72d5b590f8ef8e4fa0fe163662c0e0c
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:

View File

@@ -0,0 +1,120 @@
using UnityEngine;
namespace DestroyIt
{
public class MobileInput : VirtualInput
{
private void AddButton(string name)
{
// we have not registered this button yet so add it, happens in the constructor
CrossPlatformInputManager.RegisterVirtualButton(new CrossPlatformInputManager.VirtualButton(name));
}
private void AddAxes(string name)
{
// we have not registered this button yet so add it, happens in the constructor
CrossPlatformInputManager.RegisterVirtualAxis(new CrossPlatformInputManager.VirtualAxis(name));
}
public override float GetAxis(string name, bool raw)
{
if (!m_VirtualAxes.ContainsKey(name))
{
AddAxes(name);
}
return m_VirtualAxes[name].GetValue;
}
public override void SetButtonDown(string name)
{
if (!m_VirtualButtons.ContainsKey(name))
{
AddButton(name);
}
m_VirtualButtons[name].Pressed();
}
public override void SetButtonUp(string name)
{
if (!m_VirtualButtons.ContainsKey(name))
{
AddButton(name);
}
m_VirtualButtons[name].Released();
}
public override void SetAxisPositive(string name)
{
if (!m_VirtualAxes.ContainsKey(name))
{
AddAxes(name);
}
m_VirtualAxes[name].Update(1f);
}
public override void SetAxisNegative(string name)
{
if (!m_VirtualAxes.ContainsKey(name))
{
AddAxes(name);
}
m_VirtualAxes[name].Update(-1f);
}
public override void SetAxisZero(string name)
{
if (!m_VirtualAxes.ContainsKey(name))
{
AddAxes(name);
}
m_VirtualAxes[name].Update(0f);
}
public override void SetAxis(string name, float value)
{
if (!m_VirtualAxes.ContainsKey(name))
{
AddAxes(name);
}
m_VirtualAxes[name].Update(value);
}
public override bool GetButtonDown(string name)
{
if (m_VirtualButtons.ContainsKey(name))
{
return m_VirtualButtons[name].GetButtonDown;
}
AddButton(name);
return m_VirtualButtons[name].GetButtonDown;
}
public override bool GetButtonUp(string name)
{
if (m_VirtualButtons.ContainsKey(name))
{
return m_VirtualButtons[name].GetButtonUp;
}
AddButton(name);
return m_VirtualButtons[name].GetButtonUp;
}
public override bool GetButton(string name)
{
if (m_VirtualButtons.ContainsKey(name))
{
return m_VirtualButtons[name].GetButton;
}
AddButton(name);
return m_VirtualButtons[name].GetButton;
}
public override Vector3 MousePosition()
{
return virtualMousePosition;
}
}
}

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 77cd10d817ddc0044868a6ec0e2ddb74
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:

View File

@@ -0,0 +1,114 @@
using System;
using UnityEngine;
namespace DestroyIt
{
[Serializable]
public class MouseLook
{
public float XSensitivity = 2f;
public float YSensitivity = 2f;
public bool clampVerticalRotation = true;
public float MinimumX = -90F;
public float MaximumX = 90F;
public bool smooth;
public float smoothTime = 5f;
public bool lockCursor = true;
private Quaternion m_CharacterTargetRot;
private Quaternion m_CameraTargetRot;
private bool m_cursorIsLocked = true;
public void Init(Transform character, Transform camera)
{
m_CharacterTargetRot = character.localRotation;
m_CameraTargetRot = camera.localRotation;
}
public void LookRotation(Transform character, Transform camera)
{
float yRot = CrossPlatformInputManager.GetAxis("Mouse X") * XSensitivity;
float xRot = CrossPlatformInputManager.GetAxis("Mouse Y") * YSensitivity;
m_CharacterTargetRot *= Quaternion.Euler (0f, yRot, 0f);
m_CameraTargetRot *= Quaternion.Euler (-xRot, 0f, 0f);
if(clampVerticalRotation)
m_CameraTargetRot = ClampRotationAroundXAxis (m_CameraTargetRot);
if(smooth)
{
character.localRotation = Quaternion.Slerp (character.localRotation, m_CharacterTargetRot,
smoothTime * Time.deltaTime);
camera.localRotation = Quaternion.Slerp (camera.localRotation, m_CameraTargetRot,
smoothTime * Time.deltaTime);
}
else
{
character.localRotation = m_CharacterTargetRot;
camera.localRotation = m_CameraTargetRot;
}
UpdateCursorLock();
}
public void SetCursorLock(bool value)
{
lockCursor = value;
if(!lockCursor)
{//we force unlock the cursor if the user disable the cursor locking helper
Cursor.lockState = CursorLockMode.None;
Cursor.visible = true;
}
}
public void UpdateCursorLock()
{
//if the user set "lockCursor" we check & properly lock the cursos
if (lockCursor)
InternalLockUpdate();
}
private void InternalLockUpdate()
{
if(Input.GetKeyUp(KeyCode.Escape))
{
m_cursorIsLocked = false;
}
else if(Input.GetMouseButtonUp(0))
{
m_cursorIsLocked = true;
}
if (m_cursorIsLocked)
{
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
else if (!m_cursorIsLocked)
{
Cursor.lockState = CursorLockMode.None;
Cursor.visible = true;
}
}
Quaternion ClampRotationAroundXAxis(Quaternion q)
{
q.x /= q.w;
q.y /= q.w;
q.z /= q.w;
q.w = 1.0f;
float angleX = 2.0f * Mathf.Rad2Deg * Mathf.Atan (q.x);
angleX = Mathf.Clamp (angleX, MinimumX, MaximumX);
q.x = Mathf.Tan (0.5f * Mathf.Deg2Rad * angleX);
return q;
}
}
}

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 33a5e50bf6d3c7947b0c2f67a85b6873
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:

View File

@@ -0,0 +1,64 @@
using System;
using UnityEngine;
namespace DestroyIt
{
public class StandaloneInput : VirtualInput
{
private string exceptionMsg = " This is not possible to be called for standalone input. Please check your platform and code where this is called";
public override float GetAxis(string name, bool raw)
{
return raw ? Input.GetAxisRaw(name) : Input.GetAxis(name);
}
public override bool GetButton(string name)
{
return Input.GetButton(name);
}
public override bool GetButtonDown(string name)
{
return Input.GetButtonDown(name);
}
public override bool GetButtonUp(string name)
{
return Input.GetButtonUp(name);
}
public override void SetButtonDown(string name)
{
throw new Exception(exceptionMsg);
}
public override void SetButtonUp(string name)
{
throw new Exception(exceptionMsg);
}
public override void SetAxisPositive(string name)
{
throw new Exception(exceptionMsg);
}
public override void SetAxisNegative(string name)
{
throw new Exception(exceptionMsg);
}
public override void SetAxisZero(string name)
{
throw new Exception(exceptionMsg);
}
public override void SetAxis(string name, float value)
{
throw new Exception(exceptionMsg);
}
public override Vector3 MousePosition()
{
return Input.mousePosition;
}
}
}

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 4f3a931e5929b2b469be65087c8bf9b9
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:

View File

@@ -0,0 +1,107 @@
using System.Collections.Generic;
using UnityEngine;
namespace DestroyIt
{
public abstract class VirtualInput
{
public Vector3 virtualMousePosition { get; private set; }
protected Dictionary<string, CrossPlatformInputManager.VirtualAxis> m_VirtualAxes =
new Dictionary<string, CrossPlatformInputManager.VirtualAxis>();
// Dictionary to store the name relating to the virtual axes
protected Dictionary<string, CrossPlatformInputManager.VirtualButton> m_VirtualButtons =
new Dictionary<string, CrossPlatformInputManager.VirtualButton>();
protected List<string> m_AlwaysUseVirtual = new List<string>();
// list of the axis and button names that have been flagged to always use a virtual axis or button
public bool AxisExists(string name)
{
return m_VirtualAxes.ContainsKey(name);
}
public bool ButtonExists(string name)
{
return m_VirtualButtons.ContainsKey(name);
}
public void RegisterVirtualAxis(CrossPlatformInputManager.VirtualAxis axis)
{
// check if we already have an axis with that name and log and error if we do
if (m_VirtualAxes.ContainsKey(axis.name))
Debug.LogError("There is already a virtual axis named " + axis.name + " registered.");
else
{
// add any new axes
m_VirtualAxes.Add(axis.name, axis);
// if we dont want to match with the input manager setting then revert to always using virtual
if (!axis.matchWithInputManager)
m_AlwaysUseVirtual.Add(axis.name);
}
}
public void RegisterVirtualButton(CrossPlatformInputManager.VirtualButton button)
{
// check if already have a buttin with that name and log an error if we do
if (m_VirtualButtons.ContainsKey(button.name))
Debug.LogError("There is already a virtual button named " + button.name + " registered.");
else
{
// add any new buttons
m_VirtualButtons.Add(button.name, button);
// if we dont want to match to the input manager then always use a virtual axis
if (!button.matchWithInputManager)
m_AlwaysUseVirtual.Add(button.name);
}
}
public void UnRegisterVirtualAxis(string name)
{
// if we have an axis with that name then remove it from our dictionary of registered axes
if (m_VirtualAxes.ContainsKey(name))
m_VirtualAxes.Remove(name);
}
public void UnRegisterVirtualButton(string name)
{
// if we have a button with this name then remove it from our dictionary of registered buttons
if (m_VirtualButtons.ContainsKey(name))
m_VirtualButtons.Remove(name);
}
// returns a reference to a named virtual axis if it exists otherwise null
public CrossPlatformInputManager.VirtualAxis VirtualAxisReference(string name)
{
return m_VirtualAxes.ContainsKey(name) ? m_VirtualAxes[name] : null;
}
public void SetVirtualMousePositionX(float f)
{
virtualMousePosition = new Vector3(f, virtualMousePosition.y, virtualMousePosition.z);
}
public void SetVirtualMousePositionY(float f)
{
virtualMousePosition = new Vector3(virtualMousePosition.x, f, virtualMousePosition.z);
}
public void SetVirtualMousePositionZ(float f)
{
virtualMousePosition = new Vector3(virtualMousePosition.x, virtualMousePosition.y, f);
}
public abstract float GetAxis(string name, bool raw);
public abstract bool GetButton(string name);
public abstract bool GetButtonDown(string name);
public abstract bool GetButtonUp(string name);
public abstract void SetButtonDown(string name);
public abstract void SetButtonUp(string name);
public abstract void SetAxisPositive(string name);
public abstract void SetAxisNegative(string name);
public abstract void SetAxisZero(string name);
public abstract void SetAxis(string name, float value);
public abstract Vector3 MousePosition();
}
}

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 51db5542f58ff344383ef823fe66ae1e
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:

View File

@@ -0,0 +1,17 @@
fileFormatVersion: 2
guid: 1c4e5f0fd29e42c42b6c1ea471335d50
labels:
- Destruction
- Destroy
- Physics
- DestroyIt
- Damage
- Fracturing
- Demolition
folderAsset: yes
timeCreated: 1427397479
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,15 @@
using UnityEngine;
namespace DestroyIt
{
public class DrawLine : MonoBehaviour
{
public bool isActive = true;
void OnDrawGizmos()
{
if (isActive)
Gizmos.DrawLine(transform.position, transform.position + transform.forward * 10f);
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f5b614943b0745545887eb8b2678f44f
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,35 @@
using UnityEngine;
/// <summary>
/// Put this script on your _GameManager gameObject to have it draw gizmos for DestroyIt features (like cling points, support
/// points, and structural joints). NOTE: This script is designed to only run in Editor mode, for performance reasons.
/// </summary>
namespace DestroyIt
{
public class EditorGizmos : MonoBehaviour
{
public bool showJointAnchors = true;
#if UNITY_EDITOR
private void OnDrawGizmos()
{
// Checks
if (Application.isPlaying) return;
// JOINT ANCHORS
if (showJointAnchors)
{
Joint[] joints = Object.FindObjectsOfType<Joint>();
if (joints.Length > 0)
{
foreach (Joint jnt in joints)
{
Vector3 pos = jnt.transform.TransformPoint(jnt.anchor);
Gizmos.DrawWireSphere(pos, 0.05f);
}
}
}
}
#endif
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3da395340588a1e4cbbecab69ae47adc
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 6b94f56546ecf56408a9faa6b19a29a7
folderAsset: yes
timeCreated: 1480901336
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,89 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace DestroyIt
{
public static class WeaponHelper
{
/// <summary>Launches a weapon from the player's controller transform.</summary>
/// <param name="weaponPrefab">The weapon to launch in front of the player.</param>
/// <param name="player">The transform of the player controller.</param>
/// <param name="startDistance">The initial distance from the player transform to instantiate the weapon.</param>
/// <param name="initialVelocity">The initial force velocity applied to the weapon (if any). For example, a bullet fired from a gun.</param>
/// <param name="randomRotation">If TRUE, the weapon prefab will be instantiated and rotated randomly before launch.</param>
public static void Launch(GameObject weaponPrefab, Transform weaponLauncher, float startDistance, float initialVelocity, bool randomRotation)
{
Quaternion rotation = randomRotation ? UnityEngine.Random.rotation : weaponLauncher.rotation;
// Instantiate the projectile.
var startPos = weaponLauncher.TransformPoint(Vector3.forward * startDistance);
var projectile = ObjectPool.Instance.Spawn(weaponPrefab, startPos, rotation);
var projectileRbody = projectile.GetComponent<Rigidbody>();
// Get the fire direction based on where the player is facing and apply force to propel it forward.
if (projectileRbody != null)
{
projectileRbody.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic;
projectileRbody.velocity = Vector3.zero; // zero out the velocity
if (initialVelocity > 0.0f)
projectileRbody.AddForce(weaponLauncher.forward * initialVelocity, ForceMode.Impulse);
}
}
/// <summary>
/// Launches projectiles that have no rigidbody (such as gameobject bullets), and therefore have no initial velocity.
/// </summary>
public static void Launch(GameObject weaponPrefab, Transform weaponLauncher, float startDistance, bool randomRotation)
{
Quaternion rotation = randomRotation ? UnityEngine.Random.rotation : weaponLauncher.rotation;
// Instantiate the projectile.
var startPos = weaponLauncher.TransformPoint(Vector3.forward * startDistance);
ObjectPool.Instance.Spawn(weaponPrefab, startPos, rotation);
}
/// <summary>Gets the next weapon type available, or cycles back to the beginning if there are no more.</summary>
public static WeaponType GetNext(WeaponType currentWeaponType)
{
List<WeaponType> weaponTypes = Enum.GetValues(typeof(WeaponType)).Cast<WeaponType>().ToList();
int index = (int)currentWeaponType;
if (index == weaponTypes.Count - 1)
index = 0;
else
index++;
// Remove the nuke from WebGL builds, because Chrome does not take advantage of asm.js and therefore performance is terrible.
#if UNITY_WEBGL
if (index == (int)WeaponType.Nuke)
index++;
if (index > weaponTypes.Count - 1)
index = 0;
#endif
return weaponTypes[index];
}
/// <summary>Gets the previous weapon type available, or cycles back to the beginning if there are no more.</summary>
public static WeaponType GetPrevious(WeaponType currentWeaponType)
{
List<WeaponType> weaponTypes = Enum.GetValues(typeof(WeaponType)).Cast<WeaponType>().ToList();
int index = (int)currentWeaponType;
if (index == 0)
index = weaponTypes.Count - 1;
else
index--;
// Remove the nuke from WebGL builds, because Chrome does not take advantage of asm.js and therefore performance is terrible.
#if UNITY_WEBGL
if (index == (int)WeaponType.Nuke)
index--;
#endif
return weaponTypes[index];
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4557901f5caaf064dbfada546a005b9c
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 57a7d23959973a749a7b4101de9ceb46
folderAsset: yes
timeCreated: 1480900305
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,486 @@
using UnityEngine;
using UnityEngine.SceneManagement;
#if UNITY_EDITOR
using UnityEditor.SceneManagement;
#endif
namespace DestroyIt
{
/// <summary>This script manages all player input.</summary>
[DisallowMultipleComponent]
public class InputManager : MonoBehaviour
{
public GameObject cannonballPrefab; // The cannonball prefab to launch.
public float cannonballVelocity = 75f; // Launch velocity of the cannonball.
public GameObject rocketPrefab; // The rocket prefab to launch.
public GameObject bulletPrefab;
public ParticleSystem muzzleFlash;
public ParticleSystem cannonFire;
public ParticleSystem rocketFire;
public Light muzzleLight;
public GameObject launcherRocket; // The rocket gameobject, seated inside the launcher while ready to fire.
public int bulletDamage = 15; // the amount of damage the bullet does to its target
public float bulletForcePerSecond = 25f; // the amount of force the bullet applies to impacted rigidbodies
public float bulletForceFrequency = 10f;
[Range(1, 30)]
public int gunShotsPerSecond = 8; // The gun's shots per second (rate of fire) while Fire1 button is depressed.
public float startDistance = 1.5f; // The distance projectiles/missiles will start in front of the player.
public WeaponType startingWeapon = WeaponType.Rocket; // The weapon the player will start with.
public GameObject nukePrefab;
public float shockwaveSpeed = 800f; // How fast the shockwave expands (ie, how much force is applied to the shock walls).
public GameObject shockWallPrefab;
public GameObject dustWallPrefab;
public int dustWallDistance = 120; // How far in front of the shockwave should the dust effect around a player trigger?
public GameObject groundChurnPrefab;
public int nukeDistance = 2500; // The distance the nuke starts away from the player.
public int groundChurnDistance = 90;
[Range(0.1f, .5f)]
public float timeSlowSpeed = 0.25f;
public GameObject windZone;
public WeaponType SelectedWeapon { get; set; }
private bool timeSlowed;
private bool timeStopped;
private float timeBetweenShots;
private float meleeAttackDelay;
private float lastShotTime;
private float lastMeleeTime;
private int playerPrefShowReticle = -1;
private int playerPrefShowHud = -1;
private float rocketTimer;
private float nukeTimer;
private CharacterController firstPersonController;
private Transform gunTransform; // The transform where the gun will be fired from.
private Transform cannonTransform; // The transform where the cannon will be fired from.
private Transform rocketTransform; // The transform where the rocket will be fired from.
private Transform nukeTransform; // The location of the nuke firing controller.
private Transform axeTransform; // The location of the axe.
private Transform repairWrenchTransform; // The location of the repair wrench.
private readonly LoadSceneParameters lsp = new LoadSceneParameters { loadSceneMode = LoadSceneMode.Single, localPhysicsMode = LocalPhysicsMode.None };
// Hide the default constructor (use InputManager.Instance instead).
private InputManager() { }
public static InputManager Instance { get; private set; }
private void Awake()
{
Instance = this;
}
private void Start()
{
if (Camera.main == null || Camera.main.transform.parent == null) return;
firstPersonController = Camera.main.transform.parent.GetComponent<CharacterController>();
if (firstPersonController == null)
Debug.LogError("InputManager: Could not find Character Controller on Main Camera parent.");
foreach (Transform trans in Camera.main.transform)
{
switch (trans.name)
{
case "WeaponPosition-Nuke":
nukeTransform = trans;
break;
case "WeaponPosition-Gun":
gunTransform = trans;
break;
case "WeaponPosition-Axe":
axeTransform = trans;
break;
case "WeaponPosition-Cannon":
cannonTransform = trans;
break;
case "WeaponPosition-Rocket":
rocketTransform = trans;
break;
case "WeaponPosition-RepairWrench":
repairWrenchTransform = trans;
break;
default: // default to gun
gunTransform = trans;
break;
}
}
if (muzzleLight != null && muzzleLight.enabled)
muzzleLight.enabled = false;
timeBetweenShots = 1f / gunShotsPerSecond;
meleeAttackDelay = 0.6f; // Limit melee attacks to one every 1/2 second.
lastShotTime = 0f;
lastMeleeTime = 0f;
SetTimeScale();
// Set active weapon from player preferences.
int playerPrefWeapon = PlayerPrefs.GetInt("SelectedWeapon", -1);
if (playerPrefWeapon == -1)
SelectedWeapon = startingWeapon;
else
SelectedWeapon = (WeaponType)playerPrefWeapon;
// Set HUD visibility options from player preferences.
playerPrefShowHud = PlayerPrefs.GetInt("ShowHud", -1);
playerPrefShowReticle = PlayerPrefs.GetInt("ShowReticle", -1);
#if UNITY_WEBGL
if (SelectedWeapon == WeaponType.Nuke)
SelectedWeapon = startingWeapon;
#endif
SetActiveWeapon();
}
private void Update()
{
if (nukeTimer > 0f)
nukeTimer -= Time.deltaTime;
if (nukeTimer < 0f)
nukeTimer = 0f;
if (rocketTimer > 0f)
rocketTimer -= Time.deltaTime;
if (rocketTimer <= 0f)
{
if (launcherRocket != null)
launcherRocket.SetActive(true);
rocketTimer = 0f;
}
if (Input.GetButtonDown("Fire1"))
{
//Cursor.lockState = CursorLockMode.Locked;
switch (SelectedWeapon)
{
case WeaponType.Cannonball:
if (cannonFire != null)
{
cannonFire.GetComponent<ParticleSystem>().Clear(true);
cannonFire.Play(true);
}
WeaponHelper.Launch(cannonballPrefab, cannonTransform, startDistance, cannonballVelocity, true);
break;
case WeaponType.Rocket:
if (rocketTimer <= 0f)
{
if (launcherRocket != null)
launcherRocket.SetActive(false);
if (rocketFire != null)
{
rocketFire.GetComponent<ParticleSystem>().Clear(true);
rocketFire.Play(true);
}
WeaponHelper.Launch(rocketPrefab, rocketTransform, startDistance + .1f, 6f, false);
RocketLoading rocketLoading = launcherRocket.GetComponentInChildren<RocketLoading>();
if (rocketLoading != null)
rocketLoading.isLoaded = false;
rocketTimer = 1f; // one rocket every X seconds.
}
break;
case WeaponType.Nuke: // Nuclear Blast and Rolling Shockwave Damage
if (nukeTimer <= 0f)
{
FadeIn flashEffect = gameObject.AddComponent<FadeIn>();
flashEffect.startColor = Color.white;
flashEffect.fadeLength = 5f;
// position the nuke 2500m in front of where the player is facing.
Transform player = GameObject.FindGameObjectWithTag("Player").transform;
Vector3 nukeForwardPos = player.position + player.forward * nukeDistance;
Vector3 nukePos = new Vector3(nukeForwardPos.x, 0f, nukeForwardPos.z);
if (groundChurnPrefab != null)
{
GameObject groundChurn = Instantiate(groundChurnPrefab, nukePos, Quaternion.identity) as GameObject;
Follow followScript = groundChurn.AddComponent<Follow>();
followScript.isPositionFixed = true;
followScript.objectToFollow = player;
followScript.facingDirection = FacingDirection.FixedPosition;
followScript.fixedFromPosition = nukePos;
followScript.fixedDistance = groundChurnDistance;
}
GameObject nuke = Instantiate(nukePrefab, nukePos, Quaternion.Euler(Vector3.zero)) as GameObject;
nuke.transform.LookAt(player);
// Configure Wind Zone
if (windZone != null)
{
windZone.transform.position = nukeForwardPos;
windZone.transform.LookAt(player);
Invoke("EnableWindZone", 5f);
DisableAfter disableAfter = windZone.GetComponent<DisableAfter>() ?? windZone.AddComponent<DisableAfter>();
disableAfter.seconds = 25f;
disableAfter.removeScript = true;
}
// Configure Dust Wall
if (dustWallPrefab != null)
{
GameObject dustWall = Instantiate(dustWallPrefab, nukeForwardPos, Quaternion.Euler(Vector3.zero)) as GameObject;
dustWall.transform.LookAt(player);
dustWall.transform.position += (dustWall.transform.forward * dustWallDistance);
dustWall.GetComponent<Rigidbody>().AddForce(dustWall.transform.forward * shockwaveSpeed, ForceMode.Force);
DustWall dwScript = dustWall.GetComponent<DustWall>();
dwScript.fixedFromPosition = nukePos;
}
// Configure Shock Wall
if (shockWallPrefab != null)
{
GameObject shockWall = Instantiate(shockWallPrefab, nukeForwardPos, Quaternion.Euler(Vector3.zero)) as GameObject;
shockWall.transform.LookAt(player);
shockWall.GetComponent<Rigidbody>().AddForce(shockWall.transform.forward * shockwaveSpeed, ForceMode.Force);
ShockWall swScript = shockWall.GetComponent<ShockWall>();
swScript.origin = nukePos;
}
Invoke("BroadcastNukeStart", 0.1f);
Invoke("BroadcastNukeEnd", 25f);
nukeTimer = 30f; // only one nuke every x seconds.
}
break;
case WeaponType.Gun:
FireGun();
break;
case WeaponType.Melee:
if (Time.time >= (lastMeleeTime + meleeAttackDelay))
MeleeAttack();
break;
case WeaponType.RepairWrench:
if (Time.time >= (lastMeleeTime + meleeAttackDelay))
RepairByHand();
break;
}
}
// Continuous fire from holding the button down
if (Input.GetButton("Fire1") && SelectedWeapon == WeaponType.Gun && Time.time >= (lastShotTime + timeBetweenShots))
FireGun();
// Continuous melee attack from holding the button down (useful for chopping trees in an MMO/survival game)
if (Input.GetButton("Fire1") && SelectedWeapon == WeaponType.Melee && Time.time >= (lastMeleeTime + meleeAttackDelay))
MeleeAttack();
// Repair continuously while holding the Fire1 button down.
if (Input.GetButton("Fire1") && SelectedWeapon == WeaponType.RepairWrench && Time.time >= (lastMeleeTime + meleeAttackDelay))
RepairByHand();
// Time Slow
if (Input.GetKeyUp("t"))
{
timeSlowed = !timeSlowed;
SetTimeScale();
}
// Time Stop
if (Input.GetKeyUp("y"))
{
timeStopped = !timeStopped;
SetTimeScale();
}
// Do this every frame for rigidbodies that enter the scene, so they have smooth frame interpolation.
// TODO: can probably run this more efficiently at a set rate, like a few times per second - not every frame.
if (timeSlowed)
{
foreach (GameObject go in FindObjectsOfType(typeof(GameObject)))
{
foreach (Rigidbody rb in go.GetComponentsInChildren<Rigidbody>())
rb.interpolation = RigidbodyInterpolation.Interpolate;
}
}
// Reset the scene
if (Input.GetKey("r"))
{
TreeManager treeManager = TreeManager.Instance;
if (treeManager != null)
{
//TODO: Black out the main camera first. You can see trees insta-respawn when restored, and it looks weird.
treeManager.RestoreTrees();
}
#if UNITY_EDITOR
EditorSceneManager.LoadSceneAsyncInPlayMode(SceneManager.GetActiveScene().path, lsp);
#else
SceneManager.LoadSceneAsync($"Assets/DestroyIt/Demos (safe to delete)/{SceneManager.GetActiveScene().name}.unity", lsp);
#endif
}
if (Input.GetKeyUp("q"))
{
SelectedWeapon = WeaponHelper.GetPrevious(SelectedWeapon);
PlayerPrefs.SetInt("SelectedWeapon", (int)SelectedWeapon);
SetActiveWeapon();
}
if (Input.GetKeyUp("e"))
{
SelectedWeapon = WeaponHelper.GetNext(SelectedWeapon);
PlayerPrefs.SetInt("SelectedWeapon", (int)SelectedWeapon);
SetActiveWeapon();
}
if (Input.GetKeyUp("o"))
{
if (playerPrefShowReticle == -1)
playerPrefShowReticle = 0;
else
playerPrefShowReticle = -1;
PlayerPrefs.SetInt("ShowReticle", playerPrefShowReticle);
}
if (Input.GetKeyUp("h"))
{
if (playerPrefShowHud == -1)
playerPrefShowHud = 0;
else
playerPrefShowHud = -1;
PlayerPrefs.SetInt("ShowHud", playerPrefShowHud);
}
if (Input.GetKeyUp("m"))
{
Cursor.lockState = CursorLockMode.None;
Cursor.visible = true;
// Always restore trees before changing scenes so you don't lose terrain tree data in the Unity editor.
TreeManager treeManager = TreeManager.Instance;
if (treeManager != null)
treeManager.RestoreTrees();
#if UNITY_EDITOR
EditorSceneManager.LoadSceneAsyncInPlayMode("Assets/DestroyIt/Demos (safe to delete)/Choose Demo.unity", lsp);
#else
SceneManager.LoadSceneAsync("Assets/DestroyIt/Demos (safe to delete)/Choose Demo.unity", lsp);
#endif
}
float scrollWheel = Input.GetAxis("Mouse ScrollWheel");
if (scrollWheel > 0f) // scroll up
{
SelectedWeapon = WeaponHelper.GetNext(SelectedWeapon);
PlayerPrefs.SetInt("SelectedWeapon", (int)SelectedWeapon);
SetActiveWeapon();
}
if (scrollWheel < 0f) // scroll down
{
SelectedWeapon = WeaponHelper.GetPrevious(SelectedWeapon);
PlayerPrefs.SetInt("SelectedWeapon", (int)SelectedWeapon);
SetActiveWeapon();
}
}
private void EnableWindZone()
{
if (windZone != null)
windZone.SetActive(true);
}
private void SetActiveWeapon()
{
gunTransform.gameObject.SetActive(SelectedWeapon == WeaponType.Gun);
cannonTransform.gameObject.SetActive(SelectedWeapon == WeaponType.Cannonball);
rocketTransform.gameObject.SetActive(SelectedWeapon == WeaponType.Rocket);
nukeTransform.gameObject.SetActive(SelectedWeapon == WeaponType.Nuke);
axeTransform.gameObject.SetActive(SelectedWeapon == WeaponType.Melee);
repairWrenchTransform.gameObject.SetActive(SelectedWeapon == WeaponType.RepairWrench);
}
private void MeleeAttack()
{
Animation anim = axeTransform.GetComponentInChildren<Animation>();
anim.Play("Axe Swinging");
lastMeleeTime = Time.time;
Invoke("BroadcastMeleeDamage", .2f);
}
private void RepairByHand()
{
Animation anim = repairWrenchTransform.GetComponentInChildren<Animation>();
anim.Play("Wrench Turn");
lastMeleeTime = Time.time;
Invoke("BroadcastRepairDamage", .2f);
}
private void BroadcastMeleeDamage()
{
firstPersonController.BroadcastMessage("OnMeleeDamage");
}
private void BroadcastRepairDamage()
{
firstPersonController.BroadcastMessage("OnMeleeRepair");
}
private void BroadcastNukeStart()
{
firstPersonController.BroadcastMessage("OnNukeStart");
}
private void BroadcastNukeEnd()
{
firstPersonController.BroadcastMessage("OnNukeEnd");
}
private void FireGun()
{
// Play muzzle flash particle effect
if (muzzleFlash != null)
muzzleFlash.Emit(1);
// Turn on muzzle flash point light
if (muzzleLight != null && !muzzleLight.enabled)
{
muzzleLight.enabled = true;
Invoke("DisableMuzzleLight", 0.1f);
}
WeaponHelper.Launch(bulletPrefab, gunTransform, 0f, false); // Launch bullet
lastShotTime = Time.time;
}
private void DisableMuzzleLight()
{
if (muzzleLight != null && muzzleLight.enabled)
muzzleLight.enabled = false;
}
private void SetTimeScale()
{
if (timeStopped)
{
Time.timeScale = 0f;
return;
}
if (timeSlowed)
{
Time.timeScale = timeSlowSpeed;
/* DISABLING RIGIDBODY INTERPOLATION TEMPORARILY DUE TO AN ONGOING UNITY BUG:
https://issuetracker.unity3d.com/issues/in-order-to-call-gettransforminfoexpectuptodate-dot-dot-dot-error-message-appears-while-using-rigidbody-interpolate-slash-extrapolate
*/
foreach (GameObject go in FindObjectsOfType(typeof(GameObject)))
{
foreach (Rigidbody rb in go.GetComponentsInChildren<Rigidbody>())
rb.interpolation = RigidbodyInterpolation.Interpolate;
}
}
else
{
Time.timeScale = 1.0f;
/* DISABLING RIGIDBODY INTERPOLATION TEMPORARILY DUE TO AN ONGOING UNITY BUG:
https://issuetracker.unity3d.com/issues/in-order-to-call-gettransforminfoexpectuptodate-dot-dot-dot-error-message-appears-while-using-rigidbody-interpolate-slash-extrapolate
*/
foreach (GameObject go in FindObjectsOfType(typeof(GameObject)))
{
foreach (Rigidbody rb in go.GetComponentsInChildren<Rigidbody>())
rb.interpolation = RigidbodyInterpolation.None;
}
}
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9cb075db9f811304894713ae945c9911
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 452d6b19d654bcc4b9ff7b35cc564413
folderAsset: yes
timeCreated: 1427397479
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,127 @@
using UnityEngine;
namespace DestroyIt
{
public class Bullet : MonoBehaviour
{
[Tooltip("The bullet's speed in game units per second.")]
public float speed = 400f;
[Tooltip("How many seconds the bullet will live, regardless of distance traveled.")]
public float timeToLive = 0.5f;
public Renderer streak;
[Range(1,10)]
[Tooltip("How often the bullet streak is visibile. 1 = 10% of the time. 10 = 100% of the time.")]
public int streakVisibleFreq = 6;
[Range(1,50)]
[Tooltip("Once turned on or off, the bullet streak will remain stable (unchanged) for this many frames.")]
public int streakMinFramesStable = 3;
/// <summary>The position where the bullet started.</summary>
public Vector3 StartingPosition { get; set; }
/// <summary>How far in game units the bullet has traveled after being fired.</summary>
public float DistanceTraveled
{
get { return Vector3.Distance(StartingPosition, transform.position); }
}
private float spawnTime = 0f;
private bool hitSomething = false;
private bool isInitialized = false;
private int streakFramesStable = 0;
public void OnEnable()
{
spawnTime = Time.time;
hitSomething = false;
StartingPosition = transform.position;
if (streak != null)
streak.gameObject.SetActive(Random.Range(1, 11) <= streakVisibleFreq);
isInitialized = true;
}
public void Update()
{
if (!isInitialized) return;
// Check if the bullet needs to be destroyed.
if (Time.time > spawnTime + timeToLive || hitSomething)
{
ObjectPool.Instance.PoolObject(gameObject);
return;
}
if (streak != null)
{
if (streakFramesStable > streakMinFramesStable)
{
streak.gameObject.SetActive(Random.Range(1, 11) <= streakVisibleFreq);
streakFramesStable = 0;
}
else
streakFramesStable += 1;
}
Vector3 lineEndPoint = transform.position + (transform.forward * speed * Time.deltaTime);
Debug.DrawLine(transform.position, lineEndPoint, Color.red, 5f);
// Raycast in front of the bullet to see if it hit anything. Sort the hits from closest to farthest.
RaycastHit[] hits = Physics.RaycastAll(transform.position, transform.forward, speed * Time.deltaTime);
int hitIndex = -1; // index of the closest hit that is not a trigger collider
float closestHitDistance = float.MaxValue;
for (int i = 0; i < hits.Length; i++)
{
if (hits[i].collider.isTrigger) continue;
if (hits[i].distance < closestHitDistance)
{
hitIndex = i;
closestHitDistance = hits[i].distance;
}
}
if (hitIndex > -1)
{
ProcessBulletHit(hits[hitIndex], transform.forward);
hitSomething = true;
return;
}
// Move the bullet forward.
transform.position += transform.forward * speed * Time.deltaTime;
}
private static void ProcessBulletHit(RaycastHit hitInfo, Vector3 bulletDirection)
{
HitEffects hitEffects = hitInfo.collider.gameObject.GetComponentInParent<HitEffects>();
if (hitEffects != null && hitEffects.effects.Count > 0)
hitEffects.PlayEffect(HitBy.Bullet, hitInfo.point, hitInfo.normal);
// Apply damage if object hit was Destructible
// Only do this for the first active and enabled Destructible script found in parent objects
// Special Note: Destructible scripts are turned off on terrain trees by default (to save resources), so we will make an exception for them and process the hit anyway
Destructible[] destObjs = hitInfo.collider.gameObject.GetComponentsInParent<Destructible>(false);
foreach (Destructible destObj in destObjs)
{
if (!destObj.isActiveAndEnabled && !destObj.isTerrainTree) continue;
ImpactDamage bulletDamage = new ImpactDamage { DamageAmount = InputManager.Instance.bulletDamage, AdditionalForce = InputManager.Instance.bulletForcePerSecond, AdditionalForcePosition = hitInfo.point, AdditionalForceRadius = .5f };
destObj.ApplyDamage(bulletDamage);
break;
}
Vector3 force = bulletDirection * (InputManager.Instance.bulletForcePerSecond / InputManager.Instance.bulletForceFrequency);
// Apply impact force to rigidbody hit
Rigidbody rbody = hitInfo.collider.attachedRigidbody;
if (rbody != null)
rbody.AddForceAtPosition(force, hitInfo.point, ForceMode.Impulse);
// Check for Chip-Away Debris
ChipAwayDebris chipAwayDebris = hitInfo.collider.gameObject.GetComponent<ChipAwayDebris>();
if (chipAwayDebris != null)
chipAwayDebris.BreakOff(-1.5f * force, hitInfo.point);
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ab57db5be3c0cf34b81d0aa502f54ed6
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,70 @@
using UnityEngine;
namespace DestroyIt
{
/// <summary>
/// Attach this to any rigidbody object that acts as a projectile and may collide with
/// Destructible objects. This script will play particle effects when the object hits
/// something, and will do damage to Destructible objects.
/// </summary>
[RequireComponent(typeof(Rigidbody))]
public class RigidbodyProjectile : MonoBehaviour
{
public HitBy weaponType = HitBy.Cannonball;
[Tooltip("Impact velocity must be at least this amount to be detected as a hit.")]
public float minHitVelocity = 10f;
private Rigidbody rbody;
private Vector3 lastVelocity;
public void OnEnable()
{
rbody = GetComponent<Rigidbody>();
}
public void FixedUpdate()
{
lastVelocity = rbody.velocity;
}
public void OnCollisionEnter(Collision collision)
{
// Check that the impact is forceful enough to cause damage
if (collision.relativeVelocity.magnitude < minHitVelocity) return;
if (collision.contacts.Length == 0) return;
Collider other = collision.contacts[0].otherCollider;
// Play hit effects
HitEffects hitEffects = other.gameObject.GetComponentInParent<HitEffects>();
if (hitEffects != null && hitEffects.effects.Count > 0)
hitEffects.PlayEffect(weaponType, collision.contacts[0].point, collision.contacts[0].normal);
// Apply impact damage to Destructible objects without rigidbodies
// Only do this for the first active and enabled Destructible script found in parent objects
// Special Note: Destructible scripts are turned off on terrain trees by default (to save resources), so we will make an exception for them and process the collision anyway
Destructible[] destObjs = other.gameObject.GetComponentsInParent<Destructible>(false);
foreach (Destructible destObj in destObjs)
{
if (!destObj.isActiveAndEnabled && !destObj.isTerrainTree) continue; // ignore any disabled destructible terrain trees
if (destObj.GetComponentInParent<DestructibleParent>() != null) continue; // ignore any destructible objects that have DestructibleParent scripts above them, that system already handles rigidbody collisions
if (other.attachedRigidbody == null || other.attachedRigidbody.GetComponent<Destructible>() == null)
{
if (collision.relativeVelocity.magnitude >= destObj.ignoreCollisionsUnder)
{
destObj.ProcessDestructibleCollision(collision, gameObject.GetComponent<Rigidbody>());
rbody.velocity = lastVelocity;
break;
}
}
}
// Check for Chip-Away Debris
ChipAwayDebris chipAwayDebris = collision.contacts[0].otherCollider.gameObject.GetComponent<ChipAwayDebris>();
if (chipAwayDebris != null)
chipAwayDebris.BreakOff(collision.relativeVelocity * -1, collision.contacts[0].point);
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 048568fa306ac4341a0cdd39394d6e4b
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,287 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// ReSharper disable CommentTypo
// ReSharper disable IdentifierTypo
// ReSharper disable StringLiteralTypo
namespace DestroyIt
{
/// <summary>
/// Attach this script to a rocket.
/// Handles applying blast damage and force to all objects within range, playing an explosive effect,
/// and separating the smoke trail from the rocket on impact, so smoke hangs in the air after the rocket is gone.
/// </summary>
public class Rocket : MonoBehaviour
{
[Tooltip("The amount of constant force applied to the missile. This directly affects the missile's overall speed.")]
[Range(1, 100)]
public int speed = 30;
[Tooltip("The maximum amount of damage the blast can do. This is separate from, and does not affect, the force of the blast on rigidbodies.")]
public float blastDamage = 200f;
[Tooltip("The strength (or force) of the blast. Higher numbers push rigidbodies around more.")]
public float blastForce = 250f;
[Tooltip("The distance from point of impact where objects are considered to be hit at point blank range. Point Blank radius is checked first, then Near, then Far.")]
public float pointBlankBlastRadius = 2f;
[Tooltip("The percentage of blast damage applied to objects hit at point blank distance from the rocket's impact point.")]
[Range(0f, 1f)]
public float pointBlankDamagePercent = 1f;
[Tooltip("The distance from the point of impact where objects are nearby, but not considered point blank. Point Blank radius is checked first, then Near, then Far.")]
public float nearBlastRadius = 4f;
[Tooltip("The percentage of blast damage applied to objects hit at a distance near to the rocket's impact point.")]
[Range(0f, 1f)]
public float nearDamagePercent = .5f;
[Tooltip("The distance from the point of impact where objects are far away, but still considered to be in the blast zone. Point Blank radius is checked first, then Near, then Far.")]
public float farBlastRadius = 8f;
[Tooltip("The percentage of blast damage applied to objects hit within maximum effective distance from the rocket's impact point.")]
[Range(0f, 1f)]
public float farDamagePercent = .2f;
[Tooltip("The amount of upward \"push\" explosions have. Higher numbers make debris fly up in the air, but can get unrealistic.")]
[Range(0f, 3f)]
public float explosionUpwardPush = 1f;
[Tooltip("The particle effect to play when this object collides with something.")]
public GameObject explosionPrefab;
public ParticleSystem smokeTrailPrefab;
[Tooltip("How long the rocket will fly (in seconds) before running out of fuel.")]
[Range(0f, 6f)]
public float flightTime = 2f;
[Tooltip("Remove the rocket from the scene after this many seconds, regardless if it's out of fuel or not.")]
[Range(0f, 10f)]
public float maxLifetime = 5f;
private float checkFrequency = 0.1f; // The time (in seconds) this script checks for updates to flight time and fuel levels.
private float nextUpdateCheck;
private bool outOfFuel;
private float flightTimer;
private GameObject smokeTrailObj;
private bool isExploding;
private bool isInitialized;
private bool isStarted;
private float smokeTrailDistance = 0.27f;
private List<Rigidbody> affectedRigidbodies;
private Dictionary<ChipAwayDebris, float> affectedChipAwayDebris;
private Dictionary<Destructible, ExplosiveDamage> affectedDestructibles;
private void Start()
{
isInitialized = true;
}
private void OnEnable()
{
isStarted = false;
affectedRigidbodies = new List<Rigidbody>();
affectedChipAwayDebris = new Dictionary<ChipAwayDebris, float>();
affectedDestructibles = new Dictionary<Destructible, ExplosiveDamage>();
nextUpdateCheck = Time.time + checkFrequency;
}
private void Update()
{
if (!isInitialized) return;
if (!isStarted)
{
EngineStartUp();
isStarted = true;
}
if (Time.time > nextUpdateCheck)
{
float remainingFlightTime = Time.time - flightTimer;
// Check if rocket should be culled
if (remainingFlightTime > maxLifetime)
StartCoroutine(Recover());
// Check if rocket is out of fuel
if (!outOfFuel && remainingFlightTime > flightTime)
EngineShutDown();
// reset the counter
nextUpdateCheck = Time.time + checkFrequency;
}
}
private void EngineStartUp()
{
flightTimer = Time.time;
isExploding = false;
outOfFuel = false;
// set the missile's speed (constant force)
GetComponent<ConstantForce>().relativeForce = new Vector3(0, 0, speed);
// create the smoke trail
smokeTrailObj = ObjectPool.Instance.Spawn(smokeTrailPrefab.gameObject, new Vector3(0, 0, smokeTrailDistance * -1), Quaternion.identity, transform);
}
private void EngineShutDown()
{
if (GetComponent<ConstantForce>() != null)
GetComponent<ConstantForce>().relativeForce = Vector3.zero;
GetComponent<Rigidbody>().useGravity = true;
Transform exhaust = transform.Find("exhaust");
if (exhaust != null)
exhaust.gameObject.SetActive(false);
outOfFuel = true;
// turn off point light (no thrust means no light source)
Transform pointLight = transform.Find("point light");
if (pointLight != null)
pointLight.gameObject.SetActive(false);
}
private void TurnOffSmokeTrail()
{
if (smokeTrailObj == null) return;
// Unparent smoke trail from rocket,
// turn off particle emitters, and queue it up for culling.
smokeTrailObj.transform.parent = null;
var emission = smokeTrailObj.GetComponent<ParticleSystem>().emission;
emission.enabled = false;
PoolAfter poolAfter = smokeTrailObj.AddComponent<PoolAfter>();
poolAfter.seconds = 7f;
poolAfter.removeWhenPooled = true;
}
public void OnCollisionEnter(Collision collision)
{
// If rocket is already exploding, exit.
if (!isExploding)
Explode();
}
public void Explode()
{
Vector3 currPos = transform.position;
isExploding = true;
TurnOffSmokeTrail();
// Play explosion particle effect.
ObjectPool.Instance.Spawn(explosionPrefab, currPos, GetComponent<Rigidbody>().rotation);
// POINT BLANK RANGE - Apply force and damage to colliders and rigidbodies
int pointBlankCounter = Physics.OverlapSphereNonAlloc(currPos, pointBlankBlastRadius, DestructionManager.Instance.overlapColliders);
ExplosiveDamage pointBlankExplosiveDamage = new ExplosiveDamage()
{
Position = currPos,
DamageAmount = blastDamage * pointBlankDamagePercent,
BlastForce = blastForce,
Radius = farBlastRadius,
UpwardModifier = explosionUpwardPush
};
AddAffectedObjects(pointBlankCounter, pointBlankExplosiveDamage, .75f);
// NEAR RANGE - Apply force and damage to colliders and rigidbodies
int nearCounter = Physics.OverlapSphereNonAlloc(currPos, nearBlastRadius, DestructionManager.Instance.overlapColliders);
ExplosiveDamage nearExplosiveDamage = new ExplosiveDamage()
{
Position = currPos,
DamageAmount = blastDamage * nearDamagePercent,
BlastForce = blastForce,
Radius = farBlastRadius,
UpwardModifier = explosionUpwardPush
};
AddAffectedObjects(nearCounter, nearExplosiveDamage, .50f);
// FAR RANGE - Apply force and damage to colliders and rigidbodies
int farCounter = Physics.OverlapSphereNonAlloc(currPos, farBlastRadius, DestructionManager.Instance.overlapColliders);
ExplosiveDamage farExplosiveDamage = new ExplosiveDamage()
{
Position = currPos,
DamageAmount = blastDamage * farDamagePercent,
BlastForce = blastForce,
Radius = farBlastRadius,
UpwardModifier = explosionUpwardPush
};
AddAffectedObjects(farCounter, farExplosiveDamage, .25f);
// Apply blast force to all affected rigidbodies
foreach (Rigidbody rbody in affectedRigidbodies)
rbody.AddExplosionForce(blastForce, transform.position, farBlastRadius, explosionUpwardPush); // NOTE: farBlastRadius is used because we need the max radius for rigidbody force.
// Apply blast to ChipAwayDebris
foreach (KeyValuePair<ChipAwayDebris, float> chipAwayDebris in affectedChipAwayDebris)
{
if (Random.Range(1, 100) <= 100 * chipAwayDebris.Value) // Chip off debris pieces a fraction of the time, depending on how close they were to the blast point.
{
chipAwayDebris.Key.BreakOff(blastForce, farBlastRadius, explosionUpwardPush);
}
}
// Apply blast to Destructibles
foreach (KeyValuePair<Destructible, ExplosiveDamage> destructible in affectedDestructibles)
{
if (destructible.Value.DamageAmount > 0f)
destructible.Key.ApplyDamage(destructible.Value);
}
StartCoroutine(Recover());
}
private void AddAffectedObjects(int colliderCount, ExplosiveDamage explosiveDamage, float chipAwayPercentage)
{
for (int i=0; i<colliderCount; i++)
{
Collider col = DestructionManager.Instance.overlapColliders[i];
// Ignore terrain colliders
if (col is TerrainCollider)
continue;
// Ignore self (the rocket)
if (col == GetComponent<Collider>())
continue;
// Check for Rigidbodies
Rigidbody rbody = col.attachedRigidbody;
if (rbody != null && !rbody.isKinematic && !affectedRigidbodies.Contains(rbody))
affectedRigidbodies.Add(rbody);
// Check for Chip-Away Debris
ChipAwayDebris chipAwayDebris = col.gameObject.GetComponent<ChipAwayDebris>();
if (chipAwayDebris != null && !affectedChipAwayDebris.ContainsKey(chipAwayDebris))
affectedChipAwayDebris.Add(chipAwayDebris, chipAwayPercentage);
if (chipAwayDebris != null)
continue; // Don't process destructible components on chip-away debris.
// Apply damage to Destructible objects
// Only do this for the first active and enabled Destructible script found in parent objects
// Special Note: Destructible scripts are turned off on terrain trees by default (to save resources), so we will make an exception for them and process the collision anyway
Destructible[] destObjs = col.gameObject.GetComponentsInParent<Destructible>(false);
foreach (Destructible destObj in destObjs)
{
if (affectedDestructibles.ContainsKey(destObj)) continue;
if (!destObj.isActiveAndEnabled && !destObj.isTerrainTree) continue;
affectedDestructibles.Add(destObj, explosiveDamage);
}
}
}
private IEnumerator Recover()
{
yield return new WaitForFixedUpdate();
GetComponent<Rigidbody>().velocity = Vector3.zero;
GetComponent<Rigidbody>().angularVelocity = Vector3.zero;
GetComponent<Rigidbody>().Sleep();
GetComponent<Rigidbody>().useGravity = false;
ObjectPool.Instance.PoolObject(gameObject, true);
StopAllCoroutines();
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 28bab5825fa341c4daf3752a3acdd2aa
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData: