Элита
Регистрация: 16.01.2010
Адрес: Новосибирск
Сообщений: 2,158
Написано 502 полезных сообщений (для 1,012 пользователей)
|
Ответ: Вопросы от новичка
Сообщение от WISHMASTER35
Lestar, вчера искал, но не нашел. Когда-то давно видел.
Andvrok, я пробовал кривыми настраивать силу выталкивания в зависимости от глубины погружения. Вообщем-то получалось тоже, что и без кривой.
Я думаю можно как-то создать амплитуду качания на воде. И увеличивать\уменьшать ее в зависимости от скорости. Но все это я слабо себе представляю и сделать не получается.
Кстати, лучше сделать затухание скорости? Если просто умножать на 0.95, то большая скорость уменьшается медленно, а маленькая скорость так и не доходит до нуля.
|
Плавающие тела, переменная WaterY - высота воды.

// Buoyancy.cs // by Alex Zhdankin // Version 2.1 // // http://forum.unity3d.com/threads/72974-Buoyancy-script // // Terms of use: do whatever you like
using System.Collections.Generic; using UnityEngine;
public class Buoyancy : MonoBehaviour { // public Ocean ocean;
public float waterY=0f; public float density = 500; public int slicesPerAxis = 2; public bool isConcave = false; public int voxelsLimit = 16;
private const float DAMPFER = 0.1f; private const float WATER_DENSITY = 1000;
private float voxelHalfHeight; private Vector3 localArchimedesForce; private List<Vector3> voxels; private bool isMeshCollider; private List<Vector3[]> forces; // For drawing force gizmos
/// <summary> /// Provides initialization. /// </summary> private void Start() { forces = new List<Vector3[]>(); // For drawing force gizmos
// Store original rotation and position var originalRotation = transform.rotation; var originalPosition = transform.position; transform.rotation = Quaternion.identity; transform.position = Vector3.zero;
// The object must have a collider if (collider == null) { gameObject.AddComponent<MeshCollider>(); Debug.LogWarning(string.Format("[Buoyancy.cs] Object \"{0}\" had no collider. MeshCollider has been added.", name)); } isMeshCollider = GetComponent<MeshCollider>() != null;
var bounds = collider.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 /= 2 * slicesPerAxis;
// The object must have a RidigBody if (rigidbody == null) { gameObject.AddComponent<Rigidbody>(); Debug.LogWarning(string.Format("[Buoyancy.cs] Object \"{0}\" had no Rigidbody. Rigidbody has been added.", name)); } rigidbody.centerOfMass = new Vector3(0, -bounds.extents.y * 0f, 0) + transform.InverseTransformPoint(bounds.center);
voxels = SliceIntoVoxels(isMeshCollider && isConcave);
// Restore original rotation and position transform.rotation = originalRotation; transform.position = originalPosition;
float volume = rigidbody.mass / density;
WeldPoints(voxels, voxelsLimit);
float archimedesForceMagnitude = WATER_DENSITY * Mathf.Abs(Physics.gravity.y) * volume; localArchimedesForce = new Vector3(0, archimedesForceMagnitude, 0) / voxels.Count;
Debug.Log(string.Format("[Buoyancy.cs] Name=\"{0}\" volume={1:0.0}, mass={2:0.0}, density={3:0.0}", name, volume, rigidbody.mass, density)); }
/// <summary> /// Slices the object into number of voxels represented by their center points. /// <param name="concave">Whether the object have a concave shape.</param> /// <returns>List of voxels represented by their center points.</returns> /// </summary> private List<Vector3> SliceIntoVoxels(bool concave) { var points = new List<Vector3>(slicesPerAxis * slicesPerAxis * slicesPerAxis);
if (concave) { var meshCol = GetComponent<MeshCollider>();
var convexValue = meshCol.convex; meshCol.convex = false;
// Concave slicing var bounds = collider.bounds; for (int ix = 0; ix < slicesPerAxis; ix++) { for (int iy = 0; iy < slicesPerAxis; iy++) { for (int iz = 0; iz < slicesPerAxis; iz++) { float x = bounds.min.x + bounds.size.x / slicesPerAxis * (0.5f + ix); float y = bounds.min.y + bounds.size.y / slicesPerAxis * (0.5f + iy); float z = bounds.min.z + bounds.size.z / slicesPerAxis * (0.5f + iz);
var p = transform.InverseTransformPoint(new Vector3(x, y, z));
if (PointIsInsideMeshCollider(meshCol, p)) { points.Add(p); } } } } if (points.Count == 0) { points.Add(bounds.center); }
meshCol.convex = convexValue; } else { // Convex slicing var bounds = GetComponent<Collider>().bounds; for (int ix = 0; ix < slicesPerAxis; ix++) { for (int iy = 0; iy < slicesPerAxis; iy++) { for (int iz = 0; iz < slicesPerAxis; iz++) { float x = bounds.min.x + bounds.size.x / slicesPerAxis * (0.5f + ix); float y = bounds.min.y + bounds.size.y / slicesPerAxis * (0.5f + iy); float z = bounds.min.z + bounds.size.z / slicesPerAxis * (0.5f + iz);
var p = transform.InverseTransformPoint(new Vector3(x, y, z));
points.Add(p); } } } }
return points; }
/// <summary> /// Returns whether the point is inside the mesh collider. /// </summary> /// <param name="c">Mesh collider.</param> /// <param name="p">Point.</param> /// <returns>True - the point is inside the mesh collider. False - the point is outside of the mesh collider. </returns> private static bool PointIsInsideMeshCollider(Collider c, Vector3 p) { Vector3[] directions = { Vector3.up, Vector3.down, Vector3.left, Vector3.right, Vector3.forward, Vector3.back };
foreach (var ray in directions) { RaycastHit hit; if (c.Raycast(new Ray(p - ray * 1000, ray), out hit, 1000f) == false) { return false; } }
return true; }
/// <summary> /// Returns two closest points in the list. /// </summary> /// <param name="list">List of points.</param> /// <param name="firstIndex">Index of the first point in the list. It's always less than the second index.</param> /// <param name="secondIndex">Index of the second point in the list. It's always greater than the first index.</param> private static void FindClosestPoints(IList<Vector3> list, out int firstIndex, out int secondIndex) { float minDistance = float.MaxValue, maxDistance = 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 distance = Vector3.Distance(list[i], list[j]); if (distance < minDistance) { minDistance = distance; firstIndex = i; secondIndex = j; } if (distance > maxDistance) { maxDistance = distance; } } } }
/// <summary> /// Welds closest points. /// </summary> /// <param name="list">List of points.</param> /// <param name="targetCount">Target number of points in the list.</param> private static void WeldPoints(IList<Vector3> list, int targetCount) { if (list.Count <= 2 || targetCount < 2) { return; }
while (list.Count > targetCount) { int first, second; FindClosestPoints(list, out first, out second);
var mixed = (list[first] + list[second]) * 0.5f; list.RemoveAt(second); // the second index is always greater that the first => removing the second item first list.RemoveAt(first); list.Add(mixed); } }
/// <summary> /// Returns the water level at given location. /// </summary> /// <param name="x">x-coordinate</param> /// <param name="z">z-coordinate</param> /// <returns>Water level</returns> private float GetWaterLevel(float x, float z) { // return ocean == null ? 0.0f : ocean.GetWaterHeightAtLocation(x, z); return waterY; }
/// <summary> /// Calculates physics. /// </summary> private void FixedUpdate() { forces.Clear(); // For drawing force gizmos
foreach (var point in voxels) { var wp = transform.TransformPoint(point); float waterLevel = GetWaterLevel(wp.x, wp.z);
if (wp.y - voxelHalfHeight < waterLevel) { float k = (waterLevel - wp.y) / (2 * voxelHalfHeight) + 0.5f; if (k > 1) { k = 1f; } else if (k < 0) { k = 0f; }
var velocity = rigidbody.GetPointVelocity(wp); var localDampingForce = -velocity * DAMPFER * rigidbody.mass; var force = localDampingForce + Mathf.Sqrt(k) * localArchimedesForce; rigidbody.AddForceAtPosition(force, wp);
forces.Add(new[] { wp, force }); // For drawing force gizmos } } }
/// <summary> /// Draws gizmos. /// </summary> private void OnDrawGizmos() { if (voxels == null || forces == null) { return; }
const float gizmoSize = 0.05f; Gizmos.color = Color.yellow;
foreach (var p in voxels) { Gizmos.DrawCube(transform.TransformPoint(p), new Vector3(gizmoSize, gizmoSize, gizmoSize)); }
Gizmos.color = Color.cyan;
foreach (var force in forces) { Gizmos.DrawCube(force[0], new Vector3(gizmoSize, gizmoSize, gizmoSize)); Gizmos.DrawLine(force[0], force[0] + force[1] / rigidbody.mass); } } }
Юзай http://forum.unity3d.com/attachment....6&d=1294425510
Только перепиши немного, а то там уровень воды постоянно на 0,0,0 , не помню какая переменная.
Думаю силы к фИЗ телам прилагать умеешь .
Для колебаний - делай псевдослучайные толчки ввверх или вниз, ну или волны, на уровне меша и колайдера
|