Files
2026-02-21 16:45:37 +08:00

260 lines
6.6 KiB
C#

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<Vector3> 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<MegaDynamicRipple>();
}
rbody = GetComponent<Rigidbody>();
mycollider = GetComponent<Collider>();
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<MeshCollider>();
Debug.LogWarning(string.Format("[Buoyancy.cs] Object \"{0}\" had no collider. MeshCollider has been added.", base.name));
}
isMeshCollider = GetComponent<MeshCollider>() != 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<Rigidbody>();
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<Vector3> SliceIntoVoxels(bool concave)
{
List<Vector3> list = new List<Vector3>(slicesPerAxis * slicesPerAxis * slicesPerAxis);
if (concave)
{
MeshCollider component = GetComponent<MeshCollider>();
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<Collider>().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<Vector3> 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<Vector3> 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()
{
}
}