using System.Collections.Generic; using UnityEngine; public class BouyancyNew : MonoBehaviour { public float density = 500f; public int slicesPerAxis = 2; public bool isConcave; public int voxelsLimit = 16; private const float DAMPFER = 0.1f; private const float WATER_DENSITY = 1000f; private float voxelHalfHeight; private Vector3 localArchimedesForce; private List voxels; private bool isMeshCollider; public GameObject water; public MegaDynamicRipple dynamicwater; private Transform dwtrans; private Rigidbody rbody; private Collider mycollider; public float ripplevel = 0.4f; public float rippleforce = 0.1f; private void Start() { if ((bool)water) { dynamicwater = water.GetComponent(); } rbody = GetComponent(); mycollider = GetComponent(); if ((bool)dynamicwater) { dwtrans = dynamicwater.transform; } else { Debug.LogWarning(string.Format("[Buoyancy.cs] No Dynamic Ripple modifier found", base.name)); } Quaternion rotation = base.transform.rotation; Vector3 position = base.transform.position; base.transform.rotation = Quaternion.identity; base.transform.position = Vector3.zero; if (mycollider == null) { mycollider = base.gameObject.AddComponent(); Debug.LogWarning(string.Format("[Buoyancy.cs] Object \"{0}\" had no collider. MeshCollider has been added.", base.name)); } isMeshCollider = GetComponent() != null; Bounds bounds = mycollider.bounds; if (bounds.size.x < bounds.size.y) { voxelHalfHeight = bounds.size.x; } else { voxelHalfHeight = bounds.size.y; } if (bounds.size.z < voxelHalfHeight) { voxelHalfHeight = bounds.size.z; } voxelHalfHeight /= 2f * (float)slicesPerAxis; if (rbody == null) { rbody = base.gameObject.AddComponent(); Debug.LogWarning(string.Format("[Buoyancy.cs] Object \"{0}\" had no Rigidbody. Rigidbody has been added.", base.name)); } rbody.centerOfMass = new Vector3(0f, (0f - bounds.extents.y) * 0f, 0f) + base.transform.InverseTransformPoint(bounds.center); voxels = SliceIntoVoxels(isMeshCollider && isConcave); base.transform.rotation = rotation; base.transform.position = position; float num = rbody.mass / density; WeldPoints(voxels, voxelsLimit); float y = 1000f * Mathf.Abs(Physics.gravity.y) * num; localArchimedesForce = new Vector3(0f, y, 0f) / voxels.Count; Debug.Log(string.Format("[Buoyancy.cs] Name=\"{0}\" volume={1:0.0}, mass={2:0.0}, density={3:0.0}", base.name, num, rbody.mass, density)); } private List SliceIntoVoxels(bool concave) { List list = new List(slicesPerAxis * slicesPerAxis * slicesPerAxis); if (concave) { MeshCollider component = GetComponent(); bool convex = component.convex; component.convex = false; Bounds bounds = mycollider.bounds; for (int i = 0; i < slicesPerAxis; i++) { for (int j = 0; j < slicesPerAxis; j++) { for (int k = 0; k < slicesPerAxis; k++) { float x = bounds.min.x + bounds.size.x / (float)slicesPerAxis * (0.5f + (float)i); float y = bounds.min.y + bounds.size.y / (float)slicesPerAxis * (0.5f + (float)j); float z = bounds.min.z + bounds.size.z / (float)slicesPerAxis * (0.5f + (float)k); Vector3 vector = base.transform.InverseTransformPoint(new Vector3(x, y, z)); if (PointIsInsideMeshCollider(component, vector)) { list.Add(vector); } } } } if (list.Count == 0) { list.Add(bounds.center); } component.convex = convex; } else { Bounds bounds2 = GetComponent().bounds; for (int l = 0; l < slicesPerAxis; l++) { for (int m = 0; m < slicesPerAxis; m++) { for (int n = 0; n < slicesPerAxis; n++) { float x2 = bounds2.min.x + bounds2.size.x / (float)slicesPerAxis * (0.5f + (float)l); float y2 = bounds2.min.y + bounds2.size.y / (float)slicesPerAxis * (0.5f + (float)m); float z2 = bounds2.min.z + bounds2.size.z / (float)slicesPerAxis * (0.5f + (float)n); Vector3 item = base.transform.InverseTransformPoint(new Vector3(x2, y2, z2)); list.Add(item); } } } } return list; } private static bool PointIsInsideMeshCollider(Collider c, Vector3 p) { Vector3[] array = new Vector3[6] { Vector3.up, Vector3.down, Vector3.left, Vector3.right, Vector3.forward, Vector3.back }; Vector3[] array2 = array; foreach (Vector3 vector in array2) { RaycastHit hitInfo; if (!c.Raycast(new Ray(p - vector * 1000f, vector), out hitInfo, 1000f)) { return false; } } return true; } private static void FindClosestPoints(IList list, out int firstIndex, out int secondIndex) { float num = float.MaxValue; float num2 = float.MinValue; firstIndex = 0; secondIndex = 1; for (int i = 0; i < list.Count - 1; i++) { for (int j = i + 1; j < list.Count; j++) { float num3 = Vector3.Distance(list[i], list[j]); if (num3 < num) { num = num3; firstIndex = i; secondIndex = j; } if (num3 > num2) { num2 = num3; } } } } private static void WeldPoints(IList list, int targetCount) { if (list.Count > 2 && targetCount >= 2) { while (list.Count > targetCount) { int firstIndex; int secondIndex; FindClosestPoints(list, out firstIndex, out secondIndex); Vector3 item = (list[firstIndex] + list[secondIndex]) * 0.5f; list.RemoveAt(secondIndex); list.RemoveAt(firstIndex); list.Add(item); } } } private float GetWaterLevel(float x, float z) { if ((bool)dynamicwater) { Vector3 zero = Vector3.zero; zero.x = x; zero.z = z; return dynamicwater.GetWaterHeight(water.transform.worldToLocalMatrix.MultiplyPoint(zero)); } return 0f; } private void FixedUpdate() { float y = dwtrans.position.y; foreach (Vector3 voxel in voxels) { Vector3 vector = base.transform.TransformPoint(voxel); float num = GetWaterLevel(vector.x, vector.z) + y; if (vector.y - voxelHalfHeight < num) { float num2 = (num - vector.y) / (2f * voxelHalfHeight) + 0.5f; if (num2 > 1f) { num2 = 1f; } else if (num2 < 0f) { num2 = 0f; } Vector3 pointVelocity = rbody.GetPointVelocity(vector); Vector3 vector2 = -pointVelocity * 0.1f * rbody.mass; Vector3 force = vector2 + Mathf.Sqrt(num2) * localArchimedesForce; rbody.AddForceAtPosition(force, vector); if ((bool)dynamicwater && pointVelocity.y < 0f - ripplevel) { dynamicwater.ForceAt(vector, pointVelocity.y * rippleforce); } } } } private void OnDrawGizmos() { } }